gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

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 }