From ffa134b02b2d2d4dababddcf7d6a2b88284d86f8 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 30 Nov 2019 08:57:50 +0100 Subject: [PATCH] Documented the voices --- src/sfizz/Voice.h | 192 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 190 insertions(+), 2 deletions(-) diff --git a/src/sfizz/Voice.h b/src/sfizz/Voice.h index ae58b756..59fd94ab 100644 --- a/src/sfizz/Voice.h +++ b/src/sfizz/Voice.h @@ -36,49 +36,237 @@ #include namespace sfz { +/** + * @brief The SFZ voice are the polyphony holders. They get activated by the synth + * and tasked to play a given region until the end, stopping on note-offs, off-groups + * or natural sample decay. + * + */ class Voice { public: Voice() = delete; + /** + * @brief Construct a new voice with the midistate singleton + * + * @param midiState + */ Voice(const MidiState& midiState); enum class TriggerType { NoteOn, NoteOff, CC }; + /** + * @brief Change the sample rate of the voice. This is used to compute all + * pitch related transformations so it needs to be propagated from the synth + * at all times. + * + * @param sampleRate + */ void setSampleRate(float sampleRate) noexcept; + /** + * @brief Set the expected block size. If the block size is not fixed, set an + * upper bound. The voice will adapt at each callback to the actual number of + * samples requested but this function will allocate temporary buffers that are + * needed for proper functioning. + * + * @param samplesPerBlock + */ void setSamplesPerBlock(int samplesPerBlock) noexcept; - + + /** + * @brief Start playing a region after a short delay for different triggers (note on, off, cc) + * + * @param region + * @param delay + * @param channel + * @param number + * @param value + * @param triggerType + */ void startVoice(Region* region, int delay, int channel, int number, uint8_t value, TriggerType triggerType) noexcept; + /** + * @brief Tells the voice that it should expect to receive a file at some point using the + * setFileData() function. The ticket is a unique identifier that will prevent the file data + * to be set "too late"; if the voice receives the file for an older ticket, it will discard + * it. + * + * @param ticket + */ void expectFileData(unsigned ticket); + /** + * @brief Sets the file data for a given ticket. The voice can freely release and destroy the + * shared pointer, as it will be garbage collected by the file pool afterwards. + * + * @param file + * @param ticket + */ void setFileData(std::shared_ptr> file, unsigned ticket) noexcept; + /** + * @brief Register a note-off event; this may trigger a release. + * + * @param delay + * @param channel + * @param noteNumber + * @param velocity + */ void registerNoteOff(int delay, int channel, int noteNumber, uint8_t velocity) noexcept; + /** + * @brief Register a CC event; this may trigger a release. If the voice is playing and its + * region has CC modifiers, it will use this value to compute the CC envelope to apply to the + * parameter. + * + * @param delay + * @param channel + * @param ccNumber + * @param ccValue + */ void registerCC(int delay, int channel, int ccNumber, uint8_t ccValue) noexcept; + /** + * @brief Register a pitch wheel event; for now this does nothing + * + * @param delay + * @param channel + * @param pitch + */ void registerPitchWheel(int delay, int channel, int pitch) noexcept; + /** + * @brief Register an aftertouch event; for now this does nothing + * + * @param delay + * @param channel + * @param aftertouch + */ void registerAftertouch(int delay, int channel, uint8_t aftertouch) noexcept; + /** + * @brief Register a tempo event; for now this does nothing + * + * @param delay + * @param channel + * @param pitch + */ void registerTempo(int delay, float secondsPerQuarter) noexcept; + /** + * @brief Checks if the voice should be offed by another starting in the group specified. + * This will trigger the release if true. + * + * @param delay + * @param group + * @return true + * @return false + */ bool checkOffGroup(int delay, uint32_t group) noexcept; + /** + * @brief Render a block of data for this voice into the span + * + * @param buffer + */ void renderBlock(AudioSpan buffer) noexcept; + /** + * @brief Is the voice free? + * + * @return true + * @return false + */ bool isFree() const noexcept; + /** + * @brief Can the voice be "stolen" and reused (i.e. is it releasing) + * + * @return true + * @return false + */ bool canBeStolen() const noexcept; + /** + * @brief Get the number that triggered the voice (note number or cc number) + * + * @return int + */ int getTriggerNumber() const noexcept; + /** + * @brief Get the channel that triggered the voice + * + * @return int + */ int getTriggerChannel() const noexcept; + /** + * @brief Get the value that triggered the voice (note velocity or cc value) + * + * @return uint8_t + */ uint8_t getTriggerValue() const noexcept; + /** + * @brief Get the type of trigger + * + * @return TriggerType + */ TriggerType getTriggerType() const noexcept; + /** + * @brief Reset the voice to its initial values + * + */ void reset() noexcept; + /** + * @brief Clear the loaded file data if it's not useful anymore + * + */ void garbageCollect() noexcept; + /** + * @brief Get the mean squared power of the last rendered block. This is used + * to determine which voice to steal if there are too many notes flying around. + * + * @return float + */ float getMeanSquaredAverage() const noexcept; + /** + * @brief Get the position of the voice in the source, in samples + * + * @return uint32_t + */ uint32_t getSourcePosition() const noexcept; private: + /** + * @brief Fill a span with data from a file source. This is the first step + * in rendering each block of data. + * + * @param buffer + */ void fillWithData(AudioSpan buffer) noexcept; + /** + * @brief Fill a span with data from a generator source. This is the first step + * in rendering each block of data. + * + * @param buffer + */ void fillWithGenerator(AudioSpan buffer) noexcept; + /** + * @brief Computes the values for the envelope depending on the note or CC number and the velocity/cc value + * + * @param delay + * @param velocity + */ void prepareEGEnvelope(int delay, uint8_t velocity) noexcept; + /** + * @brief The function processing a mono sample source + * + * @param buffer + */ void processMono(AudioSpan buffer) noexcept; + /** + * @brief The function processing a stereo sample source + * + * @param buffer + */ void processStereo(AudioSpan buffer) noexcept; + /** + * @brief Release the voice after a given delay + * + * @param delay + */ void release(int delay) noexcept; Region* region { nullptr }; @@ -137,4 +325,4 @@ private: LEAK_DETECTOR(Voice); }; -} // namespace sfz \ No newline at end of file +} // namespace sfz