From b1150f724ca804f43b025948364f55945bb76f9a Mon Sep 17 00:00:00 2001 From: cviejo <1179357+cviejo@users.noreply.github.com> Date: Thu, 3 Apr 2025 21:48:04 +0100 Subject: [PATCH 01/11] circular buffer with variable length --- src/core/midiio_rtmidi.cpp | 37 +++++--- src/core/midiio_rtmidi.h | 4 +- src/core/util_buffers.cpp | 173 +++++++++++++++++++++++++++++++------ src/core/util_buffers.h | 16 ++++ 4 files changed, 191 insertions(+), 39 deletions(-) diff --git a/src/core/midiio_rtmidi.cpp b/src/core/midiio_rtmidi.cpp index 262925aeb..89d5a2550 100644 --- a/src/core/midiio_rtmidi.cpp +++ b/src/core/midiio_rtmidi.cpp @@ -50,7 +50,7 @@ #define MIDI_BUFFER_SIZE 8192 std::vector MidiInManager::the_mins; -std::vector< std::map< Chuck_VM *, CBufferAdvance * > > MidiInManager::the_bufs; +std::vector< std::map< Chuck_VM *, CBufferAdvanceVariable * > > MidiInManager::the_bufs; std::vector MidiOutManager::the_mouts; std::map< Chuck_VM *, CBufferSimple * > MidiInManager::m_event_buffers; @@ -543,8 +543,8 @@ t_CKBOOL MidiInManager::add_vm( Chuck_VM * vm, t_CKINT device_num, } // allocate the buffer - CBufferAdvance * cbuf = new CBufferAdvance; - if( !cbuf->initialize( MIDI_BUFFER_SIZE, sizeof(MidiMsg), m_event_buffers[vm] ) ) + CBufferAdvanceVariable * cbuf = new CBufferAdvanceVariable; + if( !cbuf->initialize( MIDI_BUFFER_SIZE, m_event_buffers[vm] ) ) { if( !suppress_output ) EM_error2( 0, "MidiIn: couldn't allocate CBuffer for port %i...", device_num ); @@ -626,7 +626,24 @@ t_CKBOOL MidiIn::empty() t_CKUINT MidiIn::recv( MidiMsg * msg ) { if( !m_valid ) return FALSE; - return m_buffer->get( msg, 1, m_read_index ); + + t_CKUINT size = m_buffer->nextSize(m_read_index); + + if (size > 0) + { + t_CKBYTE tmp[size]; + + m_buffer->get(&tmp, m_read_index); + + for (t_CKUINT i = 0; i < size; i++) + { + if (i > 2) + break; + msg->data[i] = tmp[i]; + } + } + + return size; } @@ -651,21 +668,17 @@ void MidiInManager::cb_midi_input( double deltatime, std::vector EM_error2( 0, "MidiIn: couldn't find buffers for port %i...", device_num ); return; } - MidiMsg m; - if( nBytes >= 1 ) m.data[0] = msg->at(0); - if( nBytes >= 2 ) m.data[1] = msg->at(1); - if( nBytes >= 3 ) m.data[2] = msg->at(2); // put in all the buffers, make sure not active sensing - if( m.data[2] != 0xfe ) + if( msg->back() != 0xfe ) { - for( std::map< Chuck_VM *, CBufferAdvance * >::iterator it = + for( std::map< Chuck_VM *, CBufferAdvanceVariable * >::iterator it = the_bufs[device_num].begin(); it != the_bufs[device_num].end(); it++ ) { - CBufferAdvance * cbuf = it->second; + CBufferAdvanceVariable * cbuf = it->second; if( cbuf != NULL ) { - cbuf->put( &m, 1 ); + cbuf->put( msg->data(), msg->size() ); } } } diff --git a/src/core/midiio_rtmidi.h b/src/core/midiio_rtmidi.h index b487f2d59..d6a7fa216 100644 --- a/src/core/midiio_rtmidi.h +++ b/src/core/midiio_rtmidi.h @@ -156,7 +156,7 @@ class MidiIn : public Chuck_Event t_CKUINT recv( MidiMsg * msg ); public: - CBufferAdvance * m_buffer; + CBufferAdvanceVariable * m_buffer; t_CKUINT m_read_index; RtMidiIn * min; t_CKBOOL m_valid; @@ -193,7 +193,7 @@ class MidiInManager static t_CKBOOL add_vm( Chuck_VM * vm, t_CKINT device_num, t_CKBOOL suppress_output ); static std::vector the_mins; - static std::vector< std::map< Chuck_VM *, CBufferAdvance * > > the_bufs; + static std::vector< std::map< Chuck_VM *, CBufferAdvanceVariable * > > the_bufs; public: static std::map< Chuck_VM *, CBufferSimple * > m_event_buffers; diff --git a/src/core/util_buffers.cpp b/src/core/util_buffers.cpp index 789c3ee8a..8d1d1e2c4 100644 --- a/src/core/util_buffers.cpp +++ b/src/core/util_buffers.cpp @@ -300,18 +300,35 @@ void CBufferAdvance::put( void * data, UINT__ num_elem ) }*/ -BOOL__ CBufferAdvance::empty( UINT__ read_offset_index ) +BOOL__ CBufferAdvance::empty(UINT__ read_offset_index) { + // make sure index is valid + if (read_offset_index >= m_read_offsets.size()) + return TRUE; + if (m_read_offsets[read_offset_index].read_offset < 0) + return TRUE; + + SINT__ m_read_offset = m_read_offsets[read_offset_index].read_offset; + + // see if caught up + return m_read_offset == m_write_offset; +} + + +BOOL__ CBufferAdvance::isValidIndex(UINT__ read_offset_index) { - // make sure index is valid if( read_offset_index >= m_read_offsets.size() ) - return TRUE; - if( m_read_offsets[read_offset_index].read_offset < 0 ) - return TRUE; + return FALSE; SINT__ m_read_offset = m_read_offsets[read_offset_index].read_offset; - // see if caught up - return m_read_offset == m_write_offset; + if( m_read_offset < 0 ) + return FALSE; + + // read catch up with write + if( m_read_offset == m_write_offset ) + return FALSE; + + return TRUE; } @@ -325,15 +342,7 @@ UINT__ CBufferAdvance::get( void * data, UINT__ num_elem, UINT__ read_offset_ind m_mutex.acquire(); #endif - // make sure index is valid - if( read_offset_index >= m_read_offsets.size() ) - { - #ifndef __DISABLE_THREADS__ - m_mutex.release(); - #endif - return 0; - } - if( m_read_offsets[read_offset_index].read_offset < 0 ) + if (!this->isValidIndex(read_offset_index)) { #ifndef __DISABLE_THREADS__ m_mutex.release(); @@ -343,15 +352,6 @@ UINT__ CBufferAdvance::get( void * data, UINT__ num_elem, UINT__ read_offset_ind SINT__ m_read_offset = m_read_offsets[read_offset_index].read_offset; - // read catch up with write - if( m_read_offset == m_write_offset ) - { - #ifndef __DISABLE_THREADS__ - m_mutex.release(); - #endif - return 0; - } - // copy for( i = 0; i < num_elem; i++ ) { @@ -387,6 +387,129 @@ UINT__ CBufferAdvance::get( void * data, UINT__ num_elem, UINT__ read_offset_ind } +BOOL__ CBufferAdvanceVariable::initialize( UINT__ buffer_size, CBufferSimple * event_buffer ) +{ + CBufferAdvance::initialize( buffer_size, 1, event_buffer ); + m_buffer_size = buffer_size; + return true; +} + + +void CBufferAdvanceVariable::cleanup() +{ + CBufferAdvance::cleanup(); + m_buffer_size = 0; +} + + +void CBufferAdvanceVariable::put( void * data, UINT__ size ) +{ + UINT__ i; + BYTE__ * d = (BYTE__ *)data; + + // TODO: necessary? + #ifndef __DISABLE_THREADS__ + m_mutex.acquire(); + #endif + + // first store the size of the message + m_data[m_write_offset] = size; + + // copy the data + for( i = 0; i < size; i++ ) + { + m_write_offset++; + + if ( m_write_offset >= m_buffer_size ) + { + m_write_offset = 0; + } + m_data[m_write_offset] = d[i]; + } + + // move to the next write position + m_write_offset++; + + // possibility of expelling evil shreds + for( i = 0; i < m_read_offsets.size(); i++ ) + { + if( m_write_offset == m_read_offsets[i].read_offset ) + { + // inform shred with index i that it has lost its privileges? + // invalidate its read_offset + // m_read_offsets[i].read_offset = -1; + } + + if( m_read_offsets[i].event ) + m_read_offsets[i].event->queue_broadcast( m_event_buffer ); + } + + // TODO: necessary? + #ifndef __DISABLE_THREADS__ + m_mutex.release(); + #endif +} + + +UINT__ CBufferAdvanceVariable::nextSize( UINT__ read_offset_index ) +{ + SINT__ m_read_offset = m_read_offsets[read_offset_index].read_offset; + + if( m_read_offset == m_write_offset ) + { + return 0; + } + + // get the size of the next messages + return m_data[m_read_offset]; +} + + +UINT__ CBufferAdvanceVariable::get( void * data, UINT__ read_offset_index ) +{ + UINT__ i; + BYTE__ * d = (BYTE__ *)data; + + // TODO: necessary? + #ifndef __DISABLE_THREADS__ + m_mutex.acquire(); + #endif + + if (!this->isValidIndex(read_offset_index)) + { + #ifndef __DISABLE_THREADS__ + m_mutex.release(); + #endif + return 0; + } + + SINT__ m_read_offset = m_read_offsets[read_offset_index].read_offset; + UINT__ size = m_data[m_read_offset]; + + for( i = 0; i < size; i++ ) + { + m_read_offset++; + + if( m_read_offset >= m_buffer_size ) + { + m_read_offset = 0; + } + d[i] = m_data[m_read_offset]; + } + + m_read_offset++; + + // update read offset at given index + m_read_offsets[read_offset_index].read_offset = m_read_offset; + + // TODO: necessary? + #ifndef __DISABLE_THREADS__ + m_mutex.release(); + #endif + + // return number of elems + return size; +} //----------------------------------------------------------------------------- diff --git a/src/core/util_buffers.h b/src/core/util_buffers.h index 32374aa67..a73aaa622 100644 --- a/src/core/util_buffers.h +++ b/src/core/util_buffers.h @@ -83,6 +83,7 @@ class CBufferAdvance void resign( UINT__ read_offset_index ); protected: + BOOL__ isValidIndex( UINT__ read_offset_index ); BYTE__ * m_data; UINT__ m_data_width; //UINT__ m_read_offset; @@ -110,7 +111,22 @@ class CBufferAdvance CBufferSimple * m_event_buffer; }; +//----------------------------------------------------------------------------- +// name: class CBufferAdvanceVariable +// desc: circular buffer with variable length elements +//----------------------------------------------------------------------------- +class CBufferAdvanceVariable : public CBufferAdvance +{ +public: + BOOL__ initialize( UINT__ buffer_size, CBufferSimple * event_buffer = NULL ); + UINT__ get( void * data, UINT__ read_offset_index ); + UINT__ nextSize( UINT__ read_offset_index ); + void put( void * data, UINT__ size ); + void cleanup(); +protected: + UINT__ m_buffer_size; +}; //----------------------------------------------------------------------------- From 94de1be51687f507ba85102297db1336218a9b9c Mon Sep 17 00:00:00 2001 From: cviejo <1179357+cviejo@users.noreply.github.com> Date: Fri, 4 Apr 2025 01:23:09 +0100 Subject: [PATCH 02/11] MidiMsg.bytes --- src/core/chuck_io.cpp | 53 +++++++++++++++++++++++---- src/core/chuck_io.h | 3 ++ src/core/midiio_rtmidi.cpp | 74 ++++++++++++++++++++++++++++++-------- src/core/midiio_rtmidi.h | 4 ++- src/core/util_buffers.cpp | 8 ++--- 5 files changed, 115 insertions(+), 27 deletions(-) diff --git a/src/core/chuck_io.cpp b/src/core/chuck_io.cpp index 7df75e120..7bb93a51a 100644 --- a/src/core/chuck_io.cpp +++ b/src/core/chuck_io.cpp @@ -709,6 +709,7 @@ t_CKUINT MidiMsg_offset_data1 = 0; t_CKUINT MidiMsg_offset_data2 = 0; t_CKUINT MidiMsg_offset_data3 = 0; t_CKUINT MidiMsg_offset_when = 0; +t_CKUINT MidiMsg_offset_bytes = 0; static t_CKUINT MidiOut_offset_data = 0; //----------------------------------------------------------------------------- // name: init_class_Midi() @@ -725,7 +726,7 @@ t_CKBOOL init_class_Midi( Chuck_Env * env ) // init base class // TODO: ctor/dtor? if( !type_engine_import_class_begin( env, "MidiMsg", "Object", - env->global(), NULL, NULL, doc.c_str() ) ) + env->global(), MidiMsg_ctor, MidiMsg_dtor, doc.c_str() ) ) return FALSE; // add member variable @@ -743,6 +744,9 @@ t_CKBOOL init_class_Midi( Chuck_Env * env ) MidiMsg_offset_data3 = type_engine_import_mvar( env, "int", "data3", FALSE, doc.c_str() ); if( MidiMsg_offset_data3 == CK_INVALID_OFFSET ) goto error; + MidiMsg_offset_bytes = type_engine_import_mvar( env, "int[]", "bytes", FALSE ); + if( MidiMsg_offset_bytes == CK_INVALID_OFFSET ) goto error; + // add member variable doc = "Duration since the last MidiMsg (only valid for MidiFileIn)."; // Time when the MidiMsg occurred, relative to the start of the file (only valid for MidiFileIn)."; @@ -880,6 +884,13 @@ t_CKBOOL init_class_Midi( Chuck_Env * env ) func->doc = "Send out a MIDI message using a MidiMsg."; if( !type_engine_import_mfun( env, func ) ) goto error; + // add send() + func = make_new_mfun( "int", "send", MidiOut_send_bytes ); + func->add_arg( "int[]", "data" ); + func->doc = "Send out a MIDI message using a MidiMsg."; + if( !type_engine_import_mfun( env, func ) ) goto error; + + // add noteOn() | 1.5.2.5 (cviejo) added func = make_new_mfun( "int", "noteOn", MidiOut_noteOn ); func->add_arg( "int", "channel" ); @@ -2407,6 +2418,23 @@ CK_DLL_MFUN( cherr_writefloat ) #ifndef __DISABLE_MIDI__ +//----------------------------------------------------------------------------- +// MidiMsg API +//----------------------------------------------------------------------------- +CK_DLL_CTOR( MidiMsg_ctor ) +{ + Chuck_ArrayInt * bytes = new Chuck_ArrayInt( FALSE ); + initialize_object( bytes, VM->env()->ckt_array, SHRED, VM ); + CK_SAFE_ADD_REF( bytes ); + OBJ_MEMBER_INT(SELF, MidiMsg_offset_bytes) = (t_CKINT)bytes; +} + +CK_DLL_DTOR( MidiMsg_dtor ) +{ + // TODO: do we need this, or are these auto-released? + CK_SAFE_RELEASE( OBJ_MEMBER_OBJECT( SELF, MidiMsg_offset_bytes ) ); + OBJ_MEMBER_OBJECT( SELF, MidiMsg_offset_bytes ) = NULL; +} //----------------------------------------------------------------------------- // MidiIn API @@ -2472,13 +2500,17 @@ CK_DLL_MFUN( MidiIn_recv ) { MidiIn * min = (MidiIn *)OBJ_MEMBER_INT(SELF, MidiIn_offset_data); Chuck_Object * fake_msg = GET_CK_OBJECT(ARGS); - MidiMsg the_msg; - RETURN->v_int = min->recv( &the_msg ); + Chuck_ArrayInt * bytes = (Chuck_ArrayInt *)OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_bytes); + RETURN->v_int = min->recv( bytes ); if( RETURN->v_int ) { - OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data1) = the_msg.data[0]; - OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data2) = the_msg.data[1]; - OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data3) = the_msg.data[2]; + t_CKUINT byte; + bytes->get(0, &byte); + OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data1) = byte; + bytes->get(1, &byte); + OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data2) = byte; + bytes->get(2, &byte); + OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data3) = byte; } } @@ -2568,6 +2600,15 @@ CK_DLL_MFUN( MidiOut_send_msg ) RETURN->v_int = mout->send( &the_msg ); } + +CK_DLL_MFUN( MidiOut_send_bytes ) +{ + MidiOut * mout = (MidiOut *)OBJ_MEMBER_INT(SELF, MidiOut_offset_data); + Chuck_ArrayInt * arr = (Chuck_ArrayInt *) GET_NEXT_OBJECT(ARGS); + RETURN->v_int = mout->send( arr ); +} + + CK_DLL_MFUN( MidiOut_noteOn ) // 1.5.2.5 (cviejo) added { 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 13b04d83b..e7286a32b 100644 --- a/src/core/chuck_io.h +++ b/src/core/chuck_io.h @@ -476,11 +476,13 @@ CK_DLL_MFUN( cherr_writefloat ); // MidiMsg API //----------------------------------------------------------------------------- CK_DLL_CTOR( MidiMsg_ctor ); +CK_DLL_DTOR( MidiMsg_dtor ); extern t_CKUINT MidiMsg_offset_data1; extern t_CKUINT MidiMsg_offset_data2; extern t_CKUINT MidiMsg_offset_data3; extern t_CKUINT MidiMsg_offset_when; +extern t_CKUINT MidiMsg_offset_bytes; #ifndef __DISABLE_MIDI__ //----------------------------------------------------------------------------- @@ -544,6 +546,7 @@ 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_send_bytes ); 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 89d5a2550..2c9fcbbec 100644 --- a/src/core/midiio_rtmidi.cpp +++ b/src/core/midiio_rtmidi.cpp @@ -85,6 +85,32 @@ MidiOut::~MidiOut() +//----------------------------------------------------------------------------- +// name: send() +// desc: send an array of midi bytes +//----------------------------------------------------------------------------- +t_CKUINT MidiOut::send( Chuck_ArrayInt * arr ) +{ + if( !m_valid ) return 0; + + t_CKINT length = arr->size(); + t_CKUINT byte; + + m_msg.clear(); + + for( int i = 0; i < length; i++ ) + { + arr->get(i, &byte); + m_msg.push_back( byte ); + } + mout->sendMessage( &m_msg ); + + return length; +} + + + + //----------------------------------------------------------------------------- // name: send() // desc: send 1 byte midi message @@ -623,25 +649,46 @@ t_CKBOOL MidiIn::empty() // name: get() // desc: get message //----------------------------------------------------------------------------- -t_CKUINT MidiIn::recv( MidiMsg * msg ) +// t_CKUINT MidiIn::recv( MidiMsg * msg ) +// { +// if( !m_valid ) return FALSE; +// +// t_CKUINT size = m_buffer->nextSize(m_read_index); +// +// if (size == 0) +// return size; +// +// t_CKBYTE tmp[size]; +// +// m_buffer->get(&tmp, m_read_index); +// +// for (t_CKUINT i = 0; i < size; i++) +// { +// if (i > 2) +// break; +// msg->data[i] = tmp[i]; +// } +// +// return size; +// } + +t_CKUINT MidiIn::recv( Chuck_ArrayInt * arr ) { if( !m_valid ) return FALSE; t_CKUINT size = m_buffer->nextSize(m_read_index); - if (size > 0) - { - t_CKBYTE tmp[size]; + if (size == 0) + return size; - m_buffer->get(&tmp, m_read_index); + t_CKBYTE tmp[size]; - for (t_CKUINT i = 0; i < size; i++) - { - if (i > 2) - break; - msg->data[i] = tmp[i]; - } - } + m_buffer->get(&tmp, m_read_index); + + arr->clear(); + + for (t_CKUINT i = 0; i < size; i++) + arr->push_back(tmp[i]); return size; } @@ -676,10 +723,9 @@ void MidiInManager::cb_midi_input( double deltatime, std::vector the_bufs[device_num].begin(); it != the_bufs[device_num].end(); it++ ) { CBufferAdvanceVariable * cbuf = it->second; + if( cbuf != NULL ) - { cbuf->put( msg->data(), msg->size() ); - } } } } diff --git a/src/core/midiio_rtmidi.h b/src/core/midiio_rtmidi.h index d6a7fa216..d717d144c 100644 --- a/src/core/midiio_rtmidi.h +++ b/src/core/midiio_rtmidi.h @@ -101,9 +101,11 @@ class MidiOut { return m_suppress_output; } public: + t_CKUINT send( t_CKBYTE status ); t_CKUINT send( t_CKBYTE status, t_CKBYTE data1 ); t_CKUINT send( t_CKBYTE status, t_CKBYTE data1, t_CKBYTE data2 ); + t_CKUINT send( Chuck_ArrayInt * arr ); t_CKUINT send( const MidiMsg * msg ); public: @@ -153,7 +155,7 @@ class MidiIn : public Chuck_Event public: t_CKBOOL empty(); - t_CKUINT recv( MidiMsg * msg ); + t_CKUINT recv( Chuck_ArrayInt * msg ); public: CBufferAdvanceVariable * m_buffer; diff --git a/src/core/util_buffers.cpp b/src/core/util_buffers.cpp index 8d1d1e2c4..df7665be3 100644 --- a/src/core/util_buffers.cpp +++ b/src/core/util_buffers.cpp @@ -421,9 +421,8 @@ void CBufferAdvanceVariable::put( void * data, UINT__ size ) m_write_offset++; if ( m_write_offset >= m_buffer_size ) - { m_write_offset = 0; - } + m_data[m_write_offset] = d[i]; } @@ -456,9 +455,7 @@ UINT__ CBufferAdvanceVariable::nextSize( UINT__ read_offset_index ) SINT__ m_read_offset = m_read_offsets[read_offset_index].read_offset; if( m_read_offset == m_write_offset ) - { return 0; - } // get the size of the next messages return m_data[m_read_offset]; @@ -491,9 +488,8 @@ UINT__ CBufferAdvanceVariable::get( void * data, UINT__ read_offset_index ) m_read_offset++; if( m_read_offset >= m_buffer_size ) - { m_read_offset = 0; - } + d[i] = m_data[m_read_offset]; } From 0e67002ca2fee2c1051314493e27d6baf9e32d45 Mon Sep 17 00:00:00 2001 From: cviejo <1179357+cviejo@users.noreply.github.com> Date: Fri, 4 Apr 2025 01:33:00 +0100 Subject: [PATCH 03/11] formatting --- src/core/util_buffers.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/core/util_buffers.cpp b/src/core/util_buffers.cpp index df7665be3..890669962 100644 --- a/src/core/util_buffers.cpp +++ b/src/core/util_buffers.cpp @@ -300,17 +300,18 @@ void CBufferAdvance::put( void * data, UINT__ num_elem ) }*/ -BOOL__ CBufferAdvance::empty(UINT__ read_offset_index) { - // make sure index is valid - if (read_offset_index >= m_read_offsets.size()) - return TRUE; - if (m_read_offsets[read_offset_index].read_offset < 0) - return TRUE; +BOOL__ CBufferAdvance::empty(UINT__ read_offset_index) +{ + // make sure index is valid + if( read_offset_index >= m_read_offsets.size() ) + return TRUE; + if( m_read_offsets[read_offset_index].read_offset < 0 ) + return TRUE; - SINT__ m_read_offset = m_read_offsets[read_offset_index].read_offset; + SINT__ m_read_offset = m_read_offsets[read_offset_index].read_offset; - // see if caught up - return m_read_offset == m_write_offset; + // see if caught up + return m_read_offset == m_write_offset; } From 8fdf76ed7dcf830a712f469773a59d68ce242399 Mon Sep 17 00:00:00 2001 From: cviejo <1179357+cviejo@users.noreply.github.com> Date: Fri, 4 Apr 2025 11:42:18 +0100 Subject: [PATCH 04/11] added MidiIn.recv(int[] bytes) --- src/core/chuck_io.cpp | 40 +++++++++++++++++++++++++++++++++------- src/core/chuck_io.h | 1 + 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/core/chuck_io.cpp b/src/core/chuck_io.cpp index 7bb93a51a..4e8d1ecb1 100644 --- a/src/core/chuck_io.cpp +++ b/src/core/chuck_io.cpp @@ -811,6 +811,14 @@ t_CKBOOL init_class_Midi( Chuck_Env * env ) func->doc = "Return into the MidiMsg argument the next message in the queue from the device. Return 0 if the queue is empty or 1 if a message was in the queue and returned in the argument."; if( !type_engine_import_mfun( env, func ) ) goto error; + + // add recv() + func = make_new_mfun( "int", "recv", MidiIn_recv_bytes ); + func->add_arg( "int[]", "bytes" ); + func->doc = "Return into the MidiMsg argument the next message in the queue from the device. Return 0 if the queue is empty or 1 if a message was in the queue and returned in the argument."; + if( !type_engine_import_mfun( env, func ) ) goto error; + + // add can_wait() func = make_new_mfun( "int", "can_wait", MidiIn_can_wait ); func->doc = "(internal) used by virtual machine for synthronization."; @@ -2504,16 +2512,34 @@ CK_DLL_MFUN( MidiIn_recv ) RETURN->v_int = min->recv( bytes ); if( RETURN->v_int ) { - t_CKUINT byte; - bytes->get(0, &byte); - OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data1) = byte; - bytes->get(1, &byte); - OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data2) = byte; - bytes->get(2, &byte); - OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data3) = byte; + OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data1) = bytes->m_vector[0]; + OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data2) = bytes->m_vector[1]; + OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data3) = bytes->m_vector[2]; } } +CK_DLL_MFUN( MidiIn_recv_bytes ) +{ + MidiIn * min = (MidiIn *)OBJ_MEMBER_INT(SELF, MidiIn_offset_data); + Chuck_ArrayInt * bytes = (Chuck_ArrayInt *)GET_CK_OBJECT(ARGS); + + if( bytes == NULL ) + { + // assing a new array to the pointer + bytes = new Chuck_ArrayInt( FALSE ); + initialize_object( bytes, SHRED->vm_ref->env()->ckt_array, SHRED, VM ); + } + + RETURN->v_int = min->recv( bytes ); + // Chuck_Object * fake_msg = GET_CK_OBJECT(ARGS); + // Chuck_ArrayInt * bytes = (Chuck_ArrayInt *)OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_bytes); + // if( RETURN->v_int ) + // { + // OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data1) = bytes->m_vector[0]; + // OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data2) = bytes->m_vector[1]; + // OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data3) = bytes->m_vector[2]; + // } +} CK_DLL_MFUN( MidiIn_can_wait ) { diff --git a/src/core/chuck_io.h b/src/core/chuck_io.h index e7286a32b..e3662660a 100644 --- a/src/core/chuck_io.h +++ b/src/core/chuck_io.h @@ -529,6 +529,7 @@ CK_DLL_MFUN( MidiIn_num ); CK_DLL_MFUN( MidiIn_name ); CK_DLL_MFUN( MidiIn_printerr ); CK_DLL_MFUN( MidiIn_recv ); +CK_DLL_MFUN( MidiIn_recv_bytes ); CK_DLL_MFUN( MidiIn_can_wait ); From 035338a89340611e7cae196ea56ff49bacbbafbe Mon Sep 17 00:00:00 2001 From: cviejo <1179357+cviejo@users.noreply.github.com> Date: Fri, 11 Apr 2025 19:26:10 +0100 Subject: [PATCH 05/11] MidiIn_recv_bytes handle NULL --- src/core/chuck_io.cpp | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/src/core/chuck_io.cpp b/src/core/chuck_io.cpp index 4e8d1ecb1..656921038 100644 --- a/src/core/chuck_io.cpp +++ b/src/core/chuck_io.cpp @@ -2521,24 +2521,13 @@ CK_DLL_MFUN( MidiIn_recv ) CK_DLL_MFUN( MidiIn_recv_bytes ) { MidiIn * min = (MidiIn *)OBJ_MEMBER_INT(SELF, MidiIn_offset_data); - Chuck_ArrayInt * bytes = (Chuck_ArrayInt *)GET_CK_OBJECT(ARGS); - - if( bytes == NULL ) - { - // assing a new array to the pointer - bytes = new Chuck_ArrayInt( FALSE ); - initialize_object( bytes, SHRED->vm_ref->env()->ckt_array, SHRED, VM ); + Chuck_ArrayInt * bytes = (Chuck_ArrayInt *)GET_NEXT_OBJECT(ARGS); + if (bytes == NULL) { + RETURN->v_int = 0; + } + else { + RETURN->v_int = min->recv( bytes ); } - - RETURN->v_int = min->recv( bytes ); - // Chuck_Object * fake_msg = GET_CK_OBJECT(ARGS); - // Chuck_ArrayInt * bytes = (Chuck_ArrayInt *)OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_bytes); - // if( RETURN->v_int ) - // { - // OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data1) = bytes->m_vector[0]; - // OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data2) = bytes->m_vector[1]; - // OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data3) = bytes->m_vector[2]; - // } } CK_DLL_MFUN( MidiIn_can_wait ) From db40f12866574435b5929d70a24f63f0f83ea953 Mon Sep 17 00:00:00 2001 From: cviejo <1179357+cviejo@users.noreply.github.com> Date: Sun, 4 May 2025 21:23:58 +0200 Subject: [PATCH 06/11] removed MidiMsg.bytes --- src/core/chuck_io.cpp | 56 ++++++++++++++++++-------------------- src/core/chuck_io.h | 2 -- src/core/midiio_rtmidi.cpp | 56 ++++++++++++++++++++++---------------- src/core/midiio_rtmidi.h | 1 + src/core/util_buffers.cpp | 14 +++------- src/core/util_buffers.h | 5 ++-- 6 files changed, 67 insertions(+), 67 deletions(-) diff --git a/src/core/chuck_io.cpp b/src/core/chuck_io.cpp index 656921038..5927cc280 100644 --- a/src/core/chuck_io.cpp +++ b/src/core/chuck_io.cpp @@ -709,7 +709,6 @@ t_CKUINT MidiMsg_offset_data1 = 0; t_CKUINT MidiMsg_offset_data2 = 0; t_CKUINT MidiMsg_offset_data3 = 0; t_CKUINT MidiMsg_offset_when = 0; -t_CKUINT MidiMsg_offset_bytes = 0; static t_CKUINT MidiOut_offset_data = 0; //----------------------------------------------------------------------------- // name: init_class_Midi() @@ -726,7 +725,7 @@ t_CKBOOL init_class_Midi( Chuck_Env * env ) // init base class // TODO: ctor/dtor? if( !type_engine_import_class_begin( env, "MidiMsg", "Object", - env->global(), MidiMsg_ctor, MidiMsg_dtor, doc.c_str() ) ) + env->global(), NULL, NULL, doc.c_str() ) ) return FALSE; // add member variable @@ -744,9 +743,6 @@ t_CKBOOL init_class_Midi( Chuck_Env * env ) MidiMsg_offset_data3 = type_engine_import_mvar( env, "int", "data3", FALSE, doc.c_str() ); if( MidiMsg_offset_data3 == CK_INVALID_OFFSET ) goto error; - MidiMsg_offset_bytes = type_engine_import_mvar( env, "int[]", "bytes", FALSE ); - if( MidiMsg_offset_bytes == CK_INVALID_OFFSET ) goto error; - // add member variable doc = "Duration since the last MidiMsg (only valid for MidiFileIn)."; // Time when the MidiMsg occurred, relative to the start of the file (only valid for MidiFileIn)."; @@ -2426,23 +2422,6 @@ CK_DLL_MFUN( cherr_writefloat ) #ifndef __DISABLE_MIDI__ -//----------------------------------------------------------------------------- -// MidiMsg API -//----------------------------------------------------------------------------- -CK_DLL_CTOR( MidiMsg_ctor ) -{ - Chuck_ArrayInt * bytes = new Chuck_ArrayInt( FALSE ); - initialize_object( bytes, VM->env()->ckt_array, SHRED, VM ); - CK_SAFE_ADD_REF( bytes ); - OBJ_MEMBER_INT(SELF, MidiMsg_offset_bytes) = (t_CKINT)bytes; -} - -CK_DLL_DTOR( MidiMsg_dtor ) -{ - // TODO: do we need this, or are these auto-released? - CK_SAFE_RELEASE( OBJ_MEMBER_OBJECT( SELF, MidiMsg_offset_bytes ) ); - OBJ_MEMBER_OBJECT( SELF, MidiMsg_offset_bytes ) = NULL; -} //----------------------------------------------------------------------------- // MidiIn API @@ -2508,15 +2487,34 @@ CK_DLL_MFUN( MidiIn_recv ) { MidiIn * min = (MidiIn *)OBJ_MEMBER_INT(SELF, MidiIn_offset_data); Chuck_Object * fake_msg = GET_CK_OBJECT(ARGS); - Chuck_ArrayInt * bytes = (Chuck_ArrayInt *)OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_bytes); - RETURN->v_int = min->recv( bytes ); + Chuck_ArrayInt bytes(false, 3); + RETURN->v_int = min->recv( &bytes ); if( RETURN->v_int ) { - OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data1) = bytes->m_vector[0]; - OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data2) = bytes->m_vector[1]; - OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data3) = bytes->m_vector[2]; - } -} + t_CKUINT val; + + bytes.get(0, &val); + OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data1) = val; + bytes.get(1, &val); + OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data2) = val; + bytes.get(2, &val); + OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data3) = val; + } +} + +// CK_DLL_MFUN( MidiIn_recv ) +// { +// MidiIn * min = (MidiIn *)OBJ_MEMBER_INT(SELF, MidiIn_offset_data); +// Chuck_Object * fake_msg = GET_CK_OBJECT(ARGS); +// MidiMsg the_msg; +// RETURN->v_int = min->recv( &the_msg ); +// if( RETURN->v_int ) +// { +// OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data1) = the_msg.data[0]; +// OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data2) = the_msg.data[1]; +// OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data3) = the_msg.data[2]; +// } +// } CK_DLL_MFUN( MidiIn_recv_bytes ) { diff --git a/src/core/chuck_io.h b/src/core/chuck_io.h index e3662660a..4e90c6736 100644 --- a/src/core/chuck_io.h +++ b/src/core/chuck_io.h @@ -476,13 +476,11 @@ CK_DLL_MFUN( cherr_writefloat ); // MidiMsg API //----------------------------------------------------------------------------- CK_DLL_CTOR( MidiMsg_ctor ); -CK_DLL_DTOR( MidiMsg_dtor ); extern t_CKUINT MidiMsg_offset_data1; extern t_CKUINT MidiMsg_offset_data2; extern t_CKUINT MidiMsg_offset_data3; extern t_CKUINT MidiMsg_offset_when; -extern t_CKUINT MidiMsg_offset_bytes; #ifndef __DISABLE_MIDI__ //----------------------------------------------------------------------------- diff --git a/src/core/midiio_rtmidi.cpp b/src/core/midiio_rtmidi.cpp index 2c9fcbbec..f2b4de284 100644 --- a/src/core/midiio_rtmidi.cpp +++ b/src/core/midiio_rtmidi.cpp @@ -648,38 +648,44 @@ t_CKBOOL MidiIn::empty() //----------------------------------------------------------------------------- // name: get() // desc: get message -//----------------------------------------------------------------------------- -// t_CKUINT MidiIn::recv( MidiMsg * msg ) -// { -// if( !m_valid ) return FALSE; -// -// t_CKUINT size = m_buffer->nextSize(m_read_index); -// -// if (size == 0) -// return size; -// -// t_CKBYTE tmp[size]; -// -// m_buffer->get(&tmp, m_read_index); -// -// for (t_CKUINT i = 0; i < size; i++) -// { -// if (i > 2) -// break; -// msg->data[i] = tmp[i]; -// } -// -// return size; -// } +// ----------------------------------------------------------------------------- +t_CKUINT MidiIn::recv( MidiMsg * msg ) +{ + if( !m_valid ) return FALSE; + t_CKUINT size = m_buffer->getNextSize(m_read_index); + if (size != 0) + { + return size; + } + + t_CKBYTE tmp[size]; + + std::fill(tmp, tmp + size, 0); + + m_buffer->get(&tmp, m_read_index); + + for (t_CKUINT i = 0; i < size && i < 3; i++) + { + // if (i > 2) + // { + // break; + // } + msg->data[i] = tmp[i]; + } + + return size; +} t_CKUINT MidiIn::recv( Chuck_ArrayInt * arr ) { if( !m_valid ) return FALSE; - t_CKUINT size = m_buffer->nextSize(m_read_index); + t_CKUINT size = m_buffer->getNextSize(m_read_index); if (size == 0) + { return size; + } t_CKBYTE tmp[size]; @@ -688,7 +694,9 @@ t_CKUINT MidiIn::recv( Chuck_ArrayInt * arr ) arr->clear(); for (t_CKUINT i = 0; i < size; i++) + { arr->push_back(tmp[i]); + } return size; } diff --git a/src/core/midiio_rtmidi.h b/src/core/midiio_rtmidi.h index d717d144c..1f286a4a0 100644 --- a/src/core/midiio_rtmidi.h +++ b/src/core/midiio_rtmidi.h @@ -155,6 +155,7 @@ class MidiIn : public Chuck_Event public: t_CKBOOL empty(); + t_CKUINT recv( MidiMsg * msg ); t_CKUINT recv( Chuck_ArrayInt * msg ); public: diff --git a/src/core/util_buffers.cpp b/src/core/util_buffers.cpp index 890669962..94eb3c97c 100644 --- a/src/core/util_buffers.cpp +++ b/src/core/util_buffers.cpp @@ -413,7 +413,7 @@ void CBufferAdvanceVariable::put( void * data, UINT__ size ) m_mutex.acquire(); #endif - // first store the size of the message + // store the size of the message m_data[m_write_offset] = size; // copy the data @@ -433,13 +433,6 @@ void CBufferAdvanceVariable::put( void * data, UINT__ size ) // possibility of expelling evil shreds for( i = 0; i < m_read_offsets.size(); i++ ) { - if( m_write_offset == m_read_offsets[i].read_offset ) - { - // inform shred with index i that it has lost its privileges? - // invalidate its read_offset - // m_read_offsets[i].read_offset = -1; - } - if( m_read_offsets[i].event ) m_read_offsets[i].event->queue_broadcast( m_event_buffer ); } @@ -451,14 +444,15 @@ void CBufferAdvanceVariable::put( void * data, UINT__ size ) } -UINT__ CBufferAdvanceVariable::nextSize( UINT__ read_offset_index ) +UINT__ CBufferAdvanceVariable::getNextSize( UINT__ read_offset_index ) { SINT__ m_read_offset = m_read_offsets[read_offset_index].read_offset; if( m_read_offset == m_write_offset ) + { return 0; + } - // get the size of the next messages return m_data[m_read_offset]; } diff --git a/src/core/util_buffers.h b/src/core/util_buffers.h index a73aaa622..3a3d27c70 100644 --- a/src/core/util_buffers.h +++ b/src/core/util_buffers.h @@ -113,14 +113,15 @@ class CBufferAdvance //----------------------------------------------------------------------------- // name: class CBufferAdvanceVariable -// desc: circular buffer with variable length elements +// desc: circular buffer with variable length elements - first byte of each +// element is the size of the element //----------------------------------------------------------------------------- class CBufferAdvanceVariable : public CBufferAdvance { public: BOOL__ initialize( UINT__ buffer_size, CBufferSimple * event_buffer = NULL ); + UINT__ getNextSize( UINT__ read_offset_index ); UINT__ get( void * data, UINT__ read_offset_index ); - UINT__ nextSize( UINT__ read_offset_index ); void put( void * data, UINT__ size ); void cleanup(); From 35751b0f2e378aa05951e99ed02d0fbf0cf9e1c7 Mon Sep 17 00:00:00 2001 From: cviejo <1179357+cviejo@users.noreply.github.com> Date: Sun, 4 May 2025 22:50:54 +0200 Subject: [PATCH 07/11] function docs --- src/core/chuck_io.cpp | 37 ++++++++++--------------------------- src/core/midiio_rtmidi.cpp | 33 ++++++++++++++++----------------- src/core/util_buffers.cpp | 2 ++ 3 files changed, 28 insertions(+), 44 deletions(-) diff --git a/src/core/chuck_io.cpp b/src/core/chuck_io.cpp index 5927cc280..0b62cb356 100644 --- a/src/core/chuck_io.cpp +++ b/src/core/chuck_io.cpp @@ -811,7 +811,7 @@ t_CKBOOL init_class_Midi( Chuck_Env * env ) // add recv() func = make_new_mfun( "int", "recv", MidiIn_recv_bytes ); func->add_arg( "int[]", "bytes" ); - func->doc = "Return into the MidiMsg argument the next message in the queue from the device. Return 0 if the queue is empty or 1 if a message was in the queue and returned in the argument."; + func->doc = "Return into the int[] argument the next message in the queue from the device. Return 0 if the queue is empty or 1 if a message was in the queue and returned in the argument."; if( !type_engine_import_mfun( env, func ) ) goto error; @@ -2487,43 +2487,26 @@ CK_DLL_MFUN( MidiIn_recv ) { MidiIn * min = (MidiIn *)OBJ_MEMBER_INT(SELF, MidiIn_offset_data); Chuck_Object * fake_msg = GET_CK_OBJECT(ARGS); - Chuck_ArrayInt bytes(false, 3); - RETURN->v_int = min->recv( &bytes ); + MidiMsg the_msg; + RETURN->v_int = min->recv( &the_msg ); if( RETURN->v_int ) { - t_CKUINT val; - - bytes.get(0, &val); - OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data1) = val; - bytes.get(1, &val); - OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data2) = val; - bytes.get(2, &val); - OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data3) = val; + OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data1) = the_msg.data[0]; + OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data2) = the_msg.data[1]; + OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data3) = the_msg.data[2]; } } -// CK_DLL_MFUN( MidiIn_recv ) -// { -// MidiIn * min = (MidiIn *)OBJ_MEMBER_INT(SELF, MidiIn_offset_data); -// Chuck_Object * fake_msg = GET_CK_OBJECT(ARGS); -// MidiMsg the_msg; -// RETURN->v_int = min->recv( &the_msg ); -// if( RETURN->v_int ) -// { -// OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data1) = the_msg.data[0]; -// OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data2) = the_msg.data[1]; -// OBJ_MEMBER_INT(fake_msg, MidiMsg_offset_data3) = the_msg.data[2]; -// } -// } - CK_DLL_MFUN( MidiIn_recv_bytes ) { MidiIn * min = (MidiIn *)OBJ_MEMBER_INT(SELF, MidiIn_offset_data); Chuck_ArrayInt * bytes = (Chuck_ArrayInt *)GET_NEXT_OBJECT(ARGS); - if (bytes == NULL) { + if( bytes == NULL ) + { RETURN->v_int = 0; } - else { + else + { RETURN->v_int = min->recv( bytes ); } } diff --git a/src/core/midiio_rtmidi.cpp b/src/core/midiio_rtmidi.cpp index f2b4de284..e0fde70b7 100644 --- a/src/core/midiio_rtmidi.cpp +++ b/src/core/midiio_rtmidi.cpp @@ -646,46 +646,45 @@ t_CKBOOL MidiIn::empty() //----------------------------------------------------------------------------- -// name: get() -// desc: get message -// ----------------------------------------------------------------------------- +// name: recv() +// desc: get a 3-byte midi message +//----------------------------------------------------------------------------- t_CKUINT MidiIn::recv( MidiMsg * msg ) { if( !m_valid ) return FALSE; + t_CKUINT size = m_buffer->getNextSize(m_read_index); - if (size != 0) - { - return size; - } - t_CKBYTE tmp[size]; + if( size == 0 ) return size; - std::fill(tmp, tmp + size, 0); + t_CKBYTE tmp[size]; m_buffer->get(&tmp, m_read_index); + std::fill(msg->data, msg->data + 3, 0); + for (t_CKUINT i = 0; i < size && i < 3; i++) { - // if (i > 2) - // { - // break; - // } msg->data[i] = tmp[i]; } return size; } + + + +//----------------------------------------------------------------------------- +// name: recv() +// desc: get a midi message of any byte length +//----------------------------------------------------------------------------- t_CKUINT MidiIn::recv( Chuck_ArrayInt * arr ) { if( !m_valid ) return FALSE; t_CKUINT size = m_buffer->getNextSize(m_read_index); - if (size == 0) - { - return size; - } + if( size == 0 ) return size; t_CKBYTE tmp[size]; diff --git a/src/core/util_buffers.cpp b/src/core/util_buffers.cpp index 94eb3c97c..6f0efb4e1 100644 --- a/src/core/util_buffers.cpp +++ b/src/core/util_buffers.cpp @@ -405,6 +405,8 @@ void CBufferAdvanceVariable::cleanup() void CBufferAdvanceVariable::put( void * data, UINT__ size ) { + if( size == 0 ) return; + UINT__ i; BYTE__ * d = (BYTE__ *)data; From 68cb626de013f3e8df794bdd9a0b92ead2de0f4c Mon Sep 17 00:00:00 2001 From: cviejo <1179357+cviejo@users.noreply.github.com> Date: Mon, 5 May 2025 12:27:44 +0200 Subject: [PATCH 08/11] added examples --- examples/midi/midi-bytes-receive.ck | 19 +++++++++++++++++++ examples/midi/midi-bytes-send.ck | 10 ++++++++++ src/core/midiio_rtmidi.cpp | 5 ++++- src/core/util_buffers.cpp | 10 ++++++++-- 4 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 examples/midi/midi-bytes-receive.ck create mode 100644 examples/midi/midi-bytes-send.ck diff --git a/examples/midi/midi-bytes-receive.ck b/examples/midi/midi-bytes-receive.ck new file mode 100644 index 000000000..1ee7a7269 --- /dev/null +++ b/examples/midi/midi-bytes-receive.ck @@ -0,0 +1,19 @@ +MidiIn min; + +if (!min.open(0)) { + me.exit(); +} + +int bytes[0]; + +while (min => now) { + while (min.recv(bytes)) { + chout <= "bytes: "; + + for (auto byte : bytes) { + chout <= byte <= " "; + } + + chout <= IO.newline(); + } +} diff --git a/examples/midi/midi-bytes-send.ck b/examples/midi/midi-bytes-send.ck new file mode 100644 index 000000000..82eb52cea --- /dev/null +++ b/examples/midi/midi-bytes-send.ck @@ -0,0 +1,10 @@ +MidiOut mout; + +if (!mout.open(0)) { + me.exit(); +} + +// Full frame midi time code (MTC) message. +// SMPTE timecode: 01:02:03:04.20 (1 hour, 2 minutes, 3 seconds, 4 frames, 20 subframes). +// F0 7F 7F 01 01 01 02 03 04 14 F7 +mout.send([ 0xF0, 0x7F, 0x7F, 0x01, 0x01, 0x01, 0x02, 0x03, 0x04, 0x14, 0xF7 ]); diff --git a/src/core/midiio_rtmidi.cpp b/src/core/midiio_rtmidi.cpp index e0fde70b7..49e2ae762 100644 --- a/src/core/midiio_rtmidi.cpp +++ b/src/core/midiio_rtmidi.cpp @@ -570,7 +570,8 @@ t_CKBOOL MidiInManager::add_vm( Chuck_VM * vm, t_CKINT device_num, // allocate the buffer CBufferAdvanceVariable * cbuf = new CBufferAdvanceVariable; - if( !cbuf->initialize( MIDI_BUFFER_SIZE, m_event_buffers[vm] ) ) + // buffer size with an estimate of 3 bytes per message + if( !cbuf->initialize( MIDI_BUFFER_SIZE * 3, m_event_buffers[vm] ) ) { if( !suppress_output ) EM_error2( 0, "MidiIn: couldn't allocate CBuffer for port %i...", device_num ); @@ -732,7 +733,9 @@ void MidiInManager::cb_midi_input( double deltatime, std::vector CBufferAdvanceVariable * cbuf = it->second; if( cbuf != NULL ) + { cbuf->put( msg->data(), msg->size() ); + } } } } diff --git a/src/core/util_buffers.cpp b/src/core/util_buffers.cpp index 6f0efb4e1..2ed720a49 100644 --- a/src/core/util_buffers.cpp +++ b/src/core/util_buffers.cpp @@ -300,7 +300,7 @@ void CBufferAdvance::put( void * data, UINT__ num_elem ) }*/ -BOOL__ CBufferAdvance::empty(UINT__ read_offset_index) +BOOL__ CBufferAdvance::empty( UINT__ read_offset_index ) { // make sure index is valid if( read_offset_index >= m_read_offsets.size() ) @@ -315,19 +315,25 @@ BOOL__ CBufferAdvance::empty(UINT__ read_offset_index) } -BOOL__ CBufferAdvance::isValidIndex(UINT__ read_offset_index) +BOOL__ CBufferAdvance::isValidIndex( UINT__ read_offset_index ) { if( read_offset_index >= m_read_offsets.size() ) + { return FALSE; + } SINT__ m_read_offset = m_read_offsets[read_offset_index].read_offset; if( m_read_offset < 0 ) + { return FALSE; + } // read catch up with write if( m_read_offset == m_write_offset ) + { return FALSE; + } return TRUE; } From c195a49ded46bbef2159ba5342263bb4281676b2 Mon Sep 17 00:00:00 2001 From: cviejo <1179357+cviejo@users.noreply.github.com> Date: Mon, 5 May 2025 15:04:01 +0200 Subject: [PATCH 09/11] fixed windows compilation --- src/core/midiio_rtmidi.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/core/midiio_rtmidi.cpp b/src/core/midiio_rtmidi.cpp index 49e2ae762..ee13bfda3 100644 --- a/src/core/midiio_rtmidi.cpp +++ b/src/core/midiio_rtmidi.cpp @@ -658,11 +658,10 @@ t_CKUINT MidiIn::recv( MidiMsg * msg ) if( size == 0 ) return size; - t_CKBYTE tmp[size]; + // MSVC doesn't play well with VLAs, don't use t_CKBYTE tmp[size] here + std::vector tmp(size, 0); - m_buffer->get(&tmp, m_read_index); - - std::fill(msg->data, msg->data + 3, 0); + m_buffer->get(tmp.data(), m_read_index); for (t_CKUINT i = 0; i < size && i < 3; i++) { @@ -685,11 +684,12 @@ t_CKUINT MidiIn::recv( Chuck_ArrayInt * arr ) t_CKUINT size = m_buffer->getNextSize(m_read_index); - if( size == 0 ) return size; + if( size == 0 ) return 0; - t_CKBYTE tmp[size]; + std::vector tmp(size, 0); - m_buffer->get(&tmp, m_read_index); + // don't pass arr->m_vector.data() directly, that holds longs + m_buffer->get(tmp.data(), m_read_index); arr->clear(); From fdef08949b5678e5ebf5804849d2830f2f3f31b1 Mon Sep 17 00:00:00 2001 From: cviejo <1179357+cviejo@users.noreply.github.com> Date: Mon, 5 May 2025 20:31:22 +0200 Subject: [PATCH 10/11] comments --- src/core/util_buffers.cpp | 142 +++++++++++++++++++++++++------------- src/core/util_buffers.h | 4 ++ 2 files changed, 99 insertions(+), 47 deletions(-) diff --git a/src/core/util_buffers.cpp b/src/core/util_buffers.cpp index 2ed720a49..d0ff5df9f 100644 --- a/src/core/util_buffers.cpp +++ b/src/core/util_buffers.cpp @@ -329,7 +329,6 @@ BOOL__ CBufferAdvance::isValidIndex( UINT__ read_offset_index ) return FALSE; } - // read catch up with write if( m_read_offset == m_write_offset ) { return FALSE; @@ -402,10 +401,43 @@ BOOL__ CBufferAdvanceVariable::initialize( UINT__ buffer_size, CBufferSimple * e } -void CBufferAdvanceVariable::cleanup() +UINT__ CBufferAdvanceVariable::get( void * data, UINT__ read_offset_index ) { - CBufferAdvance::cleanup(); - m_buffer_size = 0; + UINT__ i; + BYTE__ * d = (BYTE__ *)data; + + // TODO: necessary? + #ifndef __DISABLE_THREADS__ + m_mutex.acquire(); + #endif + + if (!this->isValidIndex(read_offset_index)) + { + #ifndef __DISABLE_THREADS__ + m_mutex.release(); + #endif + return 0; + } + + SINT__ read_offset = m_read_offsets[read_offset_index].read_offset; + UINT__ size = m_data[read_offset]; + + for( i = 0; i < size; i++ ) + { + read_offset = advanceIndex( read_offset ); + d[i] = m_data[read_offset]; + } + read_offset = advanceIndex( read_offset ); + + // update read offset at given index + m_read_offsets[read_offset_index].read_offset = read_offset; + + // TODO: necessary? + #ifndef __DISABLE_THREADS__ + m_mutex.release(); + #endif + + return size; } @@ -421,24 +453,27 @@ void CBufferAdvanceVariable::put( void * data, UINT__ size ) m_mutex.acquire(); #endif + // not enough space, drop the message. this is an edge case, will probably never happen + if( !hasSpace(size) ) + { + #ifndef __DISABLE_THREADS__ + m_mutex.release(); + #endif + return; + } + // store the size of the message m_data[m_write_offset] = size; // copy the data for( i = 0; i < size; i++ ) { - m_write_offset++; - - if ( m_write_offset >= m_buffer_size ) - m_write_offset = 0; - + m_write_offset = advanceIndex( m_write_offset ); m_data[m_write_offset] = d[i]; } - // move to the next write position - m_write_offset++; + m_write_offset = advanceIndex( m_write_offset ); - // possibility of expelling evil shreds for( i = 0; i < m_read_offsets.size(); i++ ) { if( m_read_offsets[i].event ) @@ -452,62 +487,75 @@ void CBufferAdvanceVariable::put( void * data, UINT__ size ) } +void CBufferAdvanceVariable::cleanup() +{ + CBufferAdvance::cleanup(); + m_buffer_size = 0; +} + + +//----------------------------------------------------------------------------- +// name: getNextSize() +// desc: get the size of the next message so we can allocate space for it +// before calling get() +//----------------------------------------------------------------------------- UINT__ CBufferAdvanceVariable::getNextSize( UINT__ read_offset_index ) { - SINT__ m_read_offset = m_read_offsets[read_offset_index].read_offset; + SINT__ read_offset = m_read_offsets[read_offset_index].read_offset; - if( m_read_offset == m_write_offset ) + if( read_offset == m_write_offset ) { return 0; } - return m_data[m_read_offset]; + return m_data[read_offset]; } -UINT__ CBufferAdvanceVariable::get( void * data, UINT__ read_offset_index ) +//----------------------------------------------------------------------------- +// name: advanceIndex() +// desc: advance the index, wrapping around if necessary +//----------------------------------------------------------------------------- +UINT__ CBufferAdvanceVariable::advanceIndex( UINT__ offset_index ) { - UINT__ i; - BYTE__ * d = (BYTE__ *)data; - - // TODO: necessary? - #ifndef __DISABLE_THREADS__ - m_mutex.acquire(); - #endif + offset_index++; - if (!this->isValidIndex(read_offset_index)) + if( offset_index >= m_buffer_size ) { - #ifndef __DISABLE_THREADS__ - m_mutex.release(); - #endif - return 0; + offset_index = 0; } - SINT__ m_read_offset = m_read_offsets[read_offset_index].read_offset; - UINT__ size = m_data[m_read_offset]; + return offset_index; +} + + +//----------------------------------------------------------------------------- +// name: hasSpace() +// desc: Covers an edge case where too many messages have been put into the +// buffer without being read. We check all the write positions to see if +// they are already occupied by a read position. +//----------------------------------------------------------------------------- +BOOL__ CBufferAdvanceVariable::hasSpace(UINT__ size) +{ + UINT__ i, j; + // current position we can advance without checking, + // it's the size of the next message + UINT__ pos = advanceIndex( m_write_offset ); for( i = 0; i < size; i++ ) { - m_read_offset++; - - if( m_read_offset >= m_buffer_size ) - m_read_offset = 0; + pos = advanceIndex( m_write_offset ); - d[i] = m_data[m_read_offset]; + for( j = 0; j < m_read_offsets.size(); j++ ) + { + if( pos == m_read_offsets[j].read_offset ) + { + return FALSE; + } + } } - m_read_offset++; - - // update read offset at given index - m_read_offsets[read_offset_index].read_offset = m_read_offset; - - // TODO: necessary? - #ifndef __DISABLE_THREADS__ - m_mutex.release(); - #endif - - // return number of elems - return size; + return TRUE; } diff --git a/src/core/util_buffers.h b/src/core/util_buffers.h index 3a3d27c70..efe68a21f 100644 --- a/src/core/util_buffers.h +++ b/src/core/util_buffers.h @@ -127,6 +127,10 @@ class CBufferAdvanceVariable : public CBufferAdvance protected: UINT__ m_buffer_size; + +private: + UINT__ advanceIndex( UINT__ offset_index ); + BOOL__ hasSpace( UINT__ size ); }; From 0123304dfa7722f5a3ef4e426911aa34b556add4 Mon Sep 17 00:00:00 2001 From: cviejo <1179357+cviejo@users.noreply.github.com> Date: Tue, 6 May 2025 10:30:50 +0200 Subject: [PATCH 11/11] formatting --- src/core/util_buffers.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/core/util_buffers.cpp b/src/core/util_buffers.cpp index d0ff5df9f..912187d6e 100644 --- a/src/core/util_buffers.cpp +++ b/src/core/util_buffers.cpp @@ -406,12 +406,11 @@ UINT__ CBufferAdvanceVariable::get( void * data, UINT__ read_offset_index ) UINT__ i; BYTE__ * d = (BYTE__ *)data; - // TODO: necessary? #ifndef __DISABLE_THREADS__ m_mutex.acquire(); #endif - if (!this->isValidIndex(read_offset_index)) + if ( !this->isValidIndex(read_offset_index) ) { #ifndef __DISABLE_THREADS__ m_mutex.release(); @@ -429,10 +428,8 @@ UINT__ CBufferAdvanceVariable::get( void * data, UINT__ read_offset_index ) } read_offset = advanceIndex( read_offset ); - // update read offset at given index m_read_offsets[read_offset_index].read_offset = read_offset; - // TODO: necessary? #ifndef __DISABLE_THREADS__ m_mutex.release(); #endif @@ -448,7 +445,6 @@ void CBufferAdvanceVariable::put( void * data, UINT__ size ) UINT__ i; BYTE__ * d = (BYTE__ *)data; - // TODO: necessary? #ifndef __DISABLE_THREADS__ m_mutex.acquire(); #endif @@ -465,22 +461,21 @@ void CBufferAdvanceVariable::put( void * data, UINT__ size ) // store the size of the message m_data[m_write_offset] = size; - // copy the data for( i = 0; i < size; i++ ) { m_write_offset = advanceIndex( m_write_offset ); m_data[m_write_offset] = d[i]; } - // move to the next write position m_write_offset = advanceIndex( m_write_offset ); for( i = 0; i < m_read_offsets.size(); i++ ) { if( m_read_offsets[i].event ) + { m_read_offsets[i].event->queue_broadcast( m_event_buffer ); + } } - // TODO: necessary? #ifndef __DISABLE_THREADS__ m_mutex.release(); #endif @@ -531,7 +526,7 @@ UINT__ CBufferAdvanceVariable::advanceIndex( UINT__ offset_index ) //----------------------------------------------------------------------------- // name: hasSpace() -// desc: Covers an edge case where too many messages have been put into the +// desc: covers an edge case where too many messages have been put into the // buffer without being read. We check all the write positions to see if // they are already occupied by a read position. //-----------------------------------------------------------------------------