Change Encyclo button name and macros icon
[ryzomcore.git] / nel / src / sound / driver / buffer.cpp
blobd3cba94b3421f0f45ec72cf5ca39a59e70fa1859
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2010 Matt RAYKOWSKI (sfb) <matt.raykowski@gmail.com>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "stdsound_lowlevel.h"
22 #include "nel/sound/driver/buffer.h"
23 #include "nel/misc/fast_mem.h"
24 #include "nel/misc/stream.h"
26 namespace NLSOUND {
28 // for compatibility
29 void IBuffer::setFormat(TSampleFormat format, uint freq)
31 TBufferFormat bufferFormat;
32 uint8 channels;
33 uint8 bitsPerSample;
34 sampleFormatToBufferFormat(format, bufferFormat, channels, bitsPerSample);
35 setFormat(bufferFormat, channels, bitsPerSample, (uint32)freq);
38 // for compatibility, very lazy checks (assume it's set by old setFormat)
39 void IBuffer::getFormat(TSampleFormat& format, uint& freq) const
41 TBufferFormat bufferFormat;
42 uint8 channels;
43 uint8 bitsPerSample;
44 uint32 frequency;
45 getFormat(bufferFormat, channels, bitsPerSample, frequency);
46 freq = (uint)frequency;
47 bufferFormatToSampleFormat(bufferFormat, channels, bitsPerSample, format);
50 /// Convert old sample format to new buffer format
51 void IBuffer::sampleFormatToBufferFormat(TSampleFormat sampleFormat, TBufferFormat &bufferFormat, uint8 &channels, uint8 &bitsPerSample)
53 switch (sampleFormat)
55 case Mono8:
56 bufferFormat = FormatPcm;
57 channels = 1;
58 bitsPerSample = 8;
59 break;
60 case Mono16ADPCM:
61 bufferFormat = FormatDviAdpcm;
62 channels = 1;
63 bitsPerSample = 16;
64 break;
65 case Mono16:
66 bufferFormat = FormatPcm;
67 channels = 1;
68 bitsPerSample = 16;
69 break;
70 case Stereo8:
71 bufferFormat = FormatPcm;
72 channels = 2;
73 bitsPerSample = 8;
74 break;
75 case Stereo16:
76 bufferFormat = FormatPcm;
77 channels = 2;
78 bitsPerSample = 16;
79 break;
80 default:
81 bufferFormat = FormatUnknown;
82 channels = 0;
83 bitsPerSample = 0;
84 break;
88 /// Convert new buffer format to old sample format
89 void IBuffer::bufferFormatToSampleFormat(TBufferFormat bufferFormat, uint8 channels, uint8 bitsPerSample, TSampleFormat &sampleFormat)
91 switch (bufferFormat)
93 case FormatPcm:
94 switch (channels)
96 case 1:
97 switch (bitsPerSample)
99 case 8:
100 sampleFormat = Mono8;
101 break;
102 default:
103 sampleFormat = Mono16;
104 break;
106 break;
107 default:
108 switch (bitsPerSample)
110 case 8:
111 sampleFormat = Stereo8;
112 break;
113 default:
114 sampleFormat = Stereo16;
115 break;
117 break;
119 break;
120 case FormatDviAdpcm:
121 sampleFormat = Mono16ADPCM;
122 break;
123 case FormatUnknown:
124 default:
125 sampleFormat = SampleFormatUnknown;
126 break;
130 uint IBuffer::getPCMSizeFromDuration(float duration, uint8 channels, uint8 bitsPerSample, uint32 frequency)
132 return (uint)(duration
133 * ((float)frequency)
134 * (((float)bitsPerSample) / 8.0f)
135 * ((float)channels));
138 float IBuffer::getDurationFromPCMSize(uint size, uint8 channels, uint8 bitsPerSample, uint32 frequency)
140 return ((float)size)
141 / ((float)channels)
142 / (((float)bitsPerSample) / 8.0f)
143 / ((float)frequency);
146 const sint IBuffer::_IndexTable[16] =
148 -1, -1, -1, -1, 2, 4, 6, 8,
149 -1, -1, -1, -1, 2, 4, 6, 8,
152 const uint IBuffer::_StepsizeTable[89] =
154 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
155 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
156 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
157 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
158 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
159 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
160 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
161 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
162 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
166 void IBuffer::encodeADPCM(const sint16 *indata, uint8 *outdata, uint nbSample, TADPCMState &state)
168 const sint16 *inp = indata; /* Input buffer pointer */
169 uint8 *outp = outdata; /* output buffer pointer */
170 int val; /* Current input sample value */
171 int sign; /* Current adpcm sign bit */
172 int delta; /* Current adpcm output value */
173 int diff; /* Difference between val and valprev */
174 int valpred = state.PreviousSample; /* Predicted output value */
175 int vpdiff; /* Current change to valpred */
176 int index = state.StepIndex; /* Current step change index */
177 int step = _StepsizeTable[index]; /* Stepsize */
178 uint8 outputbuffer = 0; /* place to keep previous 4-bit value */
179 int bufferstep = 1; /* toggle between outputbuffer/output */
181 for ( ; nbSample > 0 ; nbSample-- )
183 val = *inp++;
185 /* Step 1 - compute difference with previous value */
186 diff = val - valpred;
187 sign = (diff < 0) ? 8 : 0;
188 if ( sign ) diff = (-diff);
190 /* Step 2 - Divide and clamp */
191 /* Note:
192 ** This code *approximately* computes:
193 ** delta = diff*4/step;
194 ** vpdiff = (delta+0.5)*step/4;
195 ** but in shift step bits are dropped. The net result of this is
196 ** that even if you have fast mul/div hardware you cannot put it to
197 ** good use since the fixup would be too expensive.
199 delta = 0;
200 vpdiff = (step >> 3);
202 if ( diff >= step )
204 delta = 4;
205 diff -= step;
206 vpdiff += step;
208 step >>= 1;
209 if ( diff >= step )
211 delta |= 2;
212 diff -= step;
213 vpdiff += step;
215 step >>= 1;
216 if ( diff >= step )
218 delta |= 1;
219 vpdiff += step;
222 /* Step 3 - Update previous value */
223 if ( sign )
224 valpred -= vpdiff;
225 else
226 valpred += vpdiff;
228 /* Step 4 - Clamp previous value to 16 bits */
229 if ( valpred > 32767 )
231 nlwarning("over+ %d",valpred);
232 valpred = 32767;
234 else if ( valpred < -32768 )
236 nlwarning("over- %d",valpred);
237 valpred = -32768;
240 /* Step 5 - Assemble value, update index and step values */
241 delta |= sign;
243 index += _IndexTable[delta];
244 if ( index < 0 )
245 index = 0;
246 if ( index > 88 )
247 index = 88;
248 step = _StepsizeTable[index];
250 /* Step 6 - Output value */
251 if ( bufferstep )
253 outputbuffer = (delta << 4) & 0xf0;
255 else
257 *outp++ = (delta & 0x0f) | outputbuffer;
259 bufferstep = !bufferstep;
262 /* Output last step, if needed */
263 if ( !bufferstep )
264 *outp++ = outputbuffer;
266 state.PreviousSample = sint16(valpred);
267 state.StepIndex = uint8(index);
270 void IBuffer::decodeADPCM(const uint8 *indata, sint16 *outdata, uint nbSample, TADPCMState &state)
272 const uint8 *inp = indata; /* Input buffer pointer */
273 sint16 *outp = outdata; /* output buffer pointer */
274 int sign; /* Current adpcm sign bit */
275 int delta; /* Current adpcm output value */
276 int valpred = state.PreviousSample; /* Predicted value */
277 int vpdiff; /* Current change to valpred */
278 int index = state.StepIndex; /* Current step change index */
279 int step = _StepsizeTable[index]; /* Stepsize */
280 uint8 inputbuffer = 0; /* place to keep next 4-bit value */
281 int bufferstep = 0; /* toggle between inputbuffer/input */
283 for ( ; nbSample > 0 ; nbSample-- )
286 /* Step 1 - get the delta value */
287 if ( bufferstep )
289 delta = inputbuffer & 0xf;
291 else
293 inputbuffer = *inp++;
294 delta = (inputbuffer >> 4) & 0xf;
296 bufferstep = !bufferstep;
298 /* Step 2 - Find new index value (for later) */
299 index += _IndexTable[delta];
300 if ( index < 0 )
301 index = 0;
302 if ( index > 88 )
303 index = 88;
305 /* Step 3 - Separate sign and magnitude */
306 sign = delta & 8;
307 delta = delta & 7;
309 /* Step 4 - Compute difference and new predicted value */
311 ** Computes 'vpdiff = (delta+0.5)*step/4', but see comment
312 ** in adpcm_coder.
314 vpdiff = step >> 3;
315 if ( delta & 4 )
316 vpdiff += step;
317 if ( delta & 2 )
318 vpdiff += step>>1;
319 if ( delta & 1 )
320 vpdiff += step>>2;
322 if ( sign )
323 valpred -= vpdiff;
324 else
325 valpred += vpdiff;
327 /* Step 5 - clamp output value */
328 if ( valpred > 32767 )
329 valpred = 32767;
330 else if ( valpred < -32768 )
331 valpred = -32768;
333 /* Step 6 - Update step value */
334 step = _StepsizeTable[index];
336 /* Step 7 - Output value */
337 *outp++ = sint16(valpred);
340 state.PreviousSample = sint16(valpred);
341 state.StepIndex = uint8(index);
344 static bool checkFourCC(const uint8 *left, const char *right)
346 return (left[0] == right[0] && left[1] == right[1] && left[2] == right[2] && left[3] == right[3]);
349 static bool readHeader(const uint8 *header, const char *fourcc, uint32 &size, const uint8 *&data)
351 memcpy(&size, header + 4, sizeof(uint32));
352 data = header + 8;
353 return (header[0] == fourcc[0] && header[1] == fourcc[1] && header[2] == fourcc[2] && header[3] == fourcc[3]);
356 static bool findChunk(const uint8 *src, uint32 srcSize, const char *fourcc, uint32 &size, const uint8 *&data)
358 uint32 offset = 0;
359 while (offset + 8 < srcSize)
361 bool found = readHeader(src + offset, fourcc, size, data);
362 if (found) return true;
363 offset += 8 + size;
365 return false;
368 /// Read a wav file. Data type uint8 is used as unspecified buffer format.
369 bool IBuffer::readWav(const uint8 *wav, uint size, std::vector<uint8> &result, TBufferFormat &bufferFormat, uint8 &channels, uint8 &bitsPerSample, uint32 &frequency)
371 #if 0
372 // Create mmio stuff
373 MMIOINFO mmioinfo;
374 memset(&mmioinfo, 0, sizeof(MMIOINFO));
375 mmioinfo.fccIOProc = FOURCC_MEM;
376 mmioinfo.pchBuffer = (HPSTR)wav;
377 mmioinfo.cchBuffer = size;
378 HMMIO hmmio = mmioOpen(NULL, &mmioinfo, MMIO_READ | MMIO_DENYWRITE);
379 if (!hmmio) { throw ESoundDriver("Failed to open the file"); }
381 // Find wave
382 MMCKINFO mmckinforiff;
383 memset(&mmckinforiff, 0, sizeof(MMCKINFO));
384 mmckinforiff.fccType = mmioFOURCC('W', 'A', 'V', 'E');
385 if (mmioDescend(hmmio, &mmckinforiff, NULL, MMIO_FINDRIFF) != MMSYSERR_NOERROR) { mmioClose(hmmio, 0); throw ESoundDriver("mmioDescend WAVE failed"); }
387 // Find fmt
388 MMCKINFO mmckinfofmt;
389 memset(&mmckinfofmt, 0, sizeof(MMCKINFO));
390 mmckinfofmt.ckid = mmioFOURCC('f', 'm', 't', ' ');
391 if (mmioDescend(hmmio, &mmckinfofmt, &mmckinforiff, MMIO_FINDCHUNK) != MMSYSERR_NOERROR) { mmioClose(hmmio, 0); throw ESoundDriver("mmioDescend fmt failed"); }
392 WAVEFORMATEX *wavefmt = (WAVEFORMATEX *)(&wav[mmckinfofmt.dwDataOffset]);
393 if (mmioAscend(hmmio, &mmckinfofmt, 0) != MMSYSERR_NOERROR) { mmioClose(hmmio, 0); throw ESoundDriver("mmioAscend fmt failed"); }
395 // Find data
396 MMCKINFO mmckinfodata;
397 memset(&mmckinfodata, 0, sizeof(MMCKINFO));
398 mmckinfodata.ckid = mmioFOURCC('d', 'a', 't', 'a');
399 if (mmioDescend(hmmio, &mmckinfodata, &mmckinforiff, MMIO_FINDCHUNK) != MMSYSERR_NOERROR) { mmioClose(hmmio, 0); throw ESoundDriver("mmioDescend data failed"); }
400 BYTE *wavedata = (BYTE *)(&wav[mmckinfodata.dwDataOffset]);
401 if (mmioAscend(hmmio, &mmckinfodata, 0) != MMSYSERR_NOERROR) { mmioClose(hmmio, 0); throw ESoundDriver("mmioAscend data failed"); }
403 // Close mmio
404 mmioClose(hmmio, 0);
406 // Copy stuff
407 bufferFormat = (TBufferFormat)wavefmt->wFormatTag;
408 channels = (uint8)wavefmt->nChannels;
409 bitsPerSample = (uint8)wavefmt->wBitsPerSample;
410 frequency = wavefmt->nSamplesPerSec;
411 result.resize(mmckinfodata.cksize);
412 NLMISC::CFastMem::memcpy(&result[0], wavedata, mmckinfodata.cksize);
413 return true;
415 #else
416 // read the RIFF header and check if it contains WAVE data
417 const uint8 *riffHeader = wav;
418 uint32 riffSize;
419 const uint8 *riffData;
420 if (!readHeader(riffHeader, "RIFF", riffSize, riffData))
422 nlwarning("WAV: Cannot find RIFF identifier");
423 return false;
425 if (riffSize <= 4)
427 nlwarning("WAV: Empty RIFF file");
428 return false;
430 if (!checkFourCC(riffData, "WAVE"))
432 nlwarning("WAV: RIFF file does not contain WAVE data");
433 return false;
435 uint32 waveSize = riffSize - 4;
436 const uint8 *waveData = riffData + 4;
438 // find the 'fmt ' chunk
439 uint32 fmtSize;
440 const uint8 *fmtData;
441 if (!findChunk(waveData, waveSize, "fmt ", fmtSize, fmtData))
443 nlwarning("WAV: Cannot find 'fmt ' chunk");
444 return false;
446 if (fmtSize < 16)
448 nlwarning("WAV: The 'fmt ' chunk is incomplete");
449 return false;
452 // find the 'data' chunk
453 uint32 dataSize;
454 const uint8 *dataData;
455 if (!findChunk(waveData, waveSize, "data", dataSize, dataData))
457 nlwarning("WAV: Cannot find 'data' chunk");
458 return false;
460 if (dataData + dataSize > wav + size)
462 uint32 cut = (uint32)((dataData + dataSize) - (wav + size));
463 nlwarning("WAV: Oversize 'data' chunk with dataSize %u and wav size %u, cutting %u bytes", (uint32)dataSize, (uint32)size, (uint32)cut);
464 dataSize -= cut;
467 // read the 'fmt ' chunk
468 uint16 fmtFormatTag; // 0-1
469 memcpy(&fmtFormatTag, fmtData + 0, sizeof(uint16));
470 uint16 fmtChannels; // 2-3
471 memcpy(&fmtChannels, fmtData + 2, sizeof(uint16));
472 uint32 fmtSamplesPerSec; // 4-7
473 memcpy(&fmtSamplesPerSec, fmtData + 4, sizeof(uint32));
474 //uint32 fmtAvgBytesPerSec; // 8-11
475 //uint16 fmtBlockAlign; // 12-13
476 uint16 fmtBitsPerSample; // 14-15
477 memcpy(&fmtBitsPerSample, fmtData + 14, sizeof(uint16));
478 //uint16 fmtExSize; // 16-17 // only if fmtSize > 16
480 bufferFormat = (TBufferFormat)fmtFormatTag;
481 channels = (uint8)fmtChannels;
482 bitsPerSample = (uint8)fmtBitsPerSample;
483 frequency = fmtSamplesPerSec;
484 result.resize(dataSize);
485 NLMISC::CFastMem::memcpy(&result[0], dataData, dataSize);
487 return true;
489 #endif
492 /// Write a wav file. Data type uint8 does not imply a buffer of any format.
493 bool IBuffer::writeWav(const uint8 *buffer, uint size, TBufferFormat bufferFormat, uint8 channels, uint8 bitsPerSample, uint32 frequency, NLMISC::IStream &out)
495 nlassert(!out.isReading());
497 const uint32 headerSize = 8; // 32 TAG + 32 SIZE
498 uint32 fmtSize = 16;
499 uint32 dataSize = (uint32)size;
501 // create riff header
502 const char *riffFourCC = "RIFF"; // Chunk FourCC
503 uint32 riffSize = 4 // Type FourCC
504 + headerSize + fmtSize // fmt Chunk
505 + headerSize + dataSize; // data Chunk
506 // create riff data
507 const char *waveFourCC = "WAVE"; // Type FourCC
509 // write riff chunk header
510 out.serialBuffer(const_cast<uint8 *>(static_cast<const uint8 *>(static_cast<const void *>(riffFourCC))), 4);
511 out.serial(riffSize);
512 // write riff chunk data
513 out.serialBuffer(const_cast<uint8 *>(static_cast<const uint8 *>(static_cast<const void *>(waveFourCC))), 4);
515 // riff subchunks
516 // create format header
517 const char *fmtFourCC = "fmt ";
518 // create format data
519 uint16 fmtFormatTag = (uint16)bufferFormat; // 0-1
520 uint16 fmtChannels = (uint16)channels; // 2-3
521 uint32 fmtSamplesPerSec = (uint32)frequency; // 4-7
522 uint16 fmtBitsPerSample = (uint16)bitsPerSample; // 14-15
523 uint16 fmtBlockAlign = fmtChannels * fmtBitsPerSample / 8; // 12-13
524 uint32 fmtAvgBytesPerSec = fmtSamplesPerSec * fmtBlockAlign; // 8-11
525 // uint16 fmtExSize; // 16-17 // only if fmtSize > 16
527 // write format chunk header
528 out.serialBuffer(const_cast<uint8 *>(static_cast<const uint8 *>(static_cast<const void *>(fmtFourCC))), 4);
529 out.serial(fmtSize);
530 // write format chunk data
531 out.serial(fmtFormatTag);
532 out.serial(fmtChannels);
533 out.serial(fmtSamplesPerSec);
534 out.serial(fmtAvgBytesPerSec);
535 out.serial(fmtBlockAlign);
536 out.serial(fmtBitsPerSample);
538 // create data header
539 const char *dataFourCC = "data";
541 // write data chunk header
542 out.serialBuffer(const_cast<uint8 *>(static_cast<const uint8 *>(static_cast<const void *>(dataFourCC))), 4);
543 out.serial(dataSize);
544 // write data chunk data
545 out.serialBuffer(const_cast<uint8 *>(buffer), size);
547 return true;
550 /// Convert buffer data to 16bit Mono PCM.
551 bool IBuffer::convertToMono16PCM(const uint8 *buffer, uint size, std::vector<sint16> &result, TBufferFormat bufferFormat, uint8 channels, uint8 bitsPerSample)
553 if (size == 0 || channels == 0 || bitsPerSample == 0) return false;
555 switch (bufferFormat)
557 case FormatPcm:
559 result.resize((std::vector<sint16>::size_type)(((uint64)size / (uint64)channels) * 8UL / (uint64)bitsPerSample));
560 uint samples = (uint)result.size();
561 switch (bitsPerSample)
563 case 8:
565 const sint8 *src8 = (const sint8 *)(const void *)buffer;
566 uint j = 0;
567 for (uint i = 0; i < samples; ++i)
569 sint32 sample = 0;
570 for (uint k = 0; k < channels; ++k)
571 sample += (sint32)src8[j + k];
572 j += channels;
573 sample *= 256;
574 sample /= channels;
575 result[i] = (sint16)sample;
578 return true;
579 case 16:
581 const sint16 *src16 = (const sint16 *)(const void *)buffer;
582 uint j = 0;
583 for (uint i = 0; i < samples; ++i)
585 sint32 sample = 0;
586 for (uint k = 0; k < channels; ++k)
587 sample += (sint32)src16[j + k];
588 j += channels;
589 sample /= channels;
590 result[i] = (sint16)sample;
593 return true;
594 case 32:
596 const sint32 *src32 = (const sint32 *)(const void *)buffer;
597 uint j = 0;
598 for (uint i = 0; i < samples; ++i)
600 sint64 sample = 0;
601 for (uint k = 0; k < channels; ++k)
602 sample += (sint64)src32[j + k];
603 j += channels;
604 sample /= 65536;
605 sample /= channels;
606 result[i] = (sint16)sample;
609 return true;
610 default:
611 return false;
614 return true;
615 case FormatDviAdpcm:
617 uint samples = size * 2;
618 result.resize(samples);
619 TADPCMState state;
620 state.PreviousSample = 0;
621 state.StepIndex = 0;
622 decodeADPCM(buffer, &result[0], samples, state);
624 return true;
625 case FormatUnknown:
626 default:
627 return false;
631 /// Convert 16bit Mono PCM buffer data to ADPCM.
632 bool IBuffer::convertMono16PCMToMonoADPCM(const sint16 *buffer, uint samples, std::vector<uint8> &result)
634 if (samples == 0) return false;
636 // Allocate ADPCM dest
637 samples &= 0xfffffffe;
638 result.resize(samples / 2);
640 // Encode
641 TADPCMState state;
642 state.PreviousSample = 0;
643 state.StepIndex = 0;
644 encodeADPCM(buffer, &result[0], samples, state);
646 return true;
649 } // NLSOUND