/* * This program is free software; you can redistribute it and modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the license or (at your * option) any later version. * * Authors: Olivier Lapicque */ #include "stdafx.h" #include "sndfile.h" #ifndef WAVE_FORMAT_EXTENSIBLE #define WAVE_FORMAT_EXTENSIBLE 0xFFFE #endif ///////////////////////////////////////////////////////////// // WAV file support BOOL CSoundFile::ReadWav(const BYTE *lpStream, DWORD dwMemLength) //--------------------------------------------------------------- { DWORD dwMemPos = 0; WAVEFILEHEADER *phdr = (WAVEFILEHEADER *)lpStream; WAVEFORMATHEADER *pfmt = (WAVEFORMATHEADER *)(lpStream + sizeof(WAVEFILEHEADER)); if ((!lpStream) || (dwMemLength < (DWORD)sizeof(WAVEFILEHEADER))) return FALSE; if ((phdr->id_RIFF != IFFID_RIFF) || (phdr->id_WAVE != IFFID_WAVE) || (pfmt->id_fmt != IFFID_fmt)) return FALSE; dwMemPos = sizeof(WAVEFILEHEADER) + 8 + pfmt->hdrlen; if ((dwMemPos + 8 >= dwMemLength) || ((pfmt->format != WAVE_FORMAT_PCM) && (pfmt->format != WAVE_FORMAT_EXTENSIBLE)) || (pfmt->channels > 4) || (!pfmt->channels) || (!pfmt->freqHz) || (pfmt->bitspersample & 7) || (pfmt->bitspersample < 8) || (pfmt->bitspersample > 32)) return FALSE; WAVEDATAHEADER *pdata; for (;;) { pdata = (WAVEDATAHEADER *)(lpStream + dwMemPos); if (pdata->id_data == IFFID_data) break; dwMemPos += pdata->length + 8; if (dwMemPos + 8 >= dwMemLength) return FALSE; } m_nType = MOD_TYPE_WAV; m_nSamples = 0; m_nInstruments = 0; m_nChannels = 4; m_nDefaultSpeed = 8; m_nDefaultTempo = 125; m_dwSongFlags |= SONG_LINEARSLIDES; // For no resampling Order[0] = 0; Order[1] = 0xFF; PatternSize[0] = PatternSize[1] = 64; if ((Patterns[0] = AllocatePattern(64, 4)) == NULL) return TRUE; if ((Patterns[1] = AllocatePattern(64, 4)) == NULL) return TRUE; UINT samplesize = (pfmt->channels * pfmt->bitspersample) >> 3; UINT len = pdata->length, bytelen; if (dwMemPos + len > dwMemLength - 8) len = dwMemLength - dwMemPos - 8; len /= samplesize; bytelen = len; if (pfmt->bitspersample >= 16) bytelen *= 2; if (len > MAX_SAMPLE_LENGTH) len = MAX_SAMPLE_LENGTH; if (!len) return TRUE; // Setting up module length DWORD dwTime = ((len * 50) / pfmt->freqHz) + 1; DWORD framesperrow = (dwTime + 63) / 63; if (framesperrow < 4) framesperrow = 4; UINT norders = 1; while (framesperrow >= 0x20) { Order[norders++] = 1; Order[norders] = 0xFF; framesperrow = (dwTime + (64 * norders - 1)) / (64 * norders); if (norders >= MAX_ORDERS-1) break; } m_nDefaultSpeed = framesperrow; for (UINT iChn=0; iChn<4; iChn++) { ChnSettings[iChn].nPan = (iChn & 1) ? 256 : 0; ChnSettings[iChn].nVolume = 64; ChnSettings[iChn].dwFlags = 0; } // Setting up speed command MODCOMMAND *pcmd = Patterns[0]; pcmd[0].command = CMD_SPEED; pcmd[0].param = (BYTE)m_nDefaultSpeed; pcmd[0].note = 5*12+1; pcmd[0].instr = 1; pcmd[1].note = pcmd[0].note; pcmd[1].instr = pcmd[0].instr; m_nSamples = pfmt->channels; // Support for Multichannel Wave for (UINT nChn=0; nChnnLength = len; pins->nC4Speed = pfmt->freqHz; pins->nVolume = 256; pins->nPan = 128; pins->nGlobalVol = 64; pins->uFlags = (WORD)((pfmt->bitspersample >= 16) ? CHN_16BIT : 0); pins->uFlags |= CHN_PANNING; if (m_nSamples > 1) { switch(nChn) { case 0: pins->nPan = 0; break; case 1: pins->nPan = 256; break; case 2: pins->nPan = (WORD)((m_nSamples == 3) ? 128 : 64); pcmd[nChn].command = CMD_S3MCMDEX; pcmd[nChn].param = 0x91; break; case 3: pins->nPan = 192; pcmd[nChn].command = CMD_S3MCMDEX; pcmd[nChn].param = 0x91; break; default: pins->nPan = 128; break; } } if ((pins->pSample = AllocateSample(bytelen+8)) == NULL) return TRUE; if (pfmt->bitspersample >= 16) { int slsize = pfmt->bitspersample >> 3; signed short *p = (signed short *)pins->pSample; signed char *psrc = (signed char *)(lpStream+dwMemPos+8+nChn*slsize+slsize-2); for (UINT i=0; ipSample; signed char *psrc = (signed char *)(lpStream+dwMemPos+8+nChn); for (UINT i=0; i dwBytes)) return FALSE; nPos = 0; while ((nPos < nLen) && (dwBytes > 4)) { int nIndex; value = *((short int *)psrc); nIndex = psrc[2]; psrc += 4; dwBytes -= 4; pdest[nPos++] = (short int)value; for (UINT i=0; ((i<(pkBlkAlign-4)*2) && (nPos < nLen) && (dwBytes)); i++) { BYTE delta; if (i & 1) { delta = (BYTE)(((*(psrc++)) >> 4) & 0x0F); dwBytes--; } else { delta = (BYTE)((*psrc) & 0x0F); } int v = gIMAUnpackTable[nIndex] >> 3; if (delta & 1) v += gIMAUnpackTable[nIndex] >> 2; if (delta & 2) v += gIMAUnpackTable[nIndex] >> 1; if (delta & 4) v += gIMAUnpackTable[nIndex]; if (delta & 8) value -= v; else value += v; nIndex += gIMAIndexTab[delta & 7]; if (nIndex < 0) nIndex = 0; else if (nIndex > 88) nIndex = 88; if (value > 32767) value = 32767; else if (value < -32768) value = -32768; pdest[nPos++] = (short int)value; } } return TRUE; }