#include "SamplerVoice.h" SamplerVoice::SamplerVoice() = default; SamplerVoice::~SamplerVoice() { clear(); } void SamplerVoice::prepareToPlay(double sampleRate, int) { this->sampleRate = sampleRate; } void SamplerVoice::releaseResources() { isVoiceActive = false; } void SamplerVoice::noteOn(int noteNumber, int velocity) { if (sampleData == nullptr || sampleData->getNumSamples() == 0) return; this->noteNumber = noteNumber; this->velocity = static_cast(velocity) / 127.0f; this->isVoiceActive = true; this->samplePosition = 0; // Calculate pitch ratio based on MIDI note (middle C = 60) pitchRatio = std::pow(2.0, (noteNumber - 60) / 12.0); } void SamplerVoice::noteOff() { if (!loopMode) { isVoiceActive = false; } } void SamplerVoice::renderNextBlock(juce::AudioBuffer& outputBuffer, int startSample, int numSamples) { if (!isVoiceActive || sampleData == nullptr) return; const int numChannels = juce::jmin(outputBuffer.getNumChannels(), sampleData->getNumChannels()); const int sampleLength = sampleData->getNumSamples(); for (int sample = 0; sample < numSamples; ++sample) { if (samplePosition >= sampleLength) { if (loopMode) { samplePosition = 0; } else { isVoiceActive = false; break; } } for (int channel = 0; channel < numChannels; ++channel) { auto* destData = outputBuffer.getWritePointer(channel); const auto* srcData = sampleData->getReadPointer(channel); destData[startSample + sample] += srcData[samplePosition] * velocity * volume; } samplePosition += static_cast(pitchRatio); } } bool SamplerVoice::loadSample(const juce::String& filePath) { juce::File file(filePath); if (!file.existsAsFile()) { jassertfalse; return false; } juce::AudioFormatManager formatManager; formatManager.registerBasicFormats(); std::unique_ptr reader( formatManager.createReaderFor(file)); if (reader == nullptr) return false; auto newBuffer = std::make_unique>( reader->numChannels, static_cast(reader->lengthInSamples)); reader->read(newBuffer.get(), 0, reader->lengthInSamples, 0, true, true); sampleData = newBuffer.release(); sampleRate = reader->sampleRate; return true; } void SamplerVoice::clear() { delete sampleData; sampleData = nullptr; isVoiceActive = false; samplePosition = 0; } void SamplerVoice::setLoopMode(bool shouldLoop) { loopMode = shouldLoop; } void SamplerVoice::setVolume(float vol) { volume = juce::jlimit(0.0f, 1.0f, vol); } void SamplerVoice::setTempo(double bpm) { currentBpm = bpm; // Could adjust playback speed based on tempo for time-stretching }