int Trick::VariableServerThread::copy_data_scheduled(long long curr_tics) { int ret = 0 ; if ( enabled and copy_mode == VS_COPY_SCHEDULED) { if ( next_tics <= curr_tics ) { copy_sim_data() ; if ( !pause_cmd and write_mode == VS_WRITE_WHEN_COPIED and is_real_time()) { ret = write_data() ; if ( ret < 0 ) { exit_cmd = true ; } } next_tics = curr_tics + cycle_tics ; } } return ret ; }
/* Algorithnm: if overflow or flush, return ATOMIC: enqueue data if buffer overflow, set overflow if buffer overflow and sysex_in_progress, set flush */ void pm_read_short(PmInternal *midi, PmEvent *event) { long tail; int status; /* arg checking */ assert(midi != NULL); assert(!Pm_HasHostError(midi)); /* midi filtering is applied here */ status = Pm_MessageStatus(event->message); if ((status == MIDI_ACTIVE) && (midi->filters & PM_FILT_ACTIVE)) { /* MIDI active sensing filter: do nothing */ } else if ((status == MIDI_CLOCK) && (midi->filters & PM_FILT_CLOCK)) { /* MIDI clock filter: do nothing */ } else { /* if sysex is in progress and we get a status byte, it had better be a realtime message or the starting SYSEX byte; otherwise, we exit the sysex_in_progress state */ if (midi->sysex_in_progress && (status & MIDI_STATUS_MASK) && !is_real_time(status) && status != MIDI_SYSEX ) { midi->sysex_in_progress = FALSE; midi->flush = FALSE; } /* don't try to do anything more in an overflow state */ if (midi->overflow || midi->flush) return; /* insert the message */ tail = midi->tail; midi->buffer[tail++] = *event; if (tail == midi->buffer_len) tail = 0; if (tail == midi->head || midi->overflow) { midi->overflow = TRUE; if (midi->sysex_in_progress) midi->flush = TRUE; /* drop the rest of the message, this must be cleared by caller when EOX is received */ return; } midi->tail = tail; /* complete the write */ } }
int Trick::VariableServerThread::copy_data_freeze() { int ret = 0 ; long long curr_frame = exec_get_freeze_frame_count() ; long long temp_frame ; if ( enabled and copy_mode == VS_COPY_TOP_OF_FRAME) { temp_frame = curr_frame % freeze_frame_multiple ; if ( temp_frame == freeze_frame_offset ) { copy_sim_data() ; if ( !pause_cmd and write_mode == VS_WRITE_WHEN_COPIED and is_real_time()) { ret = write_data() ; if ( ret < 0 ) { exit_cmd = true ; } } } } return ret ; }
PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, long length) { PmInternal *midi = (PmInternal *) stream; PmError err; int i; int bits; /* arg checking */ if(midi == NULL) err = pmBadPtr; else if(Pm_HasHostError(midi)) err = pmHostError; else if(!descriptors[midi->device_id].pub.opened) err = pmBadPtr; else if(!descriptors[midi->device_id].pub.output) err = pmBadPtr; else err = pmNoError; if (err != pmNoError) goto pm_write_error; if (midi->latency == 0) { midi->now = 0; } else { midi->now = (*(midi->time_proc))(midi->time_info); if (midi->first_message || midi->sync_time + 100 /*ms*/ < midi->now) { /* time to resync */ midi->now = (*midi->dictionary->synchronize)(midi); midi->first_message = FALSE; } } for (i = 0; i < length; i++) { unsigned long msg = buffer[i].message; bits = 0; /* is this a sysex message? */ if (Pm_MessageStatus(msg) == MIDI_SYSEX) { if (midi->sysex_in_progress) { /* error: previous sysex was not terminated by EOX */ midi->sysex_in_progress = FALSE; err = pmBadData; goto pm_write_error; } midi->sysex_in_progress = TRUE; if ((err = (*midi->dictionary->begin_sysex)(midi, buffer[i].timestamp)) != pmNoError) goto pm_write_error; if ((err = (*midi->dictionary->write_byte)(midi, MIDI_SYSEX, buffer[i].timestamp)) != pmNoError) goto pm_write_error; bits = 8; /* fall through to continue sysex processing */ } else if ((msg & MIDI_STATUS_MASK) && (Pm_MessageStatus(msg) != MIDI_EOX)) { /* a non-sysex message */ if (midi->sysex_in_progress) { /* this should be a non-realtime message */ if (is_real_time(msg)) { if ((err = (*midi->dictionary->write_realtime)(midi, &(buffer[i]))) != pmNoError) goto pm_write_error; } else { midi->sysex_in_progress = FALSE; err = pmBadData; /* ignore any error from this, because we already have one */ /* pass 0 as timestamp -- it's ignored */ (*midi->dictionary->end_sysex)(midi, 0); goto pm_write_error; } } else { /* regular short midi message */ if ((err = (*midi->dictionary->write_short)(midi, &(buffer[i]))) != pmNoError) goto pm_write_error; continue; } } if (midi->sysex_in_progress) { /* send sysex bytes until EOX */ while (bits < 32) { unsigned char midi_byte = (unsigned char) (msg >> bits); if ((err = (*midi->dictionary->write_byte)(midi, midi_byte, buffer[i].timestamp)) != pmNoError) goto pm_write_error; if (midi_byte == MIDI_EOX) { midi->sysex_in_progress = FALSE; if ((err = (*midi->dictionary->end_sysex)(midi, buffer[i].timestamp)) != pmNoError) goto pm_write_error; break; /* from while loop */ } bits += 8; } } else { /* not in sysex mode, but message did not start with status */ err = pmBadData; goto pm_write_error; } }
PMEXPORT PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, int32_t length) { PmInternal *midi = (PmInternal *) stream; PmError err = pmNoError; int i; int bits; pm_hosterror = FALSE; /* arg checking */ if(midi == NULL) err = pmBadPtr; else if(!descriptors[midi->device_id].pub.opened) err = pmBadPtr; else if(!descriptors[midi->device_id].pub.output) err = pmBadPtr; else err = pmNoError; if (err != pmNoError) goto pm_write_error; if (midi->latency == 0) { midi->now = 0; } else { midi->now = (*(midi->time_proc))(midi->time_info); if (midi->first_message || midi->sync_time + 100 /*ms*/ < midi->now) { /* time to resync */ midi->now = (*midi->dictionary->synchronize)(midi); midi->first_message = FALSE; } } /* error recovery: when a sysex is detected, we call * dictionary->begin_sysex() followed by calls to * dictionary->write_byte() and dictionary->write_realtime() * until an end-of-sysex is detected, when we call * dictionary->end_sysex(). After an error occurs, * Pm_Write() continues to call functions. For example, * it will continue to call write_byte() even after * an error sending a sysex message, and end_sysex() will be * called when an EOX or non-real-time status is found. * When errors are detected, Pm_Write() returns immediately, * so it is possible that this will drop data and leave * sysex messages in a partially transmitted state. */ for (i = 0; i < length; i++) { uint32_t msg = buffer[i].message; bits = 0; /* is this a sysex message? */ if (Pm_MessageStatus(msg) == MIDI_SYSEX) { if (midi->sysex_in_progress) { /* error: previous sysex was not terminated by EOX */ midi->sysex_in_progress = FALSE; err = pmBadData; goto pm_write_error; } midi->sysex_in_progress = TRUE; if ((err = (*midi->dictionary->begin_sysex)(midi, buffer[i].timestamp)) != pmNoError) goto pm_write_error; if ((err = (*midi->dictionary->write_byte)(midi, MIDI_SYSEX, buffer[i].timestamp)) != pmNoError) goto pm_write_error; bits = 8; /* fall through to continue sysex processing */ } else if ((msg & MIDI_STATUS_MASK) && (Pm_MessageStatus(msg) != MIDI_EOX)) { /* a non-sysex message */ if (midi->sysex_in_progress) { /* this should be a realtime message */ if (is_real_time(msg)) { if ((err = (*midi->dictionary->write_realtime)(midi, &(buffer[i]))) != pmNoError) goto pm_write_error; } else { midi->sysex_in_progress = FALSE; err = pmBadData; /* ignore any error from this, because we already have one */ /* pass 0 as timestamp -- it's ignored */ (*midi->dictionary->end_sysex)(midi, 0); goto pm_write_error; } } else { /* regular short midi message */ if ((err = (*midi->dictionary->write_short)(midi, &(buffer[i]))) != pmNoError) goto pm_write_error; continue; } } if (midi->sysex_in_progress) { /* send sysex bytes until EOX */ /* see if we can accelerate data transfer */ if (bits == 0 && midi->fill_base && /* 4 bytes to copy */ (*midi->fill_offset_ptr) + 4 <= midi->fill_length && (msg & 0x80808080) == 0) { /* all data */ /* copy 4 bytes from msg to fill_base + fill_offset */ unsigned char *ptr = midi->fill_base + *(midi->fill_offset_ptr); ptr[0] = msg; ptr[1] = msg >> 8; ptr[2] = msg >> 16; ptr[3] = msg >> 24; (*midi->fill_offset_ptr) += 4; continue; } /* no acceleration, so do byte-by-byte copying */ while (bits < 32) { unsigned char midi_byte = (unsigned char) (msg >> bits); if ((err = (*midi->dictionary->write_byte)(midi, midi_byte, buffer[i].timestamp)) != pmNoError) goto pm_write_error; if (midi_byte == MIDI_EOX) { err = pm_end_sysex(midi); if (err != pmNoError) goto error_exit; break; /* from while loop */ } bits += 8; } } else {