/** * @brief Detect the format of message stored in a buffer. * Determine the message format used in a stream of bytes. * @public @memberof MIDIMessageFormat * @param buffer The message as it would appear on a MIDI cable. * @return a pointer to the correct message format if the format could be detected. * @return a NULL pointer if the format could not be detected. */ struct MIDIMessageFormat * MIDIMessageFormatDetect( void * buffer ) { static struct MIDIMessageFormat * formats[] = { &_note_off_on, &_polyphonic_key_pressure, &_control_change, &_program_change, &_channel_pressure, &_pitch_wheel_change, &_system_exclusive, &_time_code_quarter_frame, &_song_position_pointer, &_song_select, &_tune_request, &_real_time }; int i; MIDIPrecondReturn( buffer != NULL, EFAULT, NULL ); for( i=0; i<N_ELEM(formats); i++ ) { MIDIAssert( formats[i] != NULL && formats[i]->test != NULL ); if( (formats[i]->test)( buffer ) ) { return formats[i]; } } return NULL; }
/** * @brief Destroy a MIDIEvent instance. * Free all resources occupied by the event and release all referenced objects. * @public @memberof MIDIEvent * @param event The event. */ void MIDIEventDestroy( struct MIDIEvent * event ) { MIDIPrecondReturn( event != NULL, EFAULT, (void)0 ); if( event->message != NULL ) { free( event->message ); } free( event ); }
struct CFMIDIRunloop * CFMIDIRunloopCreate( CFRunLoopRef runloop ) { struct CFMIDIRunloop * cf_runloop = malloc( sizeof( struct CFMIDIRunloop ) ); MIDIPrecondReturn( cf_runloop != NULL, ENOMEM, NULL ); cf_runloop->refs = 1; cf_runloop->runloop = runloop; cf_runloop->timer_context.version = 0; cf_runloop->timer_context.info = cf_runloop; cf_runloop->timer_context.release = &_cf_release_callback; cf_runloop->timer_context.retain = &_cf_retain_callback; cf_runloop->timer_context.copyDescription = NULL; cf_runloop->socket_context.version = 0; cf_runloop->socket_context.info = cf_runloop; cf_runloop->socket_context.release = &_cf_release_callback; cf_runloop->socket_context.retain = &_cf_retain_callback; cf_runloop->socket_context.copyDescription = NULL; cf_runloop->delegate.info = cf_runloop; cf_runloop->delegate.schedule_read = &_cf_runloop_schedule_read; cf_runloop->delegate.schedule_write = &_cf_runloop_schedule_write; cf_runloop->delegate.schedule_timeout = &_cf_runloop_schedule_timeout; cf_runloop->delegate.clear_read = &_cf_runloop_clear_read; cf_runloop->delegate.clear_write = &_cf_runloop_clear_write; cf_runloop->delegate.clear_timeout = &_cf_runloop_clear_timeout; return cf_runloop; }
/** * @brief Release a MIDIPort instance. * Decrement the reference counter of a port. If the reference count * reached zero, destroy the port. Before decrementing the reference * count check for invalidated connected ports and remove them to * break retain cycles. * @public @memberof MIDIPort * @param port The port. */ void MIDIPortRelease( struct MIDIPort * port ) { MIDIPrecondReturn( port != NULL, EFAULT, (void)0 ); if( port->refs > 1 ) { MIDIListApply( port->ports, port, &_port_apply_check ); } MIDILogLocation( DEVELOP, "Release port %s [%p] (%i -> %i)\n", port->name, port, port->refs, port->refs -1 ); if( ! --port->refs ) { MIDIPortDestroy( port ); } }
/** * @brief Initialize a MIDIDriver instance. * @public @memberof MIDIDriver * @param name The name to identify the driver. * @param rate The sampling rate to use. */ void MIDIDriverInit( struct MIDIDriver * driver, char * name, MIDISamplingRate rate ) { MIDIPrecondReturn( driver != NULL, EFAULT, (void)0 ); driver->refs = 1; driver->rls = NULL; driver->port = MIDIPortCreate( name, MIDI_PORT_IN | MIDI_PORT_OUT, driver, &_port_receive ); driver->clock = MIDIClockProvide( rate ); driver->send = NULL; driver->destroy = NULL; }
/** * @brief Destroy a MIDIPort instance. * Free all resources occupied by the port and release connected ports. * @public @memberof MIDIPort * @param port The port. */ void MIDIPortDestroy( struct MIDIPort * port ) { MIDIPrecondReturn( port != NULL, EFAULT, (void)0 ); MIDIListRelease( port->ports ); /* If we get problems with with access to freed ports we could * enable this temporarily .. * port->ports = NULL; * MIDIPrecondReturn( port->valid == 0, ECANCELED, (void)0 ); */ MIDILogLocation( DEVELOP, "Destroy port %s [%p]\n", port->name, port ); free( port->name ); free( port ); }
struct CFMIDIRunLoopSource * CFMIDIRunLoopSourceCreate( struct MIDIRunloopSource * source ) { int i, create; CFRunLoopTimerContext timer_context; CFSocketContext socket_context; CFOptionFlags socket_cb_types; CFSocketRef socket; struct CFMIDIRunLoopSource * cf = malloc( sizeof(struct CFMIDIRunLoopSource) + sizeof(CFRunLoopSourceRef)*(source->nfds-1) ); MIDIPrecondReturn( cf != NULL, ENOMEM, NULL ); timer_context.version = 0; timer_context.info = source; timer_context.release = NULL; timer_context.retain = NULL; timer_context.copyDescription = NULL; socket_context.version = 0; socket_context.info = source; socket_context.release = NULL; socket_context.retain = NULL; socket_context.copyDescription = NULL; cf->length = source->nfds; if( source->timeout.tv_sec > 0 || source->timeout.tv_nsec > 0 ) { cf->cfrlt = CFRunLoopTimerCreate( NULL, CFAbsoluteTimeGetCurrent(), (double) source->timeout.tv_sec + 0.000000001 * (double) source->timeout.tv_nsec, 0, 1, &_cf_timer_callback, &timer_context ); } else { cf->cfrlt = NULL; } for( i=0; i<cf->length; i++ ) { create = 0; socket_cb_types = kCFSocketNoCallBack; if( FD_ISSET(i, &(source->readfds)) ) { socket_cb_types |= kCFSocketReadCallBack; create = 1; } if( FD_ISSET(i, &(source->writefds)) ) { socket_cb_types |= kCFSocketWriteCallBack; create = 1; } if( create ) { socket = CFSocketCreateWithNative( NULL, i, socket_cb_types, &_cf_socket_callback, &socket_context ); cf->cfrls[i] = CFSocketCreateRunLoopSource( NULL, socket, 1 ); CFRelease( socket ); } else { cf->cfrls[i] = NULL; } } return cf; }
/** * @brief Create a MIDIPort instance. * Allocate space and initialize a MIDIPort instance. * @public @memberof MIDIPort * @param name The name of the MIDIPort. * @param mode The communication mode flags. * @param target The target for receiving messages. * @param receive The callback for incoming messages. * @return a pointer to the created port structure on success. * @return a @c NULL pointer if the port could not created. */ struct MIDIPort * MIDIPortCreate( char * name, int mode, void * target, int (*receive)( void *, void *, struct MIDITypeSpec *, void * ) ) { MIDIPrecondReturn( name != NULL, EINVAL, NULL ); if( mode & MIDI_PORT_IN ) { MIDIPrecondReturn( target != NULL, EINVAL, NULL ); MIDIPrecondReturn( receive != NULL, EINVAL, NULL ); } struct MIDIPort * port = malloc( sizeof( struct MIDIPort ) ); size_t namelen; MIDIPrecondReturn( port != NULL, ENOMEM, NULL ); namelen = strlen( name ) + 1; if( namelen > 128 ) namelen = 128; port->refs = 1; port->mode = mode; port->name = malloc( namelen ); port->target = target; port->receive = receive; if( port->name == NULL ) { free( port ); return NULL; } port->ports = MIDIListCreate( MIDIPortType ); if( port->ports == NULL ) { /* probably ENOMEM, in that case, error code is already set by MIDIList */ free (port->name); free( port ); return NULL; } port->intercept = NULL; port->observer = NULL; strncpy( port->name, name, namelen ); return port; }
/** * @brief Destroy a CFMIDIRunLoopSource instance. * Free all resources occupied by the runloop soruce and release all referenced objects. * @public @memberof CFMIDIRunLoopSource * @param source The runloop source. */ void CFMIDIRunLoopSourceDestroy( struct CFMIDIRunLoopSource * source ) { int i; MIDIPrecondReturn( source != NULL, EFAULT, (void)0 ); if( source->cfrlt != NULL ) { CFRunLoopTimerInvalidate( source->cfrlt ); CFRelease( source->cfrlt ); } for( i=0; i<source->length; i++ ) { if( source->cfrls[i] != NULL ) { CFRunLoopSourceInvalidate( source->cfrls[i] ); CFRelease( source->cfrls[i] ); } } free( source ); }
/** * @brief Destroy a MIDIDriver instance. * Free all resources occupied by the driver and release all referenced objects. * @public @memberof MIDIDriver * @param driver The driver. */ void MIDIDriverDestroy( struct MIDIDriver * driver ) { MIDIPrecondReturn( driver != NULL, EFAULT, (void)0 ); if( driver->destroy != NULL ) { (*driver->destroy)( driver ); } if( driver->clock != NULL ) { MIDIClockRelease( driver->clock ); } if( driver->rls != NULL ) { MIDIRunloopSourceInvalidate( driver->rls ); MIDIRunloopSourceRelease( driver->rls ); } MIDIPortInvalidate( driver->port ); MIDIPortRelease( driver->port ); free( driver ); }
/** * @brief Create a MIDIDriverCoreMIDI instance. * Allocate space and initialize an MIDIDriverCoreMIDI instance. * @public @memberof MIDIDriverCoreMIDI * @return a pointer to the created driver structure on success. * @return a @c NULL pointer if the driver could not created. */ struct MIDIDriverCoreMIDI * MIDIDriverCoreMIDICreate( char * name, MIDIClientRef client ) { struct MIDIDriverCoreMIDI * driver; CFStringRef in_name, out_name; driver = malloc( sizeof( struct MIDIDriverCoreMIDI ) ); MIDIPrecondReturn( driver != NULL, ENOMEM, NULL ); MIDIDriverInit( &(driver->base), name, COREMIDI_CLOCK_RATE ); driver->client = client; in_name = CFStringCreateWithFormat( NULL, NULL, CFSTR("MIDIKit %s input"), name ); out_name = CFStringCreateWithFormat( NULL, NULL, CFSTR("MIDIKit %s input"), name ); MIDIInputPortCreate( client, in_name, &_coremidi_readproc, driver, &(driver->cm_in_port) ); MIDIOutputPortCreate( client, out_name, &(driver->cm_out_port) ); return driver; }
/** * @brief Create a MIDIDriverAppleMIDI instance. * Allocate space and initialize an MIDIDriverAppleMIDI instance. * @public @memberof MIDIDriverAppleMIDI * @return a pointer to the created driver structure on success. * @return a @c NULL pointer if the driver could not created. */ struct MIDIDriverAppleMIDI * MIDIDriverAppleMIDICreate( char * name, unsigned short port ) { struct MIDIDriverAppleMIDI * driver; MIDITimestamp timestamp; int ret = 0; driver = malloc( sizeof( struct MIDIDriverAppleMIDI ) ); MIDIPrecondReturn( driver != NULL, ENOMEM, NULL ); MIDIDriverInit( &(driver->base), name, APPLEMIDI_CLOCK_RATE ); driver->control_socket = 0; driver->rtp_socket = 0; driver->port = port; driver->accept = 0; driver->sync = 0; strncpy( &(driver->name[0]), name, sizeof(driver->name) ); driver->in_queue = MIDIMessageQueueCreate(); driver->out_queue = MIDIMessageQueueCreate(); driver->base.send = &_driver_send; driver->base.destroy = &_driver_destroy; ret = _applemidi_connect( driver ); if (ret==-1) MIDILog( ERROR, "Bind failed for port: %hu\n", port); driver->peer = NULL; driver->rtp_session = RTPSessionCreate( driver->rtp_socket ); driver->rtpmidi_session = RTPMIDISessionCreate( driver->rtp_session ); MIDIClockGetNow( driver->base.clock, ×tamp ); MIDILog( DEBUG, "initial timestamp: %lli\n", timestamp ); driver->token = timestamp; memset( &(driver->command), 0, sizeof(driver->command) ); driver->command.peer = NULL; _applemidi_init_runloop_source( driver ); return driver; }
/** * @brief Create a MIDIEvent instance. * Allocate space and initialize a MIDIEvent instance. * @public @memberof MIDIEvent * @param id A (hopefully) unique ID. * @param info Any optional data to be associated with the event. * @param message A message format that may contain placeholders. * @param ... The data to be filled into the message format placeholders. * (Refer to the sprintf specification for details.) * @return a pointer to the created event structure on success. * @return a @c NULL pointer if the event could not created. */ struct MIDIEvent * MIDIEventCreate( size_t id, void * info, char * message, ... ) { void * buffer; size_t length, required; va_list vargs; struct MIDIEvent * event = malloc( sizeof( struct MIDIEvent ) ); MIDIPrecondReturn( event != NULL, ENOMEM, NULL ); event->refs = 1; event->id = id; event->info = info; if( message != NULL ) { length = 64; buffer = malloc( length ); va_start( vargs, message ); do { if( buffer == NULL ) { MIDIError( ENOMEM, "Could not allocate space for static buffer." ); free (event); return NULL; } required = vsnprintf( buffer, length-1, message, vargs ); if( required > length ) { buffer = realloc( buffer, required ); length = required; } } while( required > length ); va_end( vargs ); event->message = buffer; event->length = length; } else { event->message = NULL; event->length = 0; } return event; }
/** * @brief Retain a MIDIDriver instance. * Increment the reference counter of a driver so that it won't be destroyed. * @public @memberof MIDIDriver * @param driver The driver. */ void MIDIDriverRetain( struct MIDIDriver * driver ) { MIDIPrecondReturn( driver != NULL, EFAULT, (void)0 ); driver->refs++; }
/** * @brief Release a CFMIDIRunLoopSource instance. * Decrement the reference counter of a clock. If the reference count * reached zero, destroy the clock. * @public @memberof CFMIDIRunLoopSource * @param source The runloop source. */ void CFMIDIRunLoopSourceRelease( struct CFMIDIRunLoopSource * source ) { MIDIPrecondReturn( source != NULL, EFAULT, (void)0 ); if( ! --source->refs ) { CFMIDIRunLoopSourceDestroy( source ); } }
/** * @brief Retain a CFMIDIRunLoopSource instance. * Increment the reference counter of a clock so that it won't be destroyed. * @public @memberof CFMIDIRunLoopSource * @param source The runloop source. */ void CFMIDIRunLoopSourceRetain( struct CFMIDIRunLoopSource * source ) { MIDIPrecondReturn( source != NULL, EFAULT, (void)0 ); source->refs++; }
/** * @brief Retain a MIDIPort instance. * Increment the reference counter of a port so that it won't be destroyed. * @public @memberof MIDIPort * @param port The port. */ void MIDIPortRetain( struct MIDIPort * port ) { MIDIPrecondReturn( port != NULL, EFAULT, (void)0 ); port->refs++; }
/** * @brief Retain a MIDIEvent instance. * Increment the reference counter of an event so that it won't be destroyed. * @public @memberof MIDIEvent * @param event The event. */ void MIDIEventRetain( struct MIDIEvent * event ) { MIDIPrecondReturn( event != NULL, EFAULT, (void)0 ); event->refs++; }
/** * @brief Release a CFMIDIRunloop instance. * Decrement the reference counter of a runloop. If the reference count * reached zero, destroy the runloop. * @public @memberof CFMIDIRunloop * @param cf_runloop The core foundation runloop. */ void CFMIDIRunloopRelease( struct CFMIDIRunloop * cf_runloop ) { MIDIPrecondReturn( cf_runloop != NULL, EFAULT, (void)0 ); if( ! --cf_runloop->refs ) { CFMIDIRunloopDestroy( cf_runloop ); } }
/** * @brief Retain a CFMIDIRunloop instance. * Increment the reference counter of a runloop so that it won't be destroyed. * @public @memberof CFMIDIRunloop * @param cf_runloop The core foundation runloop. */ void CFMIDIRunloopRetain( struct CFMIDIRunloop * cf_runloop ) { MIDIPrecondReturn( cf_runloop != NULL, EFAULT, (void)0 ); cf_runloop->refs++; }
void CFMIDIRunloopDestroy( struct CFMIDIRunloop * cf_runloop ) { MIDIPrecondReturn( cf_runloop, EFAULT, (void)0 ); free( cf_runloop ); }
/** * @brief Release a MIDIEvent instance. * Decrement the reference counter of an event. If the reference count * reached zero, destroy the event. * @public @memberof MIDIEvent * @param event The event. */ void MIDIEventRelease( struct MIDIEvent * event ) { MIDIPrecondReturn( event != NULL, EFAULT, (void)0 ); if( ! --event->refs ) { MIDIEventDestroy( event ); } }
/** * @brief Release a MIDIDriver instance. * Decrement the reference counter of a driver. If the reference count * reached zero, destroy the driver. * @public @memberof MIDIDriver * @param driver The driver. */ void MIDIDriverRelease( struct MIDIDriver * driver ) { MIDIPrecondReturn( driver != NULL, EFAULT, (void)0 ); if( ! --driver->refs ) { MIDIDriverDestroy( driver ); } }
/** * @brief Create a MIDIDriver instance. * Allocate space and initialize a MIDIDriver instance. * @public @memberof MIDIDriver * @param name The name to identify the driver. * @param rate The sampling rate to use. * @return a pointer to the created driver structure on success. * @return a @c NULL pointer if the driver could not created. */ struct MIDIDriver * MIDIDriverCreate( char * name, MIDISamplingRate rate ) { struct MIDIDriver * driver = malloc( sizeof( struct MIDIDriver ) ); MIDIPrecondReturn( driver != NULL, ENOMEM, NULL ); MIDIDriverInit( driver, name, rate ); return driver; }