/* olcPGEX_AudioSource.h +-------------------------------------------------------------+ | OneLoneCoder Pixel Game Engine Extension | | AudioSource v1.0 | +-------------------------------------------------------------+ What is this? ~~~~~~~~~~~~~ This is an extension to the olcPixelGameEngine v2.16 and above. It is to be used in conjunction with olcPGEX_AudioListener.h. A detailed description and instructions can be found in that header file, please refer to it instead :-) Enjoy! License (OLC-3) ~~~~~~~~~~~~~~~ Copyright 2018 - 2019 OneLoneCoder.com Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions or derivations of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions or derivative works in binary form must reproduce the above copyright notice. This list of conditions and the following disclaimer must be reproduced in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Author ~~~~~~ Justin Richards */ #ifndef OLC_PGEX_AUDIO_SOURCE #define OLC_PGEX_AUDIO_SOURCE #pragma once #include "olcPGEX_AudioListener.h" class olcPGEX_AudioSource : public olc::PGEX { public: // Pointer to the Audio Listener for this object olcPGEX_AudioListener* AL; // Handle for this particular copy of the sound int handle = 255; // Maximum copies of this sound allowed for this audio source //const int nMaxSamples = 4; //int nSampleHandles[4] = { 255, 255, 255, 255 }; // Audio Sample ID used to locate which sound to play int nID; // Convenient BOOL to determine playback status bool bIsPlaying = false; // Current Playback Speed float fPlaySpeed = 1.0f; // Volume float fVolume = 1.0f; float fMinVolume = 0.0f; float fMaxVolume = 1.0f; // Does the Audio Sample Loop? bool bLooping = false; // Paused status bool bPaused = false; // Object position, used for calculating volume olc::vf2d pos = { 0.0f, 0.0f }; // Instruct Audio Listener to load this sound (if not loaded already) void LoadAudioSample(int ID, const char* fileName); void PlayCentered(float speed = 1.0f, float vol = 1.0f, bool looping = false, bool paused = false); // Play the Audio Sample, with given parameters int Play(vf2d pos, float speed = 1.0f, float vol = 1.0f, bool looping = false, bool paused = false); // Pause or Un-Pause - maintains the playback position and handle void Pause(bool pauseState = true); // Stop - playback position and handle will be lost void Stop(); void Stop(int handle); // Audio Modulation - control the speed of playback void ModulateAudio(float minPlaySpeed, float maxPlaySpeed, float modulation, bool precise = false, bool deferred = false); // Adjust Volume void SetVolume(float vol, float minVol = 0.0f, float maxVol = 1.0f); // Set Default Parameters void SetDefaults(float speed, float vol, float minVol, float maxVol, bool looping); }; #ifdef AUDIO_SOURCE_IMPLEMENTATION #undef AUDIO_SOURCE_IMPLEMENTATION void olcPGEX_AudioSource::LoadAudioSample(int ID, const char* fileName) { // Link the IDs together nID = ID; // Call the Audio Listener to load the sample AL->LoadAudioSample(ID, fileName); } void olcPGEX_AudioSource::PlayCentered(float speed, float vol, bool looping, bool paused) { // Set parameters fPlaySpeed = speed; fVolume = vol; bLooping = looping; bPaused = paused; this->pos = pos; // Assign a handle to this instance of the sound we are about to play handle = AL->soloud.play(*AL->GetAudioSampleByID(nID)->wav, fVolume, 0.0f, bPaused); // Set speed and looping AL->soloud.setRelativePlaySpeed(handle, fPlaySpeed); AL->soloud.setLooping(handle, looping); // Update Play status bIsPlaying = true; } int olcPGEX_AudioSource::Play(vf2d pos, float speed, float vol, bool looping, bool paused) { // Set parameters fPlaySpeed = speed; fVolume = vol*std::max(0.f,abs(1-std::min(1.0f,(AL->GetDistance(pos)/1024.f)))); bLooping = looping; bPaused = paused; this->pos = pos; // Assign a handle to this instance of the sound we are about to play handle = AL->soloud.play(*AL->GetAudioSampleByID(nID)->wav, fVolume, 0.0f, bPaused); AL->handles.push_back({pos,vol,handle}); // Set speed and looping AL->soloud.setRelativePlaySpeed(handle, fPlaySpeed); AL->soloud.setLooping(handle, looping); AL->soloud.setPan(handle,std::clamp((pos.x-AL->vecPos.x)/1024,-1.f,1.f)); // Update Play status bIsPlaying = true; return handle; } void olcPGEX_AudioSource::Pause(bool pauseState) { // Use the Audio Listener to pause or un-pause the sound as neccessary AL->soloud.setPause(handle, pauseState); // Update Play status bIsPlaying = !pauseState; } void olcPGEX_AudioSource::Stop(int handle) { // Use the Audio Listener to stop the sound AL->soloud.stop(handle); } void olcPGEX_AudioSource::Stop() { // Use the Audio Listener to stop the sound AL->soloud.stop(handle); // The current handle will now point to nothing, so we set it to MAX so we can test for validity if need be handle = 255; // Update Play status bIsPlaying = false; } void olcPGEX_AudioSource::ModulateAudio(float minPlaySpeed, float maxPlaySpeed, float modulation, bool precise, bool deferred) { // Apply the modulation if (precise) fPlaySpeed = modulation; else fPlaySpeed += modulation; // Adjust the play speed to keep it within range if (fPlaySpeed < minPlaySpeed) fPlaySpeed = minPlaySpeed; else if (fPlaySpeed > maxPlaySpeed) fPlaySpeed = maxPlaySpeed; // If multiple adjustments to the playback speed are required, then the Audio Listener update itself can be // deferred until the very last adjustment is made... A small optimisation if (!deferred) AL->soloud.setRelativePlaySpeed(handle, fPlaySpeed); } void olcPGEX_AudioSource::SetVolume(float vol, float minVol, float maxVol) { // Set volume fVolume = vol; // Clamp volume withing set bounds if (fVolume < minVol) fVolume = minVol; else if (fVolume > maxVol) fVolume = maxVol; // Instruct the Audio Listener to apply the volume change AL->soloud.setVolume(handle, fVolume); } void olcPGEX_AudioSource::SetDefaults(float speed, float vol, float minVol, float maxVol, bool looping) { // Set defaults for this particular Audio Source fPlaySpeed = speed; fVolume = vol; fMinVolume = minVol; fMaxVolume = maxVol; bLooping = looping; } #endif // AUDIO_SOURCE_IMPLEMENTATION #endif typedef olcPGEX_AudioSource Audio;