Skip to content

Commit

Permalink
Merge pull request #820 from jpcima/hd-apis
Browse files Browse the repository at this point in the history
Add high-precision API for note, aftertouch and bend
  • Loading branch information
jpcima authored Apr 12, 2021
2 parents 6229bbe + 3c9a754 commit 5a4b1f5
Show file tree
Hide file tree
Showing 10 changed files with 289 additions and 29 deletions.
2 changes: 1 addition & 1 deletion plugins/vst/SfizzVstParameters.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ struct SfizzRange {
case kPidAftertouch:
return {0.0, 0.0, 1.0};
case kPidPitchBend:
return {0.5, 0.0, 1.0};
return {0.0, -1.0, 1.0};
default:
if (id >= kPidCC0 && id <= kPidCCLast)
return {0.0, 0.0, 1.0};
Expand Down
21 changes: 5 additions & 16 deletions plugins/vst/SfizzVstProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,6 @@
#include <chrono>
#include <cstring>

template<class T>
constexpr int fastRound(T x)
{
return static_cast<int>(x + T{ 0.5 }); // NOLINT
}

static const char defaultSfzText[] =
"<region>sample=*sine" "\n"
"ampeg_attack=0.02 ampeg_release=0.1" "\n";
Expand Down Expand Up @@ -389,10 +383,10 @@ void SfizzVstProcessor::playOrderedParameter(int32 sampleOffset, Vst::ParamID id
_state.oscillatorQuality = static_cast<int32>(range.denormalize(value));
break;
case kPidAftertouch:
synth.aftertouch(sampleOffset, fastRound(value * 127.0));
synth.hdAftertouch(sampleOffset, value);
break;
case kPidPitchBend:
synth.pitchWheel(sampleOffset, fastRound(value * 16383) - 8192);
synth.hdPitchWheel(sampleOffset, range.denormalize(value));
break;
default:
if (id >= kPidCC0 && id <= kPidCCLast) {
Expand Down Expand Up @@ -422,7 +416,7 @@ void SfizzVstProcessor::playOrderedEvent(const Vst::Event& event)
_noteEventsCurrentCycle[pitch] = 0.0f;
}
else {
synth.noteOn(sampleOffset, pitch, convertVelocityFromFloat(event.noteOn.velocity));
synth.hdNoteOn(sampleOffset, pitch, event.noteOn.velocity);
_noteEventsCurrentCycle[pitch] = event.noteOn.velocity;
}
break;
Expand All @@ -431,15 +425,15 @@ void SfizzVstProcessor::playOrderedEvent(const Vst::Event& event)
int pitch = event.noteOn.pitch;
if (pitch < 0 || pitch >= 128)
break;
synth.noteOff(sampleOffset, pitch, convertVelocityFromFloat(event.noteOff.velocity));
synth.hdNoteOff(sampleOffset, pitch, event.noteOff.velocity);
_noteEventsCurrentCycle[pitch] = 0.0f;
break;
}
case Vst::Event::kPolyPressureEvent: {
int pitch = event.polyPressure.pitch;
if (pitch < 0 || pitch >= 128)
break;
synth.polyAftertouch(sampleOffset, pitch, convertVelocityFromFloat(event.polyPressure.pressure));
synth.hdPolyAftertouch(sampleOffset, pitch, event.polyPressure.pressure);
break;
}
}
Expand Down Expand Up @@ -504,11 +498,6 @@ void SfizzVstProcessor::processMessagesFromUi()
}
}

int SfizzVstProcessor::convertVelocityFromFloat(float x)
{
return std::min(127, std::max(0, (int)(x * 127.0f)));
}

tresult PLUGIN_API SfizzVstProcessor::notify(Vst::IMessage* message)
{
// Note(jpc) this notification is not necessarily handled by the RT thread
Expand Down
1 change: 0 additions & 1 deletion plugins/vst/SfizzVstProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ class SfizzVstProcessor : public Vst::AudioEffect,
void playOrderedEvent(const Vst::Event& event);

void processMessagesFromUi();
static int convertVelocityFromFloat(float x);

tresult PLUGIN_API notify(Vst::IMessage* message) override;

Expand Down
3 changes: 2 additions & 1 deletion scripts/appveyor/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ fi

set -x

brew install dylibbundler
# -- Install if necessary; only if using external libraries (eg. jack, sndfile)
#brew install dylibbundler

cd ~; npm install appdmg; cd -
~/node_modules/appdmg/bin/appdmg.js --version
98 changes: 96 additions & 2 deletions src/sfizz.h
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,24 @@ SFIZZ_EXPORTED_API void sfizz_set_sample_rate(sfizz_synth_t* synth, float sample
*/
SFIZZ_EXPORTED_API void sfizz_send_note_on(sfizz_synth_t* synth, int delay, int note_number, char velocity);

/**
* @brief Send a high-precision on event to the synth.
* @since 0.6.0
*
* This command should be delay-ordered with all other midi-type events
* (notes, CCs, aftertouch and pitch-wheel), otherwise the behavior of the
* synth is undefined.
*
* @param synth The synth.
* @param delay The delay of the event in the block, in samples.
* @param note_number The MIDI note number.
* @param velocity The normalized MIDI velocity, in domain 0 to 1.
*
* @par Thread-safety constraints
* - @b RT: the function must be invoked from the Real-time thread
*/
SFIZZ_EXPORTED_API void sfizz_send_hd_note_on(sfizz_synth_t* synth, int delay, int note_number, float velocity);

/**
* @brief Send a note off event to the synth.
* @since 0.2.0
Expand All @@ -362,6 +380,27 @@ SFIZZ_EXPORTED_API void sfizz_send_note_on(sfizz_synth_t* synth, int delay, int
*/
SFIZZ_EXPORTED_API void sfizz_send_note_off(sfizz_synth_t* synth, int delay, int note_number, char velocity);

/**
* @brief Send a high-precision note off event to the synth.
* @since 0.6.0
*
* This command should be delay-ordered with all other midi-type events
* (notes, CCs, aftertouch and pitch-wheel), otherwise the behavior of the
* synth is undefined.
*
* As per the SFZ spec the velocity of note-off events is usually replaced by
* the note-on velocity.
*
* @param synth The synth.
* @param delay The delay of the event in the block, in samples.
* @param note_number The MIDI note number.
* @param velocity The normalized MIDI velocity, in domain 0 to 1.
*
* @par Thread-safety constraints
* - @b RT: the function must be invoked from the Real-time thread
*/
SFIZZ_EXPORTED_API void sfizz_send_hd_note_off(sfizz_synth_t* synth, int delay, int note_number, float velocity);

/**
* @brief Send a CC event to the synth.
* @since 0.2.0
Expand Down Expand Up @@ -436,6 +475,23 @@ SFIZZ_EXPORTED_API void sfizz_automate_hdcc(sfizz_synth_t* synth, int delay, int
*/
SFIZZ_EXPORTED_API void sfizz_send_pitch_wheel(sfizz_synth_t* synth, int delay, int pitch);

/**
* @brief Send a high-precision pitch wheel event.
* @since 0.6.0
*
* This command should be delay-ordered with all other midi-type events
* (notes, CCs, aftertouch and pitch-wheel), otherwise the behavior of the
* synth is undefined.
*
* @param synth The synth.
* @param delay The delay.
* @param pitch The normalized pitch, in domain -1 to 1.
*
* @par Thread-safety constraints
* - @b RT: the function must be invoked from the Real-time thread
*/
SFIZZ_EXPORTED_API void sfizz_send_hd_pitch_wheel(sfizz_synth_t* synth, int delay, float pitch);

/**
* @brief Send an aftertouch event.
* @since 0.2.0
Expand All @@ -455,8 +511,26 @@ SFIZZ_EXPORTED_API void sfizz_send_pitch_wheel(sfizz_synth_t* synth, int delay,
SFIZZ_EXPORTED_API void sfizz_send_aftertouch(sfizz_synth_t* synth, int delay, char aftertouch);

/**
* @brief Send a polyphonic aftertouch event. This feature is experimental and needs more testing
* in the internal engine.
* @brief Send a high-precision aftertouch event.
* @since 0.6.0
*
* This command should be delay-ordered with all other midi-type events
* (notes, CCs, aftertouch and pitch-wheel), otherwise the behavior of the
* synth is undefined.
*
* @param synth The synth.
* @param delay The delay at which the event occurs; this should be lower
* than the size of the block in the next call to renderBlock().
* @param aftertouch The normalized aftertouch value, in domain 0 to 1.
*
* @par Thread-safety constraints
* - @b RT: the function must be invoked from the Real-time thread
*/
SFIZZ_EXPORTED_API void sfizz_send_hd_aftertouch(sfizz_synth_t* synth, int delay, float aftertouch);

/**
* @brief Send a polyphonic aftertouch event.
* This feature is experimental and needs more testing in the internal engine.
* @since 0.6.0
*
* This command should be delay-ordered with all other midi-type events
Expand All @@ -474,6 +548,26 @@ SFIZZ_EXPORTED_API void sfizz_send_aftertouch(sfizz_synth_t* synth, int delay, c
*/
SFIZZ_EXPORTED_API void sfizz_send_poly_aftertouch(sfizz_synth_t* synth, int delay, int note_number, char aftertouch);

/**
* @brief Send a high-precision polyphonic aftertouch event.
* This feature is experimental and needs more testing in the internal engine.
* @since 0.6.0
*
* This command should be delay-ordered with all other midi-type events
* (notes, CCs, aftertouch and pitch-wheel), otherwise the behavior of the
* synth is undefined.
*
* @param synth The synth.
* @param delay The delay at which the event occurs; this should be lower
* than the size of the block in the next call to renderBlock().
* @param note_number The note number.
* @param aftertouch The normalized aftertouch value, in domain 0 to 1.
*
* @par Thread-safety constraints
* - @b RT: the function must be invoked from the Real-time thread
*/
SFIZZ_EXPORTED_API void sfizz_send_hd_poly_aftertouch(sfizz_synth_t* synth, int delay, int note_number, float aftertouch);

/**
* @brief Send a tempo event.
*
Expand Down
96 changes: 94 additions & 2 deletions src/sfizz.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,24 @@ class SFIZZ_EXPORTED_API Sfizz
*/
void noteOn(int delay, int noteNumber, uint8_t velocity) noexcept;

/**
* @brief Send a high-precision note on event to the synth.
* @since 0.6.0
*
* This command should be delay-ordered with all other midi-type events
* (notes, CCs, aftertouch and pitch-wheel), otherwise the behavior of the
* synth is undefined.
*
* @param delay the delay at which the event occurs; this should be lower
* than the size of the block in the next call to renderBlock().
* @param noteNumber the midi note number.
* @param velocity the normalized midi note velocity, in domain 0 to 1.
*
* @par Thread-safety constraints
* - @b RT: the function must be invoked from the Real-time thread
*/
void hdNoteOn(int delay, int noteNumber, float velocity) noexcept;

/**
* @brief Send a note off event to the synth.
* @since 0.2.0
Expand All @@ -401,6 +419,24 @@ class SFIZZ_EXPORTED_API Sfizz
*/
void noteOff(int delay, int noteNumber, uint8_t velocity) noexcept;

/**
* @brief Send a note off event to the synth.
* @since 0.6.0
*
* This command should be delay-ordered with all other midi-type events
* (notes, CCs, aftertouch and pitch-wheel), otherwise the behavior of the
* synth is undefined.
*
* @param delay the delay at which the event occurs; this should be lower
* than the size of the block in the next call to renderBlock().
* @param noteNumber the midi note number.
* @param velocity the normalized midi note velocity, in domain 0 to 1.
*
* @par Thread-safety constraints
* - @b RT: the function must be invoked from the Real-time thread
*/
void hdNoteOff(int delay, int noteNumber, float velocity) noexcept;

/**
* @brief Send a CC event to the synth
* @since 0.2.0
Expand Down Expand Up @@ -477,6 +513,24 @@ class SFIZZ_EXPORTED_API Sfizz
*/
void pitchWheel(int delay, int pitch) noexcept;

/**
* @brief Send a high-precision pitch bend event to the synth
*
* This command should be delay-ordered with all other midi-type events
* (notes, CCs, aftertouch and pitch-wheel), otherwise the behavior of the
* synth is undefined.
*
* @since 0.6.0
*
* @param delay the delay at which the event occurs; this should be lower
* than the size of the block in the next call to renderBlock().
* @param pitch the normalized pitch, in domain -1 to 1.
*
* @par Thread-safety constraints
* - @b RT: the function must be invoked from the Real-time thread
*/
void hdPitchWheel(int delay, float pitch) noexcept;

/**
* @brief Send an aftertouch event to the synth.
*
Expand All @@ -496,8 +550,26 @@ class SFIZZ_EXPORTED_API Sfizz
void aftertouch(int delay, uint8_t aftertouch) noexcept;

/**
* @brief Send a polyphonic aftertouch event to the synth. This feature is
* experimental and needs more testing in the internal engine.
* @brief Send a high-precision aftertouch event to the synth.
*
* This command should be delay-ordered with all other midi-type events
* (notes, CCs, aftertouch and pitch-wheel), otherwise the behavior of the
* synth is undefined.
*
* @since 0.6.0
*
* @param delay the delay at which the event occurs; this should be lower
* than the size of the block in the next call to renderBlock().
* @param aftertouch the normalized aftertouch value, in domain 0 to 1.
*
* @par Thread-safety constraints
* - @b RT: the function must be invoked from the Real-time thread
*/
void hdAftertouch(int delay, float aftertouch) noexcept;

/**
* @brief Send a polyphonic aftertouch event to the synth.
* This feature is experimental and needs more testing in the internal engine.
*
* This command should be delay-ordered with all other midi-type events
* (notes, CCs, aftertouch and pitch-wheel), otherwise the behavior of the
Expand All @@ -515,6 +587,26 @@ class SFIZZ_EXPORTED_API Sfizz
*/
void polyAftertouch(int delay, int noteNumber, uint8_t aftertouch) noexcept;

/**
* @brief Send a high-precision polyphonic aftertouch event to the synth.
* This feature is experimental and needs more testing in the internal engine.
*
* This command should be delay-ordered with all other midi-type events
* (notes, CCs, aftertouch and pitch-wheel), otherwise the behavior of the
* synth is undefined.
*
* @since 0.6.0
*
* @param delay the delay at which the event occurs; this should be lower
* than the size of the block in the next call to renderBlock().
* @param noteNumber the note number.
* @param aftertouch the normalized aftertouch value, in domain 0 to 1.
*
* @par Thread-safety constraints
* - @b RT: the function must be invoked from the Real-time thread
*/
void hdPolyAftertouch(int delay, int noteNumber, float aftertouch) noexcept;

/**
* @brief Send a tempo event to the synth.
*
Expand Down
Loading

0 comments on commit 5a4b1f5

Please sign in to comment.