From d0bf2d589de3596726b938d2f9c07ca938de655b Mon Sep 17 00:00:00 2001 From: Ge Wang Date: Tue, 9 Jul 2024 17:33:45 -0700 Subject: [PATCH] add release notes and additional comments; MIDI channel 0-based; new MidiOut.send(int,int,int) --- VERSIONS | 30 ++++++++++++++++++++++--- examples/midi/midiout.ck | 1 + examples/midi/midiout2.ck | 17 +++++++------- src/core/chuck_io.cpp | 45 ++++++++++++++++++++++++++------------ src/core/chuck_io.h | 1 + src/core/midiio_rtmidi.cpp | 19 +++++++++------- 6 files changed, 80 insertions(+), 33 deletions(-) diff --git a/VERSIONS b/VERSIONS index 85e3178a2..c15b4743e 100644 --- a/VERSIONS +++ b/VERSIONS @@ -7,7 +7,7 @@ ChucK VERSIONS log - (updated) chugin API version from 10.1 to 10.2 - (added) chugin API for callback on shutdown - (added) chugin API for setting array elements (thanks azaday) -- (added) overloaded constructors added (more to come) +- (added) overloaded constructors (more to come) ================== Envelope( dur durationToTarget ) Construct an Envelope with duration to reach target (assumed to be 1.0); @@ -33,14 +33,38 @@ ChucK VERSIONS log ================== - (added) new member functions ================== - fun dur Envelope.ramp( dur durationToTarget, float target ); + dur Envelope.ramp( dur durationToTarget, float target ); Over the given duration, ramp toward the specified target; returns the given duration. - fun dur Envelope.ramp( float secondsToTarget, float target ); + dur Envelope.ramp( float secondsToTarget, float target ); Over the given duration (in seconds), ramp toward the specified target; returns the given duration. ================== - (added) examples/basic/envelope2.ck -- to show Envelope.ramp() in action +- (added) new MIDI message voice message convenience functions (thanks @cviejo; + previously these are possible only through `MidiOut.send( MidiMsg msg )`: +================== + int MidiOut.send( int status, int data1, int data2 ); + Send out a MIDI message consisting of one status byte and two data bytes. + int channelPressure(int channel, int pressure) + Send out a channelPressure message. + int controlChange(int channel, int controller, int value) + Send out a controlChange message. + int noteOff(int channel, int note, int velocity) + Send out a noteOff message. + int noteOn(int channel, int note, int velocity) + Send out a noteOn message. + int pitchBend(int channel, int value) + Send out a pitchBend message. + int pitchBend(int channel, int lsb, int msb) + Send out a pitchBend message with fine and coarse values. + int polyPressure(int channel, int note, int pressure) + Send out a polyPressure message. + int programChange(int channel, int program) + Send out a programChange message. +================== +- (added) examples/midi/midiout2.ck -- demonstrates using the above channel + voice messages - (added) examples/deep/smb.ck -- a ChucK rendition of Super Mario Bros. original theme by Koji Kondo; (meticulously) modeled in ChucK by Wesley Burchell in 2017 diff --git a/examples/midi/midiout.ck b/examples/midi/midiout.ck index cc517056e..fc5dae64f 100644 --- a/examples/midi/midiout.ck +++ b/examples/midi/midiout.ck @@ -2,6 +2,7 @@ // name: midiout.ck // desc: example of sending MIDI messages // note: for a good explanation of how MIDI messages work, see after the code +// also see midiout2.ck for sending by common channel voice message //----------------------------------------------------------------------------- // instantiate a MIDI out object diff --git a/examples/midi/midiout2.ck b/examples/midi/midiout2.ck index 4a19bdaff..bc5c2ab46 100644 --- a/examples/midi/midiout2.ck +++ b/examples/midi/midiout2.ck @@ -1,6 +1,7 @@ //----------------------------------------------------------------------------- // name: midiout2.ck // desc: example of sending MIDI messages using MidiOut only +// requires: chuck-1.5.2.5 or higher | author: cviejo // note: for a good explanation of how MIDI messages work and sending raw midi // messages, see midiout.ck //----------------------------------------------------------------------------- @@ -16,34 +17,34 @@ if( !mout.open(0) ) me.exit(); while( true ) { <<< "sending note on message...", "" >>>; - mout.noteOn( 1, 60, 127 ); + mout.noteOn( 0, 60, 127 ); 1::second => now; <<< "sending note off message...", "" >>>; - mout.noteOff( 1, 60, 0 ); + mout.noteOff( 0, 60, 0 ); 1::second => now; <<< "sending control change message...", "" >>>; - mout.controlChange( 1, 14, 127 ); + mout.controlChange( 0, 14, 127 ); 1::second => now; <<< "sending program change message...", "" >>>; - mout.programChange( 1, 6 ); + mout.programChange( 0, 6 ); 1::second => now; <<< "sending polyphonic key pressure (aftertouch)...", "" >>>; - mout.polyPressure( 1, 60, 127 ); + mout.polyPressure( 0, 60, 127 ); 1::second => now; <<< "sending channel pressure (aftertouch)...", "" >>>; - mout.channelPressure( 1, 127 ); + mout.channelPressure( 0, 127 ); 1::second => now; <<< "sending pitch bend message...", "" >>>; - mout.pitchBend( 1, 96 ); // +50% or 1.00 semitone up + mout.pitchBend( 0, 96 ); // +50% or 1.00 semitone up 1::second => now; <<< "sending fine resolution pitch bend message...", "" >>>; - mout.pitchBend( 1, 50, 96 ); // +51% or 1.01 semitone up + mout.pitchBend( 0, 50, 96 ); // +51% or 1.01 semitone up 1::second => now; } diff --git a/src/core/chuck_io.cpp b/src/core/chuck_io.cpp index f6bb62ebc..0a35e01f6 100644 --- a/src/core/chuck_io.cpp +++ b/src/core/chuck_io.cpp @@ -825,7 +825,7 @@ t_CKBOOL init_class_Midi( Chuck_Env * env ) type_engine_import_class_end( env ); // doc string - doc = "Class for sending out Midi messages."; + doc = "Class for sending out MIDI messages. Note that channel numbers are 0-based."; // init base class if( !type_engine_import_class_begin( env, "MidiOut", "Object", env->global(), MidiOut_ctor, MidiOut_dtor, doc.c_str() ) ) @@ -864,13 +864,21 @@ t_CKBOOL init_class_Midi( Chuck_Env * env ) func->doc = "Set error printing (1 for on, 0 for off). On by default."; if( !type_engine_import_mfun( env, func ) ) goto error; - // add send() + // add send() | 1.5.2.5 (ge) added func = make_new_mfun( "int", "send", MidiOut_send ); + func->add_arg( "int", "status" ); + func->add_arg( "int", "data1" ); + func->add_arg( "int", "data2" ); + func->doc = "Send out a MIDI message consisting of one status byte and two data bytes."; + if( !type_engine_import_mfun( env, func ) ) goto error; + + // add send() + func = make_new_mfun( "int", "send", MidiOut_send_msg ); func->add_arg( "MidiMsg", "msg" ); - func->doc = "Send out a MidiMsg message."; + func->doc = "Send out a MIDI message using a MidiMsg."; if( !type_engine_import_mfun( env, func ) ) goto error; - // add noteOn() + // add noteOn() | 1.5.2.5 (cviejo) added func = make_new_mfun( "int", "noteOn", MidiOut_noteOn ); func->add_arg( "int", "channel" ); func->add_arg( "int", "note" ); @@ -878,7 +886,7 @@ t_CKBOOL init_class_Midi( Chuck_Env * env ) func->doc = "Send out a noteOn message."; if( !type_engine_import_mfun( env, func ) ) goto error; - // add noteOff() + // add noteOff() | 1.5.2.5 (cviejo) added func = make_new_mfun( "int", "noteOff", MidiOut_noteOff ); func->add_arg( "int", "channel" ); func->add_arg( "int", "note" ); @@ -886,7 +894,7 @@ t_CKBOOL init_class_Midi( Chuck_Env * env ) func->doc = "Send out a noteOff message."; if( !type_engine_import_mfun( env, func ) ) goto error; - // add controlChange() + // add controlChange() | 1.5.2.5 (cviejo) added func = make_new_mfun( "int", "controlChange", MidiOut_controlChange ); func->add_arg( "int", "channel" ); func->add_arg( "int", "controller" ); @@ -894,21 +902,21 @@ t_CKBOOL init_class_Midi( Chuck_Env * env ) func->doc = "Send out a controlChange message."; if( !type_engine_import_mfun( env, func ) ) goto error; - // add programChange() + // add programChange() | 1.5.2.5 (cviejo) added func = make_new_mfun( "int", "programChange", MidiOut_programChange ); func->add_arg( "int", "channel" ); func->add_arg( "int", "program" ); func->doc = "Send out a programChange message."; if( !type_engine_import_mfun( env, func ) ) goto error; - // add pitchBend() + // add pitchBend() | 1.5.2.5 (cviejo) added func = make_new_mfun( "int", "pitchBend", MidiOut_pitchBend ); func->add_arg( "int", "channel" ); func->add_arg( "int", "value" ); func->doc = "Send out a pitchBend message."; if( !type_engine_import_mfun( env, func ) ) goto error; - // add pitchBend() - fine resolution + // add pitchBend() - fine resolution | 1.5.2.5 (cviejo) added func = make_new_mfun( "int", "pitchBend", MidiOut_pitchBend_fine ); func->add_arg( "int", "channel" ); func->add_arg( "int", "lsb" ); @@ -916,7 +924,7 @@ t_CKBOOL init_class_Midi( Chuck_Env * env ) func->doc = "Send out a pitchBend message with fine and coarse values."; if( !type_engine_import_mfun( env, func ) ) goto error; - // add polyPressure() + // add polyPressure() | 1.5.2.5 (cviejo) added func = make_new_mfun( "int", "polyPressure", MidiOut_polyPressure ); func->add_arg( "int", "channel" ); func->add_arg( "int", "note" ); @@ -924,7 +932,7 @@ t_CKBOOL init_class_Midi( Chuck_Env * env ) func->doc = "Send out a polyPressure message."; if( !type_engine_import_mfun( env, func ) ) goto error; - // add channelPressure() + // add channelPressure() | 1.5.2.5 (cviejo) added func = make_new_mfun( "int", "channelPressure", MidiOut_channelPressure ); func->add_arg( "int", "channel" ); func->add_arg( "int", "pressure" ); @@ -933,6 +941,7 @@ t_CKBOOL init_class_Midi( Chuck_Env * env ) // add examples if( !type_engine_import_add_ex( env, "midi/midiout.ck" ) ) goto error; + if( !type_engine_import_add_ex( env, "midi/midiout2.ck" ) ) goto error; // add member variable MidiOut_offset_data = type_engine_import_mvar( env, "int", "@MidiOut_data", FALSE ); @@ -2478,7 +2487,16 @@ CK_DLL_MFUN( MidiOut_printerr ) mout->set_suppress( !print_or_not ); } -CK_DLL_MFUN( MidiOut_send ) +CK_DLL_MFUN( MidiOut_send ) // 1.5.2.5 | (ge) added +{ + MidiOut * mout = (MidiOut *)OBJ_MEMBER_INT(SELF, MidiOut_offset_data); + t_CKBYTE status = (t_CKBYTE)GET_NEXT_INT(ARGS); + t_CKBYTE data1 = (t_CKBYTE)GET_NEXT_INT(ARGS); + t_CKBYTE data2 = (t_CKBYTE)GET_NEXT_INT(ARGS); + RETURN->v_int = mout->send( status, data1, data2 ); +} + +CK_DLL_MFUN( MidiOut_send_msg ) { MidiOut * mout = (MidiOut *)OBJ_MEMBER_INT(SELF, MidiOut_offset_data); Chuck_Object * fake_msg = GET_CK_OBJECT(ARGS); @@ -2489,7 +2507,7 @@ CK_DLL_MFUN( MidiOut_send ) RETURN->v_int = mout->send( &the_msg ); } -CK_DLL_MFUN( MidiOut_noteOn ) +CK_DLL_MFUN( MidiOut_noteOn ) // 1.5.2.5 (cviejo) added { MidiOut * mout = (MidiOut *)OBJ_MEMBER_INT(SELF, MidiOut_offset_data); t_CKINT channel = GET_NEXT_INT(ARGS); @@ -2541,7 +2559,6 @@ CK_DLL_MFUN( MidiOut_pitchBend_fine ) RETURN->v_int = mout->pitchbendFine( channel, lsb, msb ); } - CK_DLL_MFUN( MidiOut_polyPressure ) { MidiOut * mout = (MidiOut *)OBJ_MEMBER_INT(SELF, MidiOut_offset_data); diff --git a/src/core/chuck_io.h b/src/core/chuck_io.h index 4c691e367..eafd2ba70 100644 --- a/src/core/chuck_io.h +++ b/src/core/chuck_io.h @@ -542,6 +542,7 @@ CK_DLL_MFUN( MidiOut_num ); CK_DLL_MFUN( MidiOut_name ); CK_DLL_MFUN( MidiOut_printerr ); CK_DLL_MFUN( MidiOut_send ); +CK_DLL_MFUN( MidiOut_send_msg ); CK_DLL_MFUN( MidiOut_noteOn ); CK_DLL_MFUN( MidiOut_noteOff ); CK_DLL_MFUN( MidiOut_controlChange ); diff --git a/src/core/midiio_rtmidi.cpp b/src/core/midiio_rtmidi.cpp index 2dcd1e685..0eb1c4b4e 100644 --- a/src/core/midiio_rtmidi.cpp +++ b/src/core/midiio_rtmidi.cpp @@ -102,7 +102,7 @@ t_CKUINT MidiOut::send( t_CKBYTE status ) // note: previously, this was sending a 3 byte message with data2 = 0, this was // causing a problem on macOS (only) where rtmidi was sending two program // change messages instead of one. This was fixed by sending a 2 byte -// message. +// message | 1.5.2.5 (cviejo) //----------------------------------------------------------------------------- t_CKUINT MidiOut::send( t_CKBYTE status, t_CKBYTE data1 ) { @@ -225,7 +225,7 @@ t_CKBOOL MidiOut::close( ) // desc: note on message //----------------------------------------------------------------------------- t_CKUINT MidiOut::noteon( t_CKUINT channel, t_CKUINT note, t_CKUINT velocity ) -{ return this->send( (t_CKBYTE)(MIDI_NOTEON + channel - 1), note, velocity ); } +{ return this->send( (t_CKBYTE)(MIDI_NOTEON + channel), note, velocity ); } @@ -235,7 +235,7 @@ t_CKUINT MidiOut::noteon( t_CKUINT channel, t_CKUINT note, t_CKUINT velocity ) // desc: note off message //----------------------------------------------------------------------------- t_CKUINT MidiOut::noteoff( t_CKUINT channel, t_CKUINT note, t_CKUINT velocity ) -{ return this->send( (t_CKBYTE)(MIDI_NOTEOFF + channel - 1), note, velocity ); } +{ return this->send( (t_CKBYTE)(MIDI_NOTEOFF + channel), note, velocity ); } @@ -245,7 +245,7 @@ t_CKUINT MidiOut::noteoff( t_CKUINT channel, t_CKUINT note, t_CKUINT velocity ) // desc: polypress message //----------------------------------------------------------------------------- t_CKUINT MidiOut::polypress( t_CKUINT channel, t_CKUINT note, t_CKUINT pressure ) -{ return this->send( (t_CKBYTE)(MIDI_POLYPRESS + channel - 1), note, pressure ); } +{ return this->send( (t_CKBYTE)(MIDI_POLYPRESS + channel), note, pressure ); } @@ -255,7 +255,7 @@ t_CKUINT MidiOut::polypress( t_CKUINT channel, t_CKUINT note, t_CKUINT pressure // desc: ctrl change message //----------------------------------------------------------------------------- t_CKUINT MidiOut::ctrlchange( t_CKUINT channel, t_CKUINT ctrl_num, t_CKUINT ctrl_val ) -{ return this->send( (t_CKBYTE)(MIDI_CTRLCHANGE + channel - 1), ctrl_num, ctrl_val ); } +{ return this->send( (t_CKBYTE)(MIDI_CTRLCHANGE + channel), ctrl_num, ctrl_val ); } @@ -265,7 +265,7 @@ t_CKUINT MidiOut::ctrlchange( t_CKUINT channel, t_CKUINT ctrl_num, t_CKUINT ctrl // desc: prog change message //----------------------------------------------------------------------------- t_CKUINT MidiOut::progchange( t_CKUINT channel, t_CKUINT patch ) -{ return this->send( (t_CKBYTE)(MIDI_PROGCHANGE + channel - 1), patch ); } +{ return this->send( (t_CKBYTE)(MIDI_PROGCHANGE + channel), patch ); } @@ -275,7 +275,8 @@ t_CKUINT MidiOut::progchange( t_CKUINT channel, t_CKUINT patch ) // desc: chan press //----------------------------------------------------------------------------- t_CKUINT MidiOut::chanpress( t_CKUINT channel, t_CKUINT pressure ) -{ return this->send( (t_CKBYTE)(MIDI_CHANPRESS + channel - 1), pressure ); } +{ return this->send( (t_CKBYTE)(MIDI_CHANPRESS + channel), pressure ); } + @@ -284,7 +285,8 @@ t_CKUINT MidiOut::chanpress( t_CKUINT channel, t_CKUINT pressure ) // desc: pitch bend //----------------------------------------------------------------------------- t_CKUINT MidiOut::pitchbendFine( t_CKUINT channel, t_CKUINT lsb, t_CKUINT msb) -{ return this->send( (t_CKBYTE)(MIDI_PITCHBEND + channel - 1), lsb, msb ); } +{ return this->send( (t_CKBYTE)(MIDI_PITCHBEND + channel), lsb, msb ); } + @@ -297,6 +299,7 @@ t_CKUINT MidiOut::pitchbend( t_CKUINT channel, t_CKUINT bend_val ) + //----------------------------------------------------------------------------- // name: allnotesoff() // desc: allnotesoff