wavReader.cpp (5094B)
1 #include "wavReader.h" 2 3 #include <cstring> 4 #include <map> 5 #include <cassert> 6 7 #include "wavTypes.h" 8 9 #include "dsp56kEmu/logging.h" 10 11 namespace synthLib 12 { 13 bool WavReader::load(Data& _data, std::vector<CuePoint>* _cuePoints, const uint8_t* _buffer, size_t _bufferSize) 14 { 15 // const unsigned int totalFileLength = _bufferSize; 16 17 size_t bufferPos = 0; 18 19 SWaveFormatHeader& header = *(SWaveFormatHeader*)&_buffer[0]; 20 bufferPos += sizeof(header); 21 22 if( memcmp( header.str_wave, "WAVE", 4 ) != 0 ) 23 return false; 24 25 if( memcmp( header.str_riff, "RIFF", 4 ) != 0 ) 26 return false; 27 28 std::map<uint32_t, SWaveFormatChunkCuePoint> cuePoints; 29 std::map<uint32_t, std::string> labels; 30 31 size_t dataChunkOffset = 0; 32 size_t dataChunkSize = 0; 33 size_t formatChunkOffset = 0; 34 35 while( bufferPos < (_bufferSize - sizeof(SWaveFormatChunkInfo)) ) 36 { 37 SWaveFormatChunkInfo& chunkInfo = *(SWaveFormatChunkInfo*)&_buffer[bufferPos]; 38 bufferPos += sizeof(chunkInfo); 39 40 if (memcmp(chunkInfo.chunkName, "fmt ", 4) == 0) 41 { 42 formatChunkOffset = bufferPos; 43 } 44 else if (memcmp(chunkInfo.chunkName, "data", 4) == 0) 45 { 46 dataChunkOffset = bufferPos; 47 dataChunkSize = chunkInfo.chunkSize; 48 } 49 else if (memcmp(chunkInfo.chunkName, "cue ", 4) == 0) 50 { 51 SWaveFormatChunkCue& chunkCue = *(SWaveFormatChunkCue*)&_buffer[bufferPos]; 52 53 size_t offset = bufferPos + sizeof(chunkCue); 54 55 for (size_t i = 0; i < chunkCue.cuePointCount; ++i) 56 { 57 SWaveFormatChunkCuePoint& point = *(SWaveFormatChunkCuePoint*)&_buffer[offset]; 58 59 if (cuePoints.find(point.cueId) == cuePoints.end()) 60 cuePoints.insert(std::make_pair(point.cueId, point)); 61 else 62 LOG("Warning: duplicated cue point " << point.cueId << " found"); 63 64 offset += sizeof(point); 65 } 66 } 67 else if (_cuePoints && (memcmp(chunkInfo.chunkName, "list", 4) == 0 || memcmp(chunkInfo.chunkName, "LIST", 4) == 0)) 68 { 69 SWaveFormatChunkList& adtl = *(SWaveFormatChunkList*)&_buffer[bufferPos]; 70 71 size_t offset = bufferPos + sizeof(adtl); 72 73 while (offset < (bufferPos + chunkInfo.chunkSize)) 74 { 75 SWaveFormatChunkInfo& subChunkInfo = *(SWaveFormatChunkInfo*)&_buffer[offset]; 76 77 offset += sizeof(subChunkInfo); 78 79 if (memcmp(subChunkInfo.chunkName, "labl", 4) == 0 || memcmp(subChunkInfo.chunkName, "note", 4) == 0) 80 { 81 SWaveFormatChunkLabel& chunkLabel = *(SWaveFormatChunkLabel*)&_buffer[offset]; 82 std::vector<char> name; 83 name.resize(subChunkInfo.chunkSize- sizeof(chunkLabel)); 84 ::memcpy(&name[0], &_buffer[offset + sizeof(chunkLabel)], name.size()); 85 86 while (!name.empty() && name.back() == 0) 87 name.pop_back(); 88 89 std::string nameString; 90 nameString.insert(nameString.begin(), name.begin(), name.end()); 91 92 if (!nameString.empty()) 93 { 94 if (labels.find(chunkLabel.cuePointId) == labels.end()) 95 { 96 labels.insert(std::make_pair(chunkLabel.cuePointId, nameString)); 97 } 98 else 99 { 100 LOG("Warning: duplicated cue label " << nameString << " found for cue id " << chunkLabel.cuePointId);; 101 } 102 } 103 } 104 offset += (subChunkInfo.chunkSize + 1) & ~1; 105 } 106 } 107 108 bufferPos += (chunkInfo.chunkSize + 1) & ~1; 109 } 110 111 if (dataChunkOffset == 0) 112 { 113 LOG("Failed to find wave data in file"); 114 return false; 115 } 116 117 if (formatChunkOffset == 0) 118 { 119 LOG("Failed to find format information in file"); 120 return false; 121 } 122 123 SWaveFormatChunkFormat& fmt = *(SWaveFormatChunkFormat*)&_buffer[formatChunkOffset]; 124 bufferPos += sizeof(fmt); 125 126 if( fmt.wave_type != eFormat_PCM && fmt.wave_type != eFormat_IEEE_FLOAT ) 127 return false; // Not PCM or float data 128 129 _data.samplerate = fmt.sample_rate; 130 131 bufferPos = dataChunkOffset; 132 133 const uint32_t numBytes = static_cast<uint32_t>(dataChunkSize); 134 const uint32_t numSamples = (numBytes << 3) / fmt.bits_per_sample; 135 136 int numChannels = fmt.num_channels; 137 138 _data.data = &_buffer[bufferPos]; 139 _data.dataByteSize = numBytes; 140 _data.bitsPerSample = fmt.bits_per_sample; 141 _data.channels = fmt.num_channels; 142 _data.isFloat = fmt.wave_type == eFormat_IEEE_FLOAT; 143 144 if (_cuePoints && !cuePoints.empty()) 145 { 146 // So this is a bit wierd, according to the doc at https://sites.google.com/site/musicgapi/technical-documents/wav-file-format 147 // The sampleOffset should be in bytes for uncompressed data and the position should be 0 if there is no plst chunk 148 // Adobe Audition writes both sampleOffset and position and they are both in samples, even though or wav file 149 // is uncompressed (32bit float though) and there is no plst chunk so for now treat it that way for float data 150 151 _cuePoints->clear(); 152 for (auto it = cuePoints.begin(); it != cuePoints.end(); ++it) 153 { 154 const SWaveFormatChunkCuePoint& src = it->second; 155 CuePoint dst; 156 157 if (src.playOrderPosition > 0 || src.playOrderPosition == src.sampleOffset) 158 dst.sampleOffset = src.playOrderPosition; 159 else 160 dst.sampleOffset = src.sampleOffset * numSamples / (fmt.bits_per_sample >> 3); 161 162 const auto itName = labels.find(it->first); 163 164 if (itName != labels.end()) 165 dst.name = itName->second; 166 167 _cuePoints->push_back(dst); 168 } 169 } 170 171 return true; 172 } 173 174 }