void playSoundWav(uint8_t channel, const uint8_t *data, uint8_t volume, int loops = 0) { uint32_t size = READ_LE_UINT32(data + 4) + 8; // check format for QuickLoad bool canQuickLoad = (AUDIO_S16SYS == AUDIO_S16LSB); if (canQuickLoad) { if (memcmp(data + 8, "WAVEfmt ", 8) == 0 && READ_LE_UINT32(data + 16) == 16) { const uint8_t *fmt = data + 20; const int format = READ_LE_UINT16(fmt); const int channels = READ_LE_UINT16(fmt + 2); const int rate = READ_LE_UINT32(fmt + 4); const int bits = READ_LE_UINT16(fmt + 14); debug(DBG_SND, "wave format %d channels %d rate %d bits %d", format, channels, rate, bits); canQuickLoad = (format == 1 && channels == 2 && rate == kMixFreq && bits == 16); } } if (canQuickLoad) { Mix_Chunk *chunk = Mix_QuickLoad_WAV(const_cast<uint8_t *>(data)); playSound(channel, volume, chunk, loops); } else { SDL_RWops *rw = SDL_RWFromConstMem(data, size); Mix_Chunk *chunk = Mix_LoadWAV_RW(rw, 1); playSound(channel, volume, chunk, loops); } }
// Volume 0-I2X (1) int CAudioChannel::Start (short nSound, int nSoundClass, fix nVolume, int nPan, int bLooping, int nLoopStart, int nLoopEnd, int nSoundObj, int nSpeed, const char *pszWAV, CFixVector* vPos) { CSoundSample* soundP = NULL; int bPersistent = (nSoundObj > -1) || bLooping || (nVolume > I2X (1)); if (!(pszWAV && *pszWAV && gameOpts->sound.bUseSDLMixer)) { if (nSound < 0) return -1; if (!gameData.pig.sound.nSoundFiles [gameStates.sound.bD1Sound]) return -1; soundP = gameData.pig.sound.sounds [gameStates.sound.bD1Sound] + nSound % gameData.pig.sound.nSoundFiles [gameStates.sound.bD1Sound]; if (!(soundP->data [soundP->bCustom].Buffer () && soundP->nLength [soundP->bCustom])) return -1; } if (m_info.bPlaying) { m_info.bPlaying = 0; if (m_info.nSoundObj > -1) audio.EndSoundObject (m_info.nSoundObj); if (soundQueue.Channel () == audio.FreeChannel ()) soundQueue.End (); } #if USE_OPENAL if (m_info.source == 0xFFFFFFFF) { CFloatVector fPos; DigiALError (); alGenSources (1, &m_info.source); if (DigiALError ()) return -1; alSourcei (m_info.source, AL_BUFFER, soundP->buffer); if (DigiALError ()) return -1; alSourcef (m_info.source, AL_GAIN, ((nVolume < I2X (1)) ? X2F (nVolume) : 1) * 2 * X2F (m_info.nVolume)); alSourcei (m_info.source, AL_LOOPING, (ALuint) ((nSoundObj > -1) || bLooping || (nVolume > I2X (1)))); fPos.Assign (vPos ? *vPos : OBJECTS [LOCALPLAYER.nObject].nPosition.vPos); alSourcefv (m_info.source, AL_POSITION, reinterpret_cast<ALfloat*> (fPos)); alSource3f (m_info.source, AL_VELOCITY, 0, 0, 0); alSource3f (m_info.source, AL_DIRECTION, 0, 0, 0); if (DigiALError ()) return -1; alSourcePlay (m_info.source); if (DigiALError ()) return -1; } #endif #if USE_SDL_MIXER if (gameOpts->sound.bUseSDLMixer) { if (m_info.mixChunkP) { Mix_HaltChannel (m_info.nChannel); if (m_info.bBuiltIn) m_info.bBuiltIn = 0; else Mix_FreeChunk (m_info.mixChunkP); m_info.mixChunkP = NULL; } } #endif if (m_info.bResampled) { m_info.sample.Destroy (); m_info.bResampled = 0; } #if USE_SDL_MIXER if (gameOpts->sound.bUseSDLMixer) { //resample to two channels m_info.nChannel = audio.FreeChannel (); if (pszWAV && *pszWAV) { if (!(m_info.mixChunkP = LoadAddonSound (pszWAV, &m_info.bBuiltIn))) return -1; } else { int l; if (soundP->bHires) { l = soundP->nLength [soundP->bCustom]; m_info.sample.SetBuffer (soundP->data [soundP->bCustom].Buffer (), 1, l); m_info.mixChunkP = Mix_QuickLoad_WAV (reinterpret_cast<Uint8*> (m_info.sample.Buffer ())); } else { if (gameOpts->sound.bHires [0]) return -1; //cannot mix hires and standard sounds l = Resample (soundP, gameStates.sound.bD1Sound && (gameOpts->sound.digiSampleRate != SAMPLE_RATE_11K), songManager.MP3 ()); if (l <= 0) return -1; if (nSpeed < I2X (1)) l = Speedup (soundP, nSpeed); #if MAKE_WAV m_info.mixChunkP = Mix_QuickLoad_WAV (reinterpret_cast<Uint8*> (m_info.sample.Buffer ())); #else m_info.mixChunkP = Mix_QuickLoad_RAW (reinterpret_cast<Uint8*> (m_info.sample.Buffer ()), l); #endif } } Mix_VolPan (m_info.nChannel, nVolume, nPan); Mix_PlayChannel (m_info.nChannel, m_info.mixChunkP, bLooping ? -1 : nLoopEnd - nLoopStart); } else #else if (pszWAV && *pszWAV) return -1; #endif { if (gameStates.sound.bD1Sound && (gameOpts->sound.digiSampleRate != SAMPLE_RATE_11K)) { int l = Resample (soundP, 0, 0); if (l <= 0) return -1; m_info.nLength = l; } else { m_info.sample.SetBuffer (soundP->data [soundP->bCustom].Buffer (), 1, m_info.nLength = soundP->nLength [soundP->bCustom]); } if (nSpeed < I2X (1)) Speedup (soundP, nSpeed); } m_info.nVolume = FixMul (audio.Volume (), nVolume); m_info.nPan = nPan; m_info.nPosition = 0; m_info.nSoundObj = nSoundObj; m_info.nSoundClass = nSoundClass; m_info.bLooped = bLooping; #if USE_OPENAL m_info.loops = bLooping ? -1 : nLoopEnd - nLoopStart + 1; #endif m_info.nSound = nSound; m_info.bPersistent = 0; m_info.bPlaying = 1; m_info.bPersistent = bPersistent; return audio.FreeChannel (); }
// Volume 0-F1_0 int DigiStartSound (short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int soundobj, int speed, char *pszWAV) { int i, starting_channel; struct sound_slot *ssp; digi_sound *gsp; if (!gameStates.sound.digi.bInitialized) return -1; if (!(pszWAV && gameOpts->sound.bUseSDLMixer)) { if (soundnum < 0) return -1; gsp = gameData.pig.snd.sounds [gameOpts->sound.bD1Sound] + soundnum % gameData.pig.snd.nSoundFiles [gameOpts->sound.bD1Sound]; if (!(gsp->data && gsp->length)) return -1; Assert(gsp->data != (void *) -1); } starting_channel = gameStates.sound.digi.nNextChannel; #if 0 //USE_SDL_MIXER if (gameOpts->sound.bUseSDLMixer) { do { if ((SoundSlots [gameStates.sound.digi.nNextChannel].soundno == soundnum) && SoundSlots [gameStates.sound.digi.nNextChannel].persistent) goto foundChannel; gameStates.sound.digi.nNextChannel++; if (gameStates.sound.digi.nNextChannel >= gameStates.sound.digi.nMaxChannels) gameStates.sound.digi.nNextChannel = 0; } while (gameStates.sound.digi.nNextChannel != starting_channel); #endif while (1) { if (!SoundSlots [gameStates.sound.digi.nNextChannel].playing) break; if (!SoundSlots [gameStates.sound.digi.nNextChannel].persistent) break; // use this channel! gameStates.sound.digi.nNextChannel++; if (gameStates.sound.digi.nNextChannel >= gameStates.sound.digi.nMaxChannels) gameStates.sound.digi.nNextChannel = 0; if (gameStates.sound.digi.nNextChannel == starting_channel) { //mprintf((1, "OUT OF SOUND CHANNELS!!!\n")); return -1; } } #if 0 } foundChannel: #endif ssp = SoundSlots + gameStates.sound.digi.nNextChannel; if (ssp->playing) { ssp->playing = 0; if (ssp->soundobj > -1) DigiEndSoundObj (ssp->soundobj); if (SoundQ_channel == gameStates.sound.digi.nNextChannel) SoundQEnd(); } #if USE_SDL_MIXER if (ssp->mixChunk) { Mix_HaltChannel (ssp->channel); Mix_FreeChunk (ssp->mixChunk); ssp->mixChunk = NULL; } #endif #ifndef NDEBUG VerifySoundChannelFree (gameStates.sound.digi.nNextChannel); #endif if (ssp->bResampled) { d_free (ssp->samples); ssp->bResampled = 0; } #if USE_SDL_MIXER if (gameOpts->sound.bUseSDLMixer) { //resample to two channels ssp->channel = gameStates.sound.digi.nNextChannel; if (pszWAV) { #if 0 if (!(ssp->samples = CFReadData (pszWAV, gameFolders.szDataDir, 0))) return -1; ssp->mixChunk = Mix_QuickLoad_WAV ((Uint8 *) ssp->samples); #else char szWAV [FILENAME_LEN]; if (!CFExtract (pszWAV, gameFolders.szDataDir, 0, "d2x-temp.wav")) return -1; # ifdef _WIN32 sprintf (szWAV, "%s%sd2x-temp.wav", gameFolders.szDataDir, *gameFolders.szDataDir ? "/" : ""); # else sprintf (szWAV, "%s%sd2x-temp.wav", gameFolders.szHomeDir, *gameFolders.szHomeDir ? "/" : ""); # endif ssp->mixChunk = Mix_LoadWAV (szWAV); #endif } else { int l = DigiResampleSound (gsp, ssp, gameOpts->sound.bD1Sound && (gameOpts->sound.digiSampleRate != SAMPLE_RATE_11K)); if (l <= 0) return -1; if (speed < F1_0) l = DigiSpeedupSound (gsp, ssp, speed); ssp->mixChunk = Mix_QuickLoad_RAW (ssp->samples, l); } Mix_VolPan (gameStates.sound.digi.nNextChannel, volume, pan); Mix_PlayChannel (gameStates.sound.digi.nNextChannel, ssp->mixChunk, looping ? -1 : loop_end - loop_start); } else #else if (pszWAV) return -1; #endif { if (gameOpts->sound.bD1Sound && (gameOpts->sound.digiSampleRate != SAMPLE_RATE_11K)) { int l = DigiResampleSound (gsp, ssp, 0); if (l <= 0) return -1; ssp->length = l; } else { ssp->samples = gsp->data; ssp->length = gsp->length; } if (speed < F1_0) DigiSpeedupSound (gsp, ssp, speed); } ssp->volume = FixMul (gameStates.sound.digi.nVolume, volume); ssp->pan = pan; ssp->position = 0; ssp->soundobj = soundobj; ssp->looped = looping; ssp->soundno = soundnum; ssp->persistent = 0; ssp->playing = 1; ssp->persistent = (soundobj > -1) || looping || (volume > F1_0); i = gameStates.sound.digi.nNextChannel; if (++gameStates.sound.digi.nNextChannel >= gameStates.sound.digi.nMaxChannels) gameStates.sound.digi.nNextChannel = 0; return i; }