| 100 | } |
| 101 | |
| 102 | Result read(std::string filename) { |
| 103 | std::ifstream file; |
| 104 | file.open(filename, std::ios::binary); |
| 105 | if (!file.is_open()) return result = Result(Result::Code::IO_ERROR, "Failed to open file: " + filename); |
| 106 | |
| 107 | // RIFF chunk |
| 108 | if (read32(file) != value_RIFF) return result = Result(Result::Code::FORMAT_ERROR, "Input is not a RIFF file"); |
| 109 | read32(file); // File length - we don't check this |
| 110 | if (read32(file) != value_WAVE) return result = Result(Result::Code::FORMAT_ERROR, "Input is not a plain WAVE file"); |
| 111 | |
| 112 | Format format = Format::PCM; // Shouldn't matter, we should always get a "fmt " chunk before data |
| 113 | while (!file.eof()) { |
| 114 | auto blockType = read32(file), blockLength = read32(file); |
| 115 | if (blockType == value_fmt) { |
| 116 | auto formatInt = read16(file); |
| 117 | format = (Format)formatInt; |
| 118 | channels = read16(file); |
| 119 | if (channels < 1) return result = Result(Result::Code::FORMAT_ERROR, "Cannot have zero channels"); |
| 120 | |
| 121 | sampleRate = read32(file); |
| 122 | if (sampleRate < 1) return result = Result(Result::Code::FORMAT_ERROR, "Cannot have zero sampleRate"); |
| 123 | |
| 124 | unsigned int expectedBytesPerSecond = read32(file); |
| 125 | unsigned int bytesPerFrame = read16(file); |
| 126 | unsigned int bitsPerSample = read16(file); |
| 127 | if (!formatIsValid(formatInt, bitsPerSample)) return result = Result(Result::Code::UNSUPPORTED, "Unsupported format:bits: " + std::to_string(formatInt) + ":" + std::to_string(bitsPerSample)); |
| 128 | // Since it's plain WAVE, we can do some extra checks for consistency |
| 129 | if (bitsPerSample*channels != bytesPerFrame*8) return result = Result(Result::Code::FORMAT_ERROR, "Format sizes don't add up"); |
| 130 | if (expectedBytesPerSecond != sampleRate*bytesPerFrame) return result = Result(Result::Code::FORMAT_ERROR, "Format sizes don't add up"); |
| 131 | } else if (blockType == value_data) { |
| 132 | std::vector<double> samples(0); |
| 133 | switch (format) { |
| 134 | case Format::PCM: |
| 135 | samples.reserve(blockLength/2); |
| 136 | for (size_t i = 0; i < blockLength/2; ++i) { |
| 137 | uint16_t value = read16(file); |
| 138 | if (file.eof()) break; |
| 139 | if (value >= 32768) { |
| 140 | samples.push_back(((double)value - 65536)/32768); |
| 141 | } else { |
| 142 | samples.push_back((double)value/32768); |
| 143 | } |
| 144 | } |
| 145 | } |
| 146 | while (samples.size()%channels != 0) { |
| 147 | samples.push_back(0); |
| 148 | } |
| 149 | this->samples = samples; |
| 150 | } else { |
| 151 | file.ignore(blockLength); |
| 152 | } |
| 153 | } |
| 154 | return result = Result(Result::Code::OK); |
| 155 | } |
| 156 | |
| 157 | Result write(std::string filename, Format format=Format::PCM) { |
| 158 | if (channels == 0 || channels > 65535) return result = Result(Result::Code::WEIRD_CONFIG, "Invalid channel count"); |