mirror of
https://codeberg.org/armin/monostep.git
synced 2026-09-01 04:10:46 +02:00
Prototype
This commit is contained in:
parent
c117906a7f
commit
4271fc34bb
14 changed files with 950 additions and 169 deletions
|
|
@ -27,7 +27,8 @@ static bool patternsEqual (const monostep::StepSequencer& a, const monostep::Ste
|
|||
const auto& sb = b.step (i);
|
||||
|
||||
if (sa.gate != sb.gate || sa.semitone != sb.semitone
|
||||
|| std::fabs (sa.cents - sb.cents) > 0.001f || sa.slide != sb.slide)
|
||||
|| std::fabs (sa.cents - sb.cents) > 0.001f
|
||||
|| sa.slide != sb.slide || sa.accent != sb.accent)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -63,7 +64,7 @@ static int testVst3Binary (const juce::File& pluginFile)
|
|||
// Part B: drive the actual processor source and render audio.
|
||||
static int testProcessorRendering()
|
||||
{
|
||||
MonoStepAudioProcessor processor;
|
||||
MonostepAudioProcessor processor;
|
||||
processor.prepareToPlay (44100.0, 512);
|
||||
|
||||
const int totalSamples = (int) (44100.0 * 8.0);
|
||||
|
|
@ -96,7 +97,7 @@ static int testProcessorRendering()
|
|||
}
|
||||
|
||||
// Without a MIDI note the sequencer must stay silent.
|
||||
MonoStepAudioProcessor idleProcessor;
|
||||
MonostepAudioProcessor idleProcessor;
|
||||
idleProcessor.prepareToPlay (44100.0, 512);
|
||||
|
||||
double idleSum = 0.0;
|
||||
|
|
@ -129,6 +130,7 @@ static int testProcessorRendering()
|
|||
processor.setStepNote (0, 7);
|
||||
processor.setStepCents (0, 42.0f);
|
||||
processor.setStepSlide (1, true);
|
||||
processor.setStepAccent (0, true);
|
||||
|
||||
if (std::fabs (processor.getSequencer().step (0).cents - 42.0f) > 0.001f)
|
||||
{
|
||||
|
|
@ -136,12 +138,97 @@ static int testProcessorRendering()
|
|||
return 1;
|
||||
}
|
||||
|
||||
// accent DSP: a uniform continuous pattern (all same note, gate held open)
|
||||
// so no per-note retrigger masks whether accent follows the step.
|
||||
*processor.getAPVTS().getRawParameterValue ("accent") = 1.0f;
|
||||
*processor.getAPVTS().getRawParameterValue ("seqGateLen") = 1.0f;
|
||||
|
||||
for (int i = 0; i < monostep::numSteps; ++i)
|
||||
{
|
||||
processor.setStepGate (i, true);
|
||||
processor.setStepNote (i, 0);
|
||||
processor.setStepSlide (i, false);
|
||||
}
|
||||
|
||||
const auto renderAccent = [&] (const std::function<bool (int)>& accented) -> double
|
||||
{
|
||||
for (int i = 0; i < monostep::numSteps; ++i)
|
||||
processor.setStepAccent (i, accented (i));
|
||||
|
||||
processor.reset();
|
||||
processor.prepareToPlay (44100.0, 512);
|
||||
|
||||
juce::AudioBuffer<float> accBlock (2, blockSize);
|
||||
juce::MidiBuffer accMidi;
|
||||
double sum = 0.0;
|
||||
|
||||
for (int b = 0; b < numBlocks; ++b)
|
||||
{
|
||||
accBlock.clear();
|
||||
accMidi.clear();
|
||||
|
||||
if (b == 0)
|
||||
accMidi.addEvent (juce::MidiMessage::noteOn (1, 60, 0.9f), 0);
|
||||
|
||||
processor.processBlock (accBlock, accMidi);
|
||||
|
||||
for (int c = 0; c < 2; ++c)
|
||||
for (int i = 0; i < blockSize; ++i)
|
||||
sum += (double) accBlock.getSample (c, i) * accBlock.getSample (c, i);
|
||||
}
|
||||
|
||||
return std::sqrt (sum / (double) (numBlocks * blockSize * 2));
|
||||
};
|
||||
|
||||
const double accRms = renderAccent ([] (int) { return true; });
|
||||
const double noAccRms = renderAccent ([] (int) { return false; });
|
||||
const double altRms = renderAccent ([] (int i) { return (i % 2) == 0; });
|
||||
|
||||
if (accRms < noAccRms * 1.05f)
|
||||
{
|
||||
std::cout << "FAILED: accent does not boost the step (acc=" << accRms
|
||||
<< " noacc=" << noAccRms << ")\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (altRms < noAccRms * 1.05f || altRms > accRms * 0.9f)
|
||||
{
|
||||
std::cout << "FAILED: accent does not track individual steps (all=" << accRms
|
||||
<< " alt=" << altRms << " noacc=" << noAccRms << ")\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::cout << "Accent boosts step volume OK (all=" << accRms
|
||||
<< " alternating=" << altRms << " none=" << noAccRms << ")\n";
|
||||
|
||||
// pattern shift rotates the steps
|
||||
processor.setStepAccent (0, true);
|
||||
processor.setStepNote (0, 7);
|
||||
processor.setStepNote (1, 3);
|
||||
processor.shiftPattern (1);
|
||||
|
||||
if (processor.getSequencer().step (1).semitone != 7)
|
||||
{
|
||||
std::cout << "FAILED: shiftPattern did not rotate steps\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
processor.shiftPattern (-1);
|
||||
|
||||
if (processor.getSequencer().step (0).semitone != 7 || ! processor.getSequencer().step (0).accent)
|
||||
{
|
||||
std::cout << "FAILED: shiftPattern did not rotate back\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::cout << "Pattern shift rotates steps OK\n";
|
||||
|
||||
// state round trip through a fresh instance
|
||||
juce::MemoryBlock state;
|
||||
processor.getStateInformation (state);
|
||||
std::cout << "State bytes: " << (int) state.getSize() << "\n";
|
||||
|
||||
MonoStepAudioProcessor processor2;
|
||||
MonostepAudioProcessor processor2;
|
||||
processor2.prepareToPlay (44100.0, 512);
|
||||
processor2.setStateInformation (state.getData(), (int) state.getSize());
|
||||
|
||||
|
|
@ -152,7 +239,8 @@ static int testProcessorRendering()
|
|||
std::cout << "step " << i << ": gate=" << a.gate << "/" << b.gate
|
||||
<< " note=" << a.semitone << "/" << b.semitone
|
||||
<< " cents=" << a.cents << "/" << b.cents
|
||||
<< " slide=" << a.slide << "/" << b.slide << "\n";
|
||||
<< " slide=" << a.slide << "/" << b.slide
|
||||
<< " accent=" << a.accent << "/" << b.accent << "\n";
|
||||
}
|
||||
|
||||
if (! patternsEqual (processor.getSequencer(), processor2.getSequencer()))
|
||||
|
|
@ -218,7 +306,7 @@ int main (int argc, char** argv)
|
|||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
std::cout << "Usage: MonoStepTestHost <plugin.vst3> [out.wav]\n";
|
||||
std::cout << "Usage: MonostepTestHost <plugin.vst3> [out.wav]\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue