Skip to content

Commit 190d690

Browse files
committed
More audio bindings tests
1 parent 8759506 commit 190d690

File tree

8 files changed

+1199
-32
lines changed

8 files changed

+1199
-32
lines changed

modules/yup_audio_basics/synthesisers/yup_Synthesiser.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ Synthesiser::~Synthesiser()
106106
}
107107

108108
//==============================================================================
109-
SynthesiserVoice* Synthesiser::getVoice (const int index) const
109+
SynthesiserVoice::Ptr Synthesiser::getVoice (const int index) const
110110
{
111111
const ScopedLock sl (lock);
112112
return voices[index];
@@ -118,7 +118,7 @@ void Synthesiser::clearVoices()
118118
voices.clear();
119119
}
120120

121-
SynthesiserVoice* Synthesiser::addVoice (SynthesiserVoice* const newVoice)
121+
SynthesiserVoice* Synthesiser::addVoice (const SynthesiserVoice::Ptr newVoice)
122122
{
123123
SynthesiserVoice* voice;
124124

modules/yup_audio_basics/synthesisers/yup_Synthesiser.h

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ class YUP_API SynthesiserSound : public ReferenceCountedObject
9999
100100
@tags{Audio}
101101
*/
102-
class YUP_API SynthesiserVoice
102+
class YUP_API SynthesiserVoice : public ReferenceCountedObject
103103
{
104104
public:
105105
//==============================================================================
@@ -261,6 +261,9 @@ class YUP_API SynthesiserVoice
261261
/** Returns true if this voice started playing its current note before the other voice did. */
262262
bool wasStartedBefore (const SynthesiserVoice& other) const noexcept;
263263

264+
/** The class is reference-counted, so this is a handy pointer class for it. */
265+
using Ptr = ReferenceCountedObjectPtr<SynthesiserVoice>;
266+
264267
protected:
265268
/** Resets the state of this voice after a sound has finished playing.
266269
@@ -337,17 +340,16 @@ class YUP_API Synthesiser
337340
int getNumVoices() const noexcept { return voices.size(); }
338341

339342
/** Returns one of the voices that have been added. */
340-
SynthesiserVoice* getVoice (int index) const;
343+
SynthesiserVoice::Ptr getVoice (int index) const;
341344

342345
/** Adds a new voice to the synth.
343346
344347
All the voices should be the same class of object and are treated equally.
345348
346-
The object passed in will be managed by the synthesiser, which will delete
347-
it later on when no longer needed. The caller should not retain a pointer to the
348-
voice.
349+
The object passed in is reference counted, so will be deleted when the
350+
synthesiser and all voices are no longer using it.
349351
*/
350-
SynthesiserVoice* addVoice (SynthesiserVoice* newVoice);
352+
SynthesiserVoice* addVoice (SynthesiserVoice::Ptr newVoice);
351353

352354
/** Deletes one of the voices. */
353355
void removeVoice (int index);
@@ -400,9 +402,7 @@ class YUP_API Synthesiser
400402
401403
The midiChannel parameter is the channel, between 1 and 16 inclusive.
402404
*/
403-
virtual void noteOn (int midiChannel,
404-
int midiNoteNumber,
405-
float velocity);
405+
virtual void noteOn (int midiChannel, int midiNoteNumber, float velocity);
406406

407407
/** Triggers a note-off event.
408408
@@ -416,10 +416,7 @@ class YUP_API Synthesiser
416416
417417
The midiChannel parameter is the channel, between 1 and 16 inclusive.
418418
*/
419-
virtual void noteOff (int midiChannel,
420-
int midiNoteNumber,
421-
float velocity,
422-
bool allowTailOff);
419+
virtual void noteOff (int midiChannel, int midiNoteNumber, float velocity, bool allowTailOff);
423420

424421
/** Turns off all notes.
425422
@@ -435,8 +432,7 @@ class YUP_API Synthesiser
435432
This method will be called automatically according to the midi data passed into
436433
renderNextBlock(), but may be called explicitly too.
437434
*/
438-
virtual void allNotesOff (int midiChannel,
439-
bool allowTailOff);
435+
virtual void allNotesOff (int midiChannel, bool allowTailOff);
440436

441437
/** Sends a pitch-wheel message to any active voices.
442438
@@ -449,8 +445,7 @@ class YUP_API Synthesiser
449445
@param midiChannel the midi channel, from 1 to 16 inclusive
450446
@param wheelValue the wheel position, from 0 to 0x3fff, as returned by MidiMessage::getPitchWheelValue()
451447
*/
452-
virtual void handlePitchWheel (int midiChannel,
453-
int wheelValue);
448+
virtual void handlePitchWheel (int midiChannel, int wheelValue);
454449

455450
/** Sends a midi controller message to any active voices.
456451
@@ -464,9 +459,7 @@ class YUP_API Synthesiser
464459
@param controllerNumber the midi controller type, as returned by MidiMessage::getControllerNumber()
465460
@param controllerValue the midi controller value, between 0 and 127, as returned by MidiMessage::getControllerValue()
466461
*/
467-
virtual void handleController (int midiChannel,
468-
int controllerNumber,
469-
int controllerValue);
462+
virtual void handleController (int midiChannel, int controllerNumber, int controllerValue);
470463

471464
/** Sends an aftertouch message.
472465
@@ -510,8 +503,7 @@ class YUP_API Synthesiser
510503
The base class implementation of this has no effect, but you may want to make your
511504
own synth react to program changes.
512505
*/
513-
virtual void handleProgramChange (int midiChannel,
514-
int programNumber);
506+
virtual void handleProgramChange (int midiChannel, int programNumber);
515507

516508
//==============================================================================
517509
/** Tells the synthesiser what the sample rate is for the audio it's being used to render.
@@ -575,7 +567,7 @@ class YUP_API Synthesiser
575567
/** This is used to control access to the rendering callback and the note trigger methods. */
576568
CriticalSection lock;
577569

578-
OwnedArray<SynthesiserVoice> voices;
570+
ReferenceCountedArray<SynthesiserVoice> voices;
579571
ReferenceCountedArray<SynthesiserSound> sounds;
580572

581573
/** The last pitch-wheel values for each midi channel. */

modules/yup_python/bindings/yup_YupAudioBasics_bindings.cpp

Lines changed: 106 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,97 @@ void registerYupAudioBasicsBindings (py::module_& m)
256256
return Decibels::toString (decibels, decimalPlaces, minusInfinityDb, shouldIncludeSuffix, customMinusInfinityString);
257257
}, "decibels"_a, "decimalPlaces"_a = 2, "minusInfinityDb"_a = -100.0f, "shouldIncludeSuffix"_a = true, "customMinusInfinityString"_a = StringRef());
258258

259+
// ============================================================================================ yup::MidiMessage
260+
261+
py::class_<MidiMessage> classMidiMessage (m, "MidiMessage");
262+
263+
classMidiMessage
264+
.def (py::init<>())
265+
.def (py::init<const MidiMessage&>())
266+
.def (py::init<const MidiMessage&, double>(), "other"_a, "newTimeStamp"_a)
267+
.def ("getRawData", [] (const MidiMessage& self) -> py::bytes
268+
{
269+
return py::bytes (reinterpret_cast<const char*> (self.getRawData()), self.getRawDataSize());
270+
})
271+
.def ("getRawDataSize", &MidiMessage::getRawDataSize)
272+
.def ("getDescription", &MidiMessage::getDescription)
273+
.def ("getTimeStamp", &MidiMessage::getTimeStamp)
274+
.def ("setTimeStamp", &MidiMessage::setTimeStamp)
275+
.def ("addToTimeStamp", &MidiMessage::addToTimeStamp)
276+
.def ("withTimeStamp", &MidiMessage::withTimeStamp)
277+
.def ("getChannel", &MidiMessage::getChannel)
278+
.def ("isForChannel", &MidiMessage::isForChannel)
279+
.def ("setChannel", &MidiMessage::setChannel)
280+
.def ("isSysEx", &MidiMessage::isSysEx)
281+
.def ("getSysExDataSize", &MidiMessage::getSysExDataSize)
282+
.def ("isNoteOn", &MidiMessage::isNoteOn, "returnTrueForVelocity0"_a = false)
283+
.def ("isNoteOff", &MidiMessage::isNoteOff, "returnTrueForNoteOnVelocity0"_a = true)
284+
.def ("isNoteOnOrOff", &MidiMessage::isNoteOnOrOff)
285+
.def ("getNoteNumber", &MidiMessage::getNoteNumber)
286+
.def ("setNoteNumber", &MidiMessage::setNoteNumber)
287+
.def ("getVelocity", &MidiMessage::getVelocity)
288+
.def ("getFloatVelocity", &MidiMessage::getFloatVelocity)
289+
.def ("setVelocity", &MidiMessage::setVelocity)
290+
.def ("multiplyVelocity", &MidiMessage::multiplyVelocity)
291+
.def ("isAftertouch", &MidiMessage::isAftertouch)
292+
.def ("getAfterTouchValue", &MidiMessage::getAfterTouchValue)
293+
.def ("isProgramChange", &MidiMessage::isProgramChange)
294+
.def ("getProgramChangeNumber", &MidiMessage::getProgramChangeNumber)
295+
.def ("isPitchWheel", &MidiMessage::isPitchWheel)
296+
.def ("getPitchWheelValue", &MidiMessage::getPitchWheelValue)
297+
.def ("isController", &MidiMessage::isController)
298+
.def ("getControllerNumber", &MidiMessage::getControllerNumber)
299+
.def ("getControllerValue", &MidiMessage::getControllerValue)
300+
.def ("isControllerOfType", &MidiMessage::isControllerOfType)
301+
.def ("isAllNotesOff", &MidiMessage::isAllNotesOff)
302+
.def ("isAllSoundOff", &MidiMessage::isAllSoundOff)
303+
.def ("isResetAllControllers", &MidiMessage::isResetAllControllers)
304+
.def_static ("noteOn", static_cast<MidiMessage (*)(int, int, float)> (&MidiMessage::noteOn), "channel"_a, "noteNumber"_a, "velocity"_a)
305+
.def_static ("noteOff", static_cast<MidiMessage (*)(int, int, float)> (&MidiMessage::noteOff), "channel"_a, "noteNumber"_a, "velocity"_a)
306+
.def_static ("noteOff", static_cast<MidiMessage (*)(int, int)> (&MidiMessage::noteOff), "channel"_a, "noteNumber"_a)
307+
.def_static ("programChange", &MidiMessage::programChange, "channel"_a, "programNumber"_a)
308+
.def_static ("pitchWheel", &MidiMessage::pitchWheel, "channel"_a, "position"_a)
309+
.def_static ("aftertouchChange", &MidiMessage::aftertouchChange, "channel"_a, "noteNumber"_a, "aftertouchValue"_a)
310+
.def_static ("channelPressureChange", &MidiMessage::channelPressureChange, "channel"_a, "pressure"_a)
311+
.def_static ("controllerEvent", &MidiMessage::controllerEvent, "channel"_a, "controllerType"_a, "value"_a)
312+
.def_static ("allNotesOff", &MidiMessage::allNotesOff, "channel"_a)
313+
.def_static ("allSoundOff", &MidiMessage::allSoundOff, "channel"_a)
314+
.def_static ("allControllersOff", &MidiMessage::allControllersOff, "channel"_a);
315+
316+
// ============================================================================================ yup::MidiMessageMetadata
317+
318+
py::class_<MidiMessageMetadata> classMidiMessageMetadata (m, "MidiMessageMetadata");
319+
320+
classMidiMessageMetadata
321+
.def (py::init<>())
322+
.def (py::init<const uint8*, int, int>())
323+
.def ("getMessage", &MidiMessageMetadata::getMessage)
324+
.def_readonly ("numBytes", &MidiMessageMetadata::numBytes)
325+
.def_readonly ("samplePosition", &MidiMessageMetadata::samplePosition);
326+
327+
// ============================================================================================ yup::MidiBuffer
328+
329+
py::class_<MidiBuffer> classMidiBuffer (m, "MidiBuffer");
330+
331+
classMidiBuffer
332+
.def (py::init<>())
333+
.def (py::init<const MidiMessage&>())
334+
.def ("clear", py::overload_cast<> (&MidiBuffer::clear))
335+
.def ("clear", py::overload_cast<int, int> (&MidiBuffer::clear))
336+
.def ("isEmpty", &MidiBuffer::isEmpty)
337+
.def ("getNumEvents", &MidiBuffer::getNumEvents)
338+
.def ("addEvent", py::overload_cast<const MidiMessage&, int> (&MidiBuffer::addEvent))
339+
.def ("addEvents", &MidiBuffer::addEvents)
340+
.def ("getFirstEventTime", &MidiBuffer::getFirstEventTime)
341+
.def ("getLastEventTime", &MidiBuffer::getLastEventTime)
342+
.def ("swapWith", &MidiBuffer::swapWith)
343+
.def ("ensureSize", &MidiBuffer::ensureSize)
344+
.def ("__iter__", [] (const MidiBuffer& self)
345+
{
346+
return py::make_iterator (self.begin(), self.end());
347+
}, py::keep_alive<0, 1>())
348+
.def ("__len__", &MidiBuffer::getNumEvents);
349+
259350
// ============================================================================================ yup::ADSR
260351

261352
py::class_<ADSR> classADSR (m, "ADSR");
@@ -382,7 +473,7 @@ void registerYupAudioBasicsBindings (py::module_& m)
382473

383474
// ============================================================================================ yup::PositionableAudioSource
384475

385-
py::class_<PositionableAudioSource, PyPositionableAudioSource<>, AudioSource> classPositionableAudioSource (m, "PositionableAudioSource");
476+
py::class_<PositionableAudioSource, PyPositionableAudioSource<>> classPositionableAudioSource (m, "PositionableAudioSource");
386477

387478
classPositionableAudioSource
388479
.def (py::init<>())
@@ -422,7 +513,7 @@ void registerYupAudioBasicsBindings (py::module_& m)
422513

423514
// ============================================================================================ yup::SynthesiserVoice
424515

425-
py::class_<SynthesiserVoice, PySynthesiserVoice> classSynthesiserVoice (m, "SynthesiserVoice");
516+
py::class_<SynthesiserVoice, PySynthesiserVoice, ReferenceCountedObjectPtr<SynthesiserVoice>> classSynthesiserVoice (m, "SynthesiserVoice");
426517

427518
classSynthesiserVoice
428519
.def (py::init<>())
@@ -443,11 +534,12 @@ void registerYupAudioBasicsBindings (py::module_& m)
443534

444535
// ============================================================================================ yup::Synthesiser
445536

446-
py::class_<Synthesiser> classSynthesiser (m, "Synthesiser");
537+
py::class_<Synthesiser, PySynthesiser> classSynthesiser (m, "Synthesiser");
447538

448539
classSynthesiser
449540
.def (py::init<>())
450541
.def ("clearVoices", &Synthesiser::clearVoices)
542+
.def ("getNumVoices", &Synthesiser::getNumVoices)
451543
.def ("getVoice", &Synthesiser::getVoice, py::return_value_policy::reference)
452544
.def ("addVoice", &Synthesiser::addVoice)
453545
.def ("removeVoice", &Synthesiser::removeVoice)
@@ -461,7 +553,17 @@ void registerYupAudioBasicsBindings (py::module_& m)
461553
.def ("setMinimumRenderingSubdivisionSize", &Synthesiser::setMinimumRenderingSubdivisionSize)
462554
.def ("setCurrentPlaybackSampleRate", &Synthesiser::setCurrentPlaybackSampleRate)
463555
.def ("renderNextBlock", py::overload_cast<AudioBuffer<float>&, const MidiBuffer&, int, int> (&Synthesiser::renderNextBlock), "outputAudio"_a, "inputMidi"_a, "startSample"_a, "numSamples"_a)
464-
.def ("allNotesOff", &Synthesiser::allNotesOff);
556+
.def ("noteOn", &Synthesiser::noteOn)
557+
.def ("noteOff", &Synthesiser::noteOff)
558+
.def ("allNotesOff", &Synthesiser::allNotesOff)
559+
.def ("handlePitchWheel", &Synthesiser::handlePitchWheel)
560+
.def ("handleController", &Synthesiser::handleController)
561+
.def ("handleAftertouch", &Synthesiser::handleAftertouch)
562+
.def ("handleChannelPressure", &Synthesiser::handleChannelPressure)
563+
.def ("handleSustainPedal", &Synthesiser::handleSustainPedal)
564+
.def ("handleSostenutoPedal", &Synthesiser::handleSostenutoPedal)
565+
.def ("handleSoftPedal", &Synthesiser::handleSoftPedal)
566+
.def ("handleProgramChange", &Synthesiser::handleProgramChange);
465567

466568
// ============================================================================================ yup::AudioPlayHead
467569

modules/yup_python/bindings/yup_YupAudioBasics_bindings.h

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,70 @@ struct PySynthesiserVoice : SynthesiserVoice
156156
}
157157
};
158158

159+
//==============================================================================
160+
struct PySynthesiser : Synthesiser
161+
{
162+
void noteOn (int midiChannel, int midiNoteNumber, float velocity) override
163+
{
164+
PYBIND11_OVERRIDE (void, Synthesiser, noteOn, midiChannel, midiNoteNumber, velocity);
165+
}
166+
167+
void noteOff (int midiChannel, int midiNoteNumber, float velocity, bool allowTailOff) override
168+
{
169+
PYBIND11_OVERRIDE (void, Synthesiser, noteOff, midiChannel, midiNoteNumber, velocity, allowTailOff);
170+
}
171+
172+
void allNotesOff (int midiChannel, bool allowTailOff) override
173+
{
174+
PYBIND11_OVERRIDE (void, Synthesiser, allNotesOff, midiChannel, allowTailOff);
175+
}
176+
177+
void handlePitchWheel (int midiChannel, int wheelValue) override
178+
{
179+
PYBIND11_OVERRIDE (void, Synthesiser, handlePitchWheel, midiChannel, wheelValue);
180+
}
181+
182+
void handleController (int midiChannel, int controllerNumber, int controllerValue) override
183+
{
184+
PYBIND11_OVERRIDE (void, Synthesiser, handleController, midiChannel, controllerNumber, controllerValue);
185+
}
186+
187+
void handleAftertouch (int midiChannel, int midiNoteNumber, int aftertouchValue) override
188+
{
189+
PYBIND11_OVERRIDE (void, Synthesiser, handleAftertouch, midiChannel, midiNoteNumber, aftertouchValue);
190+
}
191+
192+
void handleChannelPressure (int midiChannel, int channelPressureValue) override
193+
{
194+
PYBIND11_OVERRIDE (void, Synthesiser, handleChannelPressure, midiChannel, channelPressureValue);
195+
}
196+
197+
void handleSustainPedal (int midiChannel, bool isDown) override
198+
{
199+
PYBIND11_OVERRIDE (void, Synthesiser, handleSustainPedal, midiChannel, isDown);
200+
}
201+
202+
void handleSostenutoPedal (int midiChannel, bool isDown) override
203+
{
204+
PYBIND11_OVERRIDE (void, Synthesiser, handleSostenutoPedal, midiChannel, isDown);
205+
}
206+
207+
void handleSoftPedal (int midiChannel, bool isDown) override
208+
{
209+
PYBIND11_OVERRIDE (void, Synthesiser, handleSoftPedal, midiChannel, isDown);
210+
}
211+
212+
void handleProgramChange (int midiChannel, int programNumber) override
213+
{
214+
PYBIND11_OVERRIDE (void, Synthesiser, handleProgramChange, midiChannel, programNumber);
215+
}
216+
217+
void setCurrentPlaybackSampleRate (double sampleRate) override
218+
{
219+
PYBIND11_OVERRIDE (void, Synthesiser, setCurrentPlaybackSampleRate, sampleRate);
220+
}
221+
};
222+
159223
//==============================================================================
160224

161225
struct PyAudioPlayHeadPositionInfo : AudioPlayHead::PositionInfo

0 commit comments

Comments
 (0)