Deploy() Method
Table of contents
For this Stage of Deployment, You should modify the following file
Description
mention that they should have already added model to project (refer to Model Preparation section)
In this method, you receive the ModelOutput
struct received from the MDL
thread. Moreover, you have access to the parameters of the plugin. In here you should extract the notes to be played back as well as specify how the playback should occur.
Methods/Variables Available:
model_output
: TheModelOutput
struct received from theMDL
threadgui_params
: TheGuiParams
struct containing the parameters of the pluginrealtimePlaybackInfo
: TheRealtimePlaybackInfo
struct containing the realtime playback informationplaybackSequence
: ThePlaybackSequence
struct that you should fill in this method and send to thePPP
threadplaybackPolicy
: ThePlaybackPolicy
struct that you should fill in this method and send to thePPP
thread
This method is called whenever:
- A
ModelOutput
is received from theMDL
thread - Any of the parameters are changed
In order to notify the wrapper whether the PlaybackSequence
and/or PlaybackPolicy
structs have been filled, you should return a {bool
, bool
} pair. The first bool
indicates whether the PlaybackSequence
struct has been filled and the second bool
indicates whether the PlaybackPolicy
struct has been filled.
Code
std::pair<bool, bool> PlaybackPreparatorThread::deploy(bool new_model_output_received, bool did_any_gui_params_change) {
// =================================================================================
// === 1.a. ACCESSING GUI PARAMETERS
// Refer to:
// https://neuralmidifx.github.io/docs/v1_0_0/datatypes/GuiParams#accessing-the-ui-parameters
// =================================================================================
// =================================================================================
// ---------------------------------------------------------------------------------
// --- ExampleStarts ------ ExampleStarts ------ ExampleStarts ---- ExampleStarts --
// in this example, whenever the slider is moved, I resend a sequence of generations
// to the processor thread (NMP)
bool testFlag{false};
auto newPlaybackDelaySlider = gui_params.getValueFor("Generation Playback Delay");
if (PlaybackDelaySlider != newPlaybackDelaySlider) {
PrintMessage("PlaybackPreparatorThread: PlaybackDelaySlider changed from" +
std::to_string(PlaybackDelaySlider) + " to " + std::to_string(newPlaybackDelaySlider));
PlaybackDelaySlider = newPlaybackDelaySlider;
testFlag = true;
}
// --- ExampleEnds -------- ExampleEnds -------- ExampleEnds ------ ExampleEnds ----
// ---------------------------------------------------------------------------------
// =================================================================================
// === 1.b. ACCESSING REALTIME PLAYBACK INFORMATION
// Refer to:
// https://neuralmidifx.github.io/docs/v1_0_0/datatypes/RealtimePlaybackInfo#accessing-the-realtimeplaybackinfo
// =================================================================================
// =================================================================================
// === 2. ACCESSING INFORMATION (EVENTS) RECEIVED FROM HOST
// Refer to:
// https://neuralmidifx.github.io/docs/v1_0_0/datatypes/EventFromHost
// =================================================================================
// ---------------------------------------------------------------------------------
// --- ExampleStarts ------ ExampleStarts ------ ExampleStarts ---- ExampleStarts --
auto onsets = model_output.tensor1; // I'm not using this tensor below, just an e.g.
// ...
// --- ExampleEnds -------- ExampleEnds -------- ExampleEnds ------ ExampleEnds ----
// ---------------------------------------------------------------------------------
// =================================================================================
// === 3. Add Extracted Generations to Playback Sequence
// Refer to:
// https://neuralmidifx.github.io/docs/v1_0_0/datatypes/PlaybackSequence
// =================================================================================
// =================================================================================
// === 4. At least once, before sending generations,
// Specify the PlaybackPolicy, Time_unit, OverwritePolicy
// Refer to:
// https://neuralmidifx.github.io/docs/v1_0_0/datatypes/PlaybackPolicy
// =================================================================================
// -----------------------------------------------------------------------------------------
// ------ ExampleStarts ------ ExampleStarts ------ ExampleStarts ------ ExampleStarts -----
bool newPlaybackPolicyShouldBeSent{false};
bool newPlaybackSequenceGeneratedAndShouldBeSent{false};
if (testFlag) {
// 1. ---- Update Playback Policy -----
// Can be sent just once, || every time the policy changes
// playbackPolicy.SetPaybackPolicy_RelativeToNow(); // or
playbackPolicy.SetPlaybackPolicy_RelativeToAbsoluteZero(); // or
// playbackPolicy.SetPlaybackPolicy_RelativeToPlaybackStart(); // or
// playbackPolicy.SetTimeUnitIsSeconds(); // or
playbackPolicy.SetTimeUnitIsPPQ(); // or
// playbackPolicy.SetTimeUnitIsAudioSamples(); // or FIXME Timestamps near zero don't work well in loop mode
bool forceSendNoteOffsFirst{true};
// playbackPolicy.SetOverwritePolicy_DeleteAllEventsInPreviousStreamAndUseNewStream(forceSendNoteOffsFirst); // or
playbackPolicy.SetOverwritePolicy_DeleteAllEventsAfterNow(forceSendNoteOffsFirst); // or
// playbackPolicy.SetOverwritePolicy_KeepAllPreviousEvents(forceSendNoteOffsFirst); // or
// playbackPolicy.SetClearGenerationsAfterPauseStop(false); //
playbackPolicy.ActivateLooping(4);
// playbackPolicy.DisableLooping();
newPlaybackPolicyShouldBeSent = true;
// 2. ---- Update Playback Sequence -----
// clear the previous sequence || append depending on your requirements
playbackSequence.clear();
playbackSequence.clearStartingAt(0);
// I'm generating a single note to be played at timestamp 4 && delayed by the slider value
int channel{1};
int note = rand() % 64;
float velocity{0.3f};
double timestamp{0};
double duration{1};
// add noteOn Offs (time stamp shifted by the slider value)
playbackSequence.addNoteOn(channel, note, velocity,
timestamp + newPlaybackDelaySlider);
playbackSequence.addNoteOff(channel, note, velocity,
timestamp + newPlaybackDelaySlider + duration);
// or add a note with duration (an octave higher)
playbackSequence.addNoteWithDuration(channel, note+12, velocity,
timestamp + newPlaybackDelaySlider, duration);
newPlaybackSequenceGeneratedAndShouldBeSent = true;
}
// --- ExampleEnds -------- ExampleEnds -------- ExampleEnds ------ ExampleEnds ----
// ---------------------------------------------------------------------------------
// MUST Notify What Data Ready to be Sent
// If you don't want to send anything, just set both flags to false
// If you have a new playback policy, set the first flag to true
// If you have a new playback sequence, set the second flag to true
return {newPlaybackPolicyShouldBeSent, newPlaybackSequenceGeneratedAndShouldBeSent};
}