52 instrument.enableLegacyMode (pitchbendRange, channelRange);
67 instrument.setLegacyModeChannelRange (channelRange);
72 return instrument.getLegacyModePitchbendRange();
77 instrument.setLegacyModePitchbendRange (pitchbendRange);
83 instrument.setPressureTrackingMode (modeToUse);
88 instrument.setPitchbendTrackingMode (modeToUse);
103template <
typename floatType>
114 auto prevSample = startSample;
115 const auto endSample = startSample + numSamples;
119 const auto metadata = *it;
121 if (metadata.samplePosition >= endSample)
127 if (metadata.samplePosition >= prevSample + thisBlockSize)
130 prevSample = metadata.samplePosition;
136 if (prevSample < endSample)
167 class MpeSynthesiserBaseTests :
public UnitTest
169 enum class CallbackKind {
process, midi };
171 struct StartAndLength
180 bool operator== (
const StartAndLength& other)
const noexcept {
return tie() == other.tie(); }
181 bool operator!= (
const StartAndLength& other)
const noexcept {
return tie() != other.tie(); }
183 bool operator< (
const StartAndLength& other)
const noexcept {
return tie() < other.tie(); }
188 std::vector<StartAndLength> blocks;
189 std::vector<MidiMessage> messages;
190 std::vector<CallbackKind> order;
193 class MockSynthesiser :
public MPESynthesiserBase
198 void handleMidiEvent (
const MidiMessage&
m)
override
200 events.messages.emplace_back (
m);
201 events.order.emplace_back (CallbackKind::midi);
205 using MPESynthesiserBase::renderNextSubBlock;
207 void renderNextSubBlock (AudioBuffer<float>&,
209 int numSamples)
override
211 events.blocks.push_back ({ startSample, numSamples });
212 events.order.emplace_back (CallbackKind::process);
216 static MidiBuffer makeTestBuffer (
const int bufferLength)
220 for (
int i = 0;
i != bufferLength; ++
i)
227 MpeSynthesiserBaseTests()
230 void runTest()
override
232 const auto sumBlockLengths = [] (
const std::vector<StartAndLength>&
b)
234 const auto addBlock = [] (
int acc,
const StartAndLength&
info) {
return acc +
info.length; };
235 return std::accumulate (
b.begin(),
b.end(), 0, addBlock);
238 beginTest (
"Rendering sparse subblocks works");
240 const int blockSize = 512;
241 const auto midi = [&] { MidiBuffer
b;
b.addEvent ({}, blockSize / 2);
return b; }();
242 AudioBuffer<float> audio (1, blockSize);
244 const auto processEvents = [&] (
int start,
int length)
246 MockSynthesiser
synth;
247 synth.setMinimumRenderingSubdivisionSize (1,
false);
248 synth.setCurrentPlaybackSampleRate (44100);
254 const auto e = processEvents (0, blockSize);
255 expect (
e.blocks.size() == 2);
256 expect (
e.messages.size() == 1);
257 expect (std::is_sorted (
e.blocks.begin(),
e.blocks.end()));
258 expect (sumBlockLengths (
e.blocks) == blockSize);
259 expect (
e.order == std::vector<CallbackKind> { CallbackKind::process,
261 CallbackKind::process });
265 beginTest (
"Rendering subblocks processes only contained midi events");
267 const int blockSize = 512;
268 const auto midi = makeTestBuffer (blockSize);
269 AudioBuffer<float> audio (1, blockSize);
271 const auto processEvents = [&] (
int start,
int length)
273 MockSynthesiser
synth;
274 synth.setMinimumRenderingSubdivisionSize (1,
false);
275 synth.setCurrentPlaybackSampleRate (44100);
281 const int subBlockLength = 0;
282 const auto e = processEvents (0, subBlockLength);
283 expect (
e.blocks.size() == 0);
284 expect (
e.messages.size() == 0);
285 expect (std::is_sorted (
e.blocks.begin(),
e.blocks.end()));
286 expect (sumBlockLengths (
e.blocks) == subBlockLength);
290 const int subBlockLength = 0;
291 const auto e = processEvents (1, subBlockLength);
292 expect (
e.blocks.size() == 0);
293 expect (
e.messages.size() == 0);
294 expect (std::is_sorted (
e.blocks.begin(),
e.blocks.end()));
295 expect (sumBlockLengths (
e.blocks) == subBlockLength);
299 const int subBlockLength = 1;
300 const auto e = processEvents (1, subBlockLength);
301 expect (
e.blocks.size() == 1);
302 expect (
e.messages.size() == 1);
303 expect (std::is_sorted (
e.blocks.begin(),
e.blocks.end()));
304 expect (sumBlockLengths (
e.blocks) == subBlockLength);
305 expect (
e.order == std::vector<CallbackKind> { CallbackKind::midi,
306 CallbackKind::process });
310 const auto e = processEvents (0, blockSize);
311 expect (
e.blocks.size() == blockSize);
312 expect (
e.messages.size() == blockSize);
313 expect (std::is_sorted (
e.blocks.begin(),
e.blocks.end()));
314 expect (sumBlockLengths (
e.blocks) == blockSize);
315 expect (
e.order.front() == CallbackKind::midi);
319 beginTest (
"Subblocks respect their minimum size");
321 const int blockSize = 512;
322 const auto midi = makeTestBuffer (blockSize);
323 AudioBuffer<float> audio (1, blockSize);
325 const auto blockLengthsAreValid = [] (
const std::vector<StartAndLength>&
info,
int minLength,
bool strict)
327 if (
info.size() <= 1)
330 const auto lengthIsValid = [&] (
const StartAndLength&
s) {
return minLength <=
s.length; };
331 const auto begin = strict ?
info.begin() : std::next (
info.begin());
333 return std::all_of (begin, std::prev (
info.end()), lengthIsValid);
336 for (
auto strict : {
false,
true })
338 for (
auto subblockSize : { 1, 16, 32, 64, 1024 })
340 MockSynthesiser
synth;
341 synth.setMinimumRenderingSubdivisionSize (subblockSize, strict);
342 synth.setCurrentPlaybackSampleRate (44100);
343 synth.renderNextBlock (audio, midi, 0, blockSize);
345 const auto&
e =
synth.events;
346 expectWithinAbsoluteError (
float (
e.blocks.size()),
347 std::ceil ((
float) blockSize / (
float) subblockSize),
349 expect (
e.messages.size() == blockSize);
350 expect (std::is_sorted (
e.blocks.begin(),
e.blocks.end()));
351 expect (sumBlockLengths (
e.blocks) == blockSize);
352 expect (blockLengthsAreValid (
e.blocks, subblockSize, strict));
357 MockSynthesiser
synth;
358 synth.setMinimumRenderingSubdivisionSize (32,
true);
359 synth.setCurrentPlaybackSampleRate (44100);
360 synth.renderNextBlock (audio, MidiBuffer{}, 0, 16);
362 expect (
synth.events.blocks == std::vector<StartAndLength> { { 0, 16 } });
363 expect (
synth.events.order == std::vector<CallbackKind> { CallbackKind::process });
364 expect (
synth.events.messages.empty());
370 MpeSynthesiserBaseTests mpeSynthesiserBaseTests;
#define noexcept
Definition DistrhoDefines.h:72
SYNTH_T * synth
Definition LocalZynAddSubFx.cpp:47
void process(Alg_seq_ptr seq, bool tempo_flag, double tempo, bool flatten_flag)
Definition allegroconvert.cpp:42
Definition juce_AudioSampleBuffer.h:34
Definition juce_MPEInstrument.h:54
Definition juce_MPEZoneLayout.h:121
Definition juce_MidiBuffer.h:145
MidiBufferIterator findNextSamplePosition(int samplePosition) const noexcept
Definition juce_MidiBuffer.cpp:203
MidiBufferIterator cend() const noexcept
Definition juce_MidiBuffer.h:268
Definition juce_MidiMessage.h:35
Definition juce_Range.h:40
Definition juce_UnitTest.h:70
* e
Definition inflate.c:1404
int * l
Definition inflate.c:1579
unsigned * m
Definition inflate.c:1559
register unsigned i
Definition inflate.c:1575
unsigned s
Definition inflate.c:1555
virtual ASIOError start()=0
struct backing_store_struct * info
Definition jmemsys.h:183
Definition juce_UnitTestCategories.h:27
Definition carla_juce.cpp:31
CriticalSection::ScopedLockType ScopedLock
Definition juce_CriticalSection.h:186
RangedDirectoryIterator begin(const RangedDirectoryIterator &it)
Definition juce_RangedDirectoryIterator.h:179
png_uint_32 length
Definition png.c:2247
int minimumSubBlockSize
Definition juce_MPESynthesiserBase.h:210
void setPitchbendTrackingMode(TrackingMode modeToUse)
Definition juce_MPESynthesiserBase.cpp:86
virtual void handleMidiEvent(const MidiMessage &)
Definition juce_MPESynthesiserBase.cpp:97
bool isLegacyModeEnabled() const noexcept
Definition juce_MPESynthesiserBase.cpp:55
MPEZoneLayout getZoneLayout() const noexcept
Definition juce_MPESynthesiserBase.cpp:39
bool subBlockSubdivisionIsStrict
Definition juce_MPESynthesiserBase.h:211
MPEInstrument defaultInstrument
Definition juce_MPESynthesiserBase.h:206
void setZoneLayout(MPEZoneLayout newLayout)
Definition juce_MPESynthesiserBase.cpp:44
int getLegacyModePitchbendRange() const noexcept
Definition juce_MPESynthesiserBase.cpp:70
MPEInstrument::TrackingMode TrackingMode
Definition juce_MPESynthesiserBase.h:172
CriticalSection noteStateLock
Definition juce_MPESynthesiserBase.h:208
MPEInstrument & instrument
Definition juce_MPESynthesiserBase.h:202
void setLegacyModeChannelRange(Range< int > channelRange)
Definition juce_MPESynthesiserBase.cpp:65
void setLegacyModePitchbendRange(int pitchbendRange)
Definition juce_MPESynthesiserBase.cpp:75
void enableLegacyMode(int pitchbendRange=2, Range< int > channelRange=Range< int >(1, 17))
Definition juce_MPESynthesiserBase.cpp:50
void setTimbreTrackingMode(TrackingMode modeToUse)
Definition juce_MPESynthesiserBase.cpp:91
void setPressureTrackingMode(TrackingMode modeToUse)
Definition juce_MPESynthesiserBase.cpp:81
Range< int > getLegacyModeChannelRange() const noexcept
Definition juce_MPESynthesiserBase.cpp:60
virtual void setCurrentPlaybackSampleRate(double sampleRate)
Definition juce_MPESynthesiserBase.cpp:145
void renderNextBlock(AudioBuffer< floatType > &outputAudio, const MidiBuffer &inputMidi, int startSample, int numSamples)
Definition juce_MPESynthesiserBase.cpp:104
void setMinimumRenderingSubdivisionSize(int numSamples, bool shouldBeStrict=false) noexcept
Definition juce_MPESynthesiserBase.cpp:156
virtual void renderNextSubBlock(AudioBuffer< float > &outputAudio, int startSample, int numSamples)=0
MPESynthesiserBase()
Definition juce_MPESynthesiserBase.cpp:26
double sampleRate
Definition juce_MPESynthesiserBase.h:209
int result
Definition process.c:1455
#define const
Definition zconf.h:137