#include "SoundPlayer.h" namespace dsr { SoundPlayer::SoundPlayer(const SoundBuffer &soundBuffer, int32_t soundIndex, int64_t playerID, bool repeat, uint32_t startLocation, float leftVolume, float rightVolume, const EnvelopeSettings &envelopeSettings) : soundBuffer(soundBuffer), soundIndex(soundIndex), playerID(playerID), repeat(repeat), location(startLocation % sound_getSamplesPerChannel(soundBuffer)), fadeLeft(leftVolume < 0.9999f || leftVolume > 1.0001f), fadeRight(rightVolume < 0.9999f || rightVolume > 1.0001f), leftVolume(leftVolume), rightVolume(rightVolume), envelope(envelopeSettings) {} void player_getNextSamples(SoundPlayer &player, SafePointer target, int32_t playedSamplesPerChannel, double secondsPerSample) { uint32_t totalSamplesPerChannel = sound_getSamplesPerChannel(player.soundBuffer); uint32_t channelCount = sound_getChannelCount(player.soundBuffer); SafePointer source = sound_getSafePointer(player.soundBuffer); uint32_t startIndex = player.location; uint32_t blockBytes = channelCount * sizeof(float); if (startIndex + playedSamplesPerChannel > totalSamplesPerChannel) { // TODO: Properly test this part of the code using regression tests. SafePointer writer = target; // Calculate how many samples that are inside of the buffer. uint32_t insideSamples = totalSamplesPerChannel - startIndex; if (insideSamples > 0) { uintptr_t insideBytes = insideSamples * blockBytes; safeMemoryCopy(writer, source + (player.location * channelCount), insideBytes); writer.increaseBytes(insideBytes); } // Calculate how many samples that are outside of the buffer. uint32_t outsideSamples = playedSamplesPerChannel - insideSamples; if (player.repeat) { // Copy whole laps of the sound buffer. uintptr_t wholeLapBytes = totalSamplesPerChannel * blockBytes; while (outsideSamples >= totalSamplesPerChannel) { safeMemoryCopy(writer, source, wholeLapBytes); writer.increaseBytes(wholeLapBytes); outsideSamples -= totalSamplesPerChannel; } // Copy a partial lap at the end if there are samples remaining. if (outsideSamples > 0) { uintptr_t lastLapBytes = outsideSamples * blockBytes; safeMemoryCopy(writer, source, lastLapBytes); } } else { // Padd the outside with zeroes. uint32_t outsideBytes = outsideSamples * blockBytes; safeMemorySet(target, 0, outsideBytes); player.sustained = false; } } else { // Only a single copy is needed to fill the output buffer with samples. safeMemoryCopy(target, source + (player.location * channelCount), playedSamplesPerChannel * blockBytes); } player.location += playedSamplesPerChannel; if (player.repeat) { while (player.location >= totalSamplesPerChannel) { player.location -= totalSamplesPerChannel; } } // Apply optional envelope if (player.envelope.envelopeSettings.used) { SafePointer currentTarget = target; for (int32_t s = 0; s < playedSamplesPerChannel; s++) { float volume = float(player.envelope.getVolume(player.sustained, secondsPerSample)); for (uint32_t c = 0; c < channelCount; c++) { *currentTarget *= volume; currentTarget += 1; } } } } }