Skip to content

Instantly share code, notes, and snippets.

@andretodman
Created January 19, 2020 00:30
Show Gist options
  • Save andretodman/e587093a5bb4125c64584a7c65a83ce8 to your computer and use it in GitHub Desktop.
Save andretodman/e587093a5bb4125c64584a7c65a83ce8 to your computer and use it in GitHub Desktop.
An Objective-C midi event class that is part of a sequencer engine that I wrote for iOS before CoreMidi. The class saves actual universal midi event packages but allows initializing events with simple Int parameters. The sequencer engine is a circular buffer that stores events played at the eventTimeInTicks. CoreMidi was first available in iOS 4…
//
// MidiEvent.h - Part of a music sequencer audio engine framework written by Andre Todman.
// Used in several audio applications in the App Store (2007-2010).
// Created by Andre Todman on 8/8/09.
//
// Copyright 2009 Pubfuse Inc. All rights reserved.
/* ******************************************************************************************* *\
* A midi event class that is part of a sequencer engine that I wrote for iOS before CoreMidi. *
* The class saves actual universal midi event packages but allows initializing events with *
* simple Int parameters. See: https://en.wikipedia.org/wiki/MIDI_1.0 *
* The sequencer engine is a circular buffer that stores events played at the eventTimeInTicks. *
* CoreMidi was first available in iOS 4.1 around 2010. *
\* ******************************************************************************************* */
// Struct to store modes for offset event times.
// Each mode has different strengths that will trigger events with a different swing
// This allow a more natural feel during playback
struct swingQuantizeTime {
float closest_for_setting_0;
float closest_for_setting_1;
float closest_for_setting_2;
float closest_for_setting_3;
float closest_for_setting_4;
float closest_for_setting_5;
float closest_for_setting_6;
float closest_for_setting_7;
float closest_for_setting_8;
float closest_for_setting_9;
};
/// Class to store a Midi Event with properties that use midi event messages
@interface MidiEvent : NSObject {
struct swingQuantizeTime quantizedTime; // value to snap event time to
NSNumber* on; // On or off
NSNumber* triggerPlay; // Trigger midi play message
NSNumber* triggerStop; // Trigger midi stop message
NSNumber* didPlay; // Save playback state each loop.
NSNumber* midiVelocity; // Volume for the event
NSNumber* beatPosition_0First_15ForLast; // Position of playback in simple 16/th beat mode
NSNumber* timeExact0__to_late7; // Offset event time randomly between abount to allow a natural feel
NSNumber* midiBar; // Bar in beats where the even is played
NSNumber* midiNote; // The value of the midi note, for example 63 for middle C
NSNumber* midiChan; // Midi Channel of the event
NSNumber* eventTimeInTicks; // The event time in ticks per beat
}
//- Generated getters & setters
@property(nonatomic,retain)NSNumber* on;
@property(nonatomic,retain)NSNumber* triggerPlay;
@property(nonatomic,retain)NSNumber* triggerStop;
@property(nonatomic,retain)NSNumber* didPlay;
@property(nonatomic,retain)NSNumber* midiVelocity;
@property(nonatomic,retain)NSNumber* beatPosition_0First_15ForLast;
@property(nonatomic,retain)NSNumber* timeExact0__to_late7;
@property(nonatomic,retain)NSNumber* midiBar;
@property(nonatomic,retain)NSNumber* midiNote;
@property(nonatomic,retain)NSNumber* midiChan;
@property(nonatomic,retain)NSNumber* eventTimeInTicks;
@property struct swingQuantizeTime quantizedTime;
/// Creates a new MidiEvent and initializes it's position of playback, the bar, the note on off display, and the assigned pad number
/// @param beatColNumber Position of playback in simple 16/th beat
/// @param precisionRowNumber Int that stores the position of playback for the event
/// @param theBarNumber Int that stores the bar of playback time
/// @param onOffOther_123 Int that stores on (1), off (0) or other (Custom Midi Message) state.
/// @param padNum The pad number that binds to the midi event. When pressed, allows the sequencer to save the event
-(id) initWithBeatNumber_0__to_15:(int)beatColNumber precision_0_to_7:(int)precisionRowNumber barNumber:(int)theBarNumber setOn1_off0__other2:(int)onOffOther_123 andPad:(int)padNum;
/// Returns the MidiEvent tickPerBeat as Float with swing time forin the current swing setting.
/// Changing during playback in the sequencer engine, you would hear a drummer play more relaxed, for example.
/// @param n Int Setting to use a for swing
-(float)getQuantizedTimeForSetting:(int)n;
/// Change MidiEvent and it's position of playback, the bar, the note on off display
/// @param beat Position of playback in simple 16/th beat
/// @param barNumber Int that stores the bar of playback time
/// @param timeExact Swing setting as in where 0 is exact playback time and 7 is late
-(void)setBeatPosition__0First_15ForLast:(int)beat andBar:(int)barNumber andTimeExact0__to_late7:(int)timeExact;
/// Sets note on/off
/// @param Set note on or off
-(void)setOn1_off0__other2:(int)n;
/// Get NoteOn,NoteOff or Other value
-(int)getOn1_off0__other2 ;
/// Set Quantization offset
/// @param n quantize number as Int
/// @param ev time in ticks of event
-(void)setQuantizeNumber:(int)n withTime:(float)ev;
/// Set bar in beat to play event
/// @param n Bar number to play the event at
-(void)setBar:(int)n;
/// Compare another event to see if it is equal
/// @param midi other event
-(BOOL)isEqual:(MidiEvent*)midi;
/// Copy another midi event
/// @param midi another midi event
-(void)copyEvent:(MidiEvent*)midi;
@end
//
// MidiEvent.h - Part of a music sequencer audio engine framework written by Andre Todman.
// Used in several audio applications in the App Store (2007-2010).
// Created by Andre Todman on 8/8/09.
//
// Copyright 2009 Pubfuse Inc. All rights reserved.
/* ******************************************************************************************* *\
* A midi event class that is part of a sequencer engine that I wrote for iOS before CoreMidi. *
* The class saves actual universal midi event packages but allows initializing events with *
* simple Int parameters. See: https://en.wikipedia.org/wiki/MIDI_1.0 *
* The sequencer engine is a circular buffer that stores events played at the eventTimeInTicks. *
* CoreMidi was first available in iOS 4.1 around 2010. *
\* ******************************************************************************************* */
#import "MidiEvent.h"
@implementation MidiEvent
@synthesize on;
@synthesize triggerPlay;
@synthesize triggerStop;
@synthesize didPlay;
@synthesize midiVelocity;
@synthesize beatPosition_0First_15ForLast;
@synthesize timeExact0__to_late7;
@synthesize midiBar;
@synthesize midiNote;
@synthesize midiChan;
@synthesize eventTimeInTicks;
@synthesize quantizedTime;
/// Initializes a midi event
-(id) init {
if (self = [super init]) {
on = [[[NSNumber alloc]init ]retain] ;
triggerPlay = [[[NSNumber alloc]init ]retain] ;
triggerStop = [[[NSNumber alloc]init ]retain] ;
didPlay = [[[NSNumber alloc]init ]retain] ;
midiVelocity = [[[NSNumber alloc]init ]retain] ;
beatPosition_0First_15ForLast = [[[NSNumber alloc]init ]retain] ;
timeExact0__to_late7 = [[[NSNumber alloc]init ]retain] ;
midiBar = [[[NSNumber alloc]init ]retain] ;
midiNote = [[NSNumber alloc]init ] ;
midiChan = [[[NSNumber alloc]init ]retain] ;
eventTimeInTicks = [[[NSNumber alloc]init ]retain] ;
}
return self;
}
/// Creates a new MidiEvent and initializes it's position of playback, the bar, the note on off display, and the assigned pad number
/// @param beatColNumber Position of playback in simple 16/th beat
/// @param precisionRowNumber Int that stores the position of playback for the event
/// @param theBarNumber Int that stores the bar of playback time
/// @param onOffOther_123 Int that stores on (1), off (0) or other (Custom Midi Message) state.
/// @param padNum The pad number that binds to the midi event. When pressed, allows the sequencer to save the event
-(id) initWithBeatNumber_0__to_15:(int)beatColNumber precision_0_to_7:(int)precisionRowNumber barNumber:(int)theBarNumber setOn1_off0__other2:(int)onOffOther_123 andPad:(int)padNum{
if (self = [super init]) {
[self setOn:[ NSNumber numberWithInt:-1]];
[self setTriggerPlay:[ NSNumber numberWithBool:NO]];
[self setTriggerStop:[ NSNumber numberWithBool:NO]];
[self setDidPlay:[ NSNumber numberWithBool:NO]];
[self setMidiVelocity:[ NSNumber numberWithFloat:1.0f]];
[self setBeatPosition_0First_15ForLast:[ NSNumber numberWithInt:0]];
[self setTimeExact0__to_late7:[ NSNumber numberWithInt:0]];
[self setMidiBar:[ NSNumber numberWithInt:theBarNumber]];
[self setMidiNote:[ NSNumber numberWithInt:padNum]];
[self setMidiChan:[ NSNumber numberWithInt:0]];
[self setEventTimeInTicks:[ NSNumber numberWithInt:0]];
if(onOffOther_123 == 1){
[self setOn:[ NSNumber numberWithBool:YES]];
[self setTriggerPlay:[ NSNumber numberWithBool:YES]];
[self setTriggerStop:[ NSNumber numberWithBool:NO]];
}
else if(onOffOther_123 == 0){
[self setOn:[ NSNumber numberWithBool:YES]];
[self setTriggerPlay:[ NSNumber numberWithBool:NO]];
[self setTriggerStop:[ NSNumber numberWithBool:YES]];
}
else if(onOffOther_123 == 2){
[self setOn:[ NSNumber numberWithBool:YES]];
[self setTriggerPlay:[ NSNumber numberWithBool:NO]];
[self setTriggerStop:[ NSNumber numberWithBool:NO]];
}
}
return self;
}
/// Allows Initializing a saved object automatically when the app is loaded
/// @param coder the save encoded object to load
-(id) initWithCoder:(NSCoder *)coder {
[super init];
on = [[coder decodeObjectForKey:@"on"] retain];
triggerPlay = [[coder decodeObjectForKey:@"triggerPlay"] retain];
triggerStop = [[coder decodeObjectForKey:@"triggerStop"] retain];
didPlay = [[coder decodeObjectForKey:@"didPlay"] retain];
midiVelocity = [[coder decodeObjectForKey:@"midiVelocity"] retain];
beatPosition_0First_15ForLast= [[coder decodeObjectForKey:@"beatPosition_0First_15ForLast"] retain];
timeExact0__to_late7= [[coder decodeObjectForKey:@"timeExact0__to_late7"] retain];
midiBar= [[coder decodeObjectForKey:@"midiBar"] retain];
midiNote= [[coder decodeObjectForKey:@"midiNote"] retain];
midiChan= [[coder decodeObjectForKey:@"midiChan"] retain];
eventTimeInTicks= [[coder decodeObjectForKey:@"eventTimeInTicks"] retain];
return self;
}
/// Saves the current object and it's values
/// @param encoder encoded object ref
-(void) encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:on forKey:@"on"];
[encoder encodeObject:triggerPlay forKey:@"triggerPlay"];
[encoder encodeObject:triggerStop forKey:@"triggerStop"];
[encoder encodeObject:didPlay forKey:@"didPlay"];
[encoder encodeObject:midiVelocity forKey:@"midiVelocity"];
[encoder encodeObject:beatPosition_0First_15ForLast forKey:@"beatPosition_0First_15ForLast"];
[encoder encodeObject:timeExact0__to_late7 forKey:@"timeExact0__to_late7"];
[encoder encodeObject:midiBar forKey:@"midiBar"];
[encoder encodeObject:midiNote forKey:@"midiNote"];
[encoder encodeObject:midiChan forKey:@"midiChan"];
[encoder encodeObject:eventTimeInTicks forKey:@"eventTimeInTicks"];
}
/// Sets the midi note
/// @param n Value of the midi key, 63 is middle C
-(void)setNote:(int)n{
[self setMidiNote:[ NSNumber numberWithInt:n]];
}
/// Sets the midi channel
/// @param n New midi channel to use
-(void)setChan:(int)n{
[self setMidiChan:[ NSNumber numberWithInt:n]];
}
/// Sets Velocity to of the note
/// @param n Velocity amount
-(void)setVelocity:(float)n{
[self setMidiVelocity:[ NSNumber numberWithFloat:n]];
}
/// Returns the MidiEvent tickPerBeat as Float with swing time forin the current swing setting.
/// Changing during playback in the sequencer engine, you would hear a drummer play more relaxed, for example.
/// @param n Int Setting to use a for swing
-(float)getQuantizedTimeForSetting:(int)n{
switch (n) {
case 0:
return quantizedTime.closest_for_setting_0;
break;
case 1:
return quantizedTime.closest_for_setting_1;
break;
case 2:
return quantizedTime.closest_for_setting_2;
break;
case 3:
return quantizedTime.closest_for_setting_3;
break;
case 4:
return quantizedTime.closest_for_setting_4;
break;
case 5:
return quantizedTime.closest_for_setting_5;
break;
case 6:
return quantizedTime.closest_for_setting_6;
break;
case 7:
return quantizedTime.closest_for_setting_7;
break;
case 8:
return quantizedTime.closest_for_setting_8;
break;
case 9:
return quantizedTime.closest_for_setting_9;
break;
default:
return -100;
break;
}
}
/// Change MidiEvent and it's position of playback, the bar, the note on off display
/// @param beat Position of playback in simple 16/th beat
/// @param barNumber Int that stores the bar of playback time
/// @param timeExact Swing setting as in where 0 is exact playback time and 7 is late
-(void)setBeatPosition__0First_15ForLast:(int)beat andBar:(int)barNumber andTimeExact0__to_late7:(int)timeExact{
[self setBeatPosition_0First_15ForLast:[ NSNumber numberWithInt:beat]];
[self setTimeExact0__to_late7:[ NSNumber numberWithInt:timeExact]];
[self setBar: barNumber ];
}
/// Set bar in beat to play event
/// @param n Bar number to play the event at
-(void)setBar:(int)n{
[self setMidiBar:[ NSNumber numberWithInt:n]];
}
/// Set Quantization offset
/// @param n quantize number as Int
/// @param ev time in ticks of event
-(void) setQuantizeNumber:(int)n withTime:(float)ev{
switch (n) {
case 0:
quantizedTime.closest_for_setting_0 = ev;
break;
case 1:
quantizedTime.closest_for_setting_1= ev;
break;
case 2:
quantizedTime.closest_for_setting_2= ev;
break;
case 3:
quantizedTime.closest_for_setting_3= ev;
break;
case 4:
quantizedTime.closest_for_setting_4= ev;
break;
case 5:
quantizedTime.closest_for_setting_5= ev;
break;
case 6:
quantizedTime.closest_for_setting_6= ev;
break;
case 7:
quantizedTime.closest_for_setting_7= ev;
break;
case 8:
quantizedTime.closest_for_setting_8= ev;
break;
case 9:
quantizedTime.closest_for_setting_9= ev;
break;
}
}
/// Sets note on
-(void)setNoteOn{
[self setOn:[ NSNumber numberWithBool:YES]];
}
/// Sets note off
-(void)setNoteOff{
[self setOn:[ NSNumber numberWithBool:YES]];
}
/// Triggers a stop event when played if this is enabled
/// @param n set if enabled
-(void)shouldTriggerStop:(BOOL)n{
[self setOn:[ NSNumber numberWithBool:YES]];
[self setTriggerStop:[ NSNumber numberWithBool:n]];
}
/// Deallocate objects
-(void)dealloc{
[ on release];
[ triggerPlay release];
[ triggerStop release];
[ didPlay release];
[ midiVelocity release];
[ beatPosition_0First_15ForLast release];
[ timeExact0__to_late7 release];
[ midiBar release];
[ midiNote release];
[ midiChan release];
[ eventTimeInTicks release];
[super dealloc];
}
/// Sets note on/off
/// @param Set note on or off
-(void)setOn1_off0__other2:(int)n{
if(n == 1){
[self setOn:[ NSNumber numberWithBool:YES]];
[self setTriggerPlay:[ NSNumber numberWithBool:YES]];
[self setTriggerStop:[ NSNumber numberWithBool:NO]];
}
else if(n == 0){
[self setOn:[ NSNumber numberWithBool:YES]];
[self setTriggerPlay:[ NSNumber numberWithBool:NO]];
[self setTriggerStop:[ NSNumber numberWithBool:YES]];
}
else if(n == 2){
[self setOn:[ NSNumber numberWithBool:YES]];
[self setTriggerPlay:[ NSNumber numberWithBool:NO]];
[self setTriggerStop:[ NSNumber numberWithBool:NO]];
}
}
/// Get NoteOn,NoteOff or Other value
-(int)getOn1_off0__other2{
int result;
if(triggerPlay.boolValue == YES && triggerStop.boolValue ==NO){
result =1 ;
}
else if(triggerPlay.boolValue == NO && triggerStop.boolValue ==YES){
result =0;
}
else if(triggerPlay.boolValue == NO && triggerStop.boolValue ==NO){
result =2;
}
return result;
}
/// Compare another event to see if it is equal
/// @param midi other event
-(BOOL)isEqual:(MidiEvent*)midi{
BOOL result = NO;
if(
on == [midi on] &&
triggerPlay == [midi triggerPlay] &&
triggerStop == [midi triggerStop] &&
didPlay == [midi didPlay] &&
midiVelocity == [midi midiVelocity] &&
beatPosition_0First_15ForLast == [midi beatPosition_0First_15ForLast] &&
timeExact0__to_late7 == [midi timeExact0__to_late7] &&
midiBar == [midi midiBar] &&
midiNote == [midi midiNote] &&
midiChan == [midi midiChan] &&
eventTimeInTicks == [midi eventTimeInTicks]
)result = YES;
return result;
}
/// Copy another midi event
/// @param midi another midi event
-(void)copyEvent:(MidiEvent*)midi{
on = [NSNumber numberWithBool:[midi on].boolValue];
triggerPlay = [NSNumber numberWithBool:[midi triggerPlay].boolValue];
triggerStop = [NSNumber numberWithBool:[midi triggerStop].boolValue];
didPlay = [NSNumber numberWithBool:YES] ;
midiVelocity = [ NSNumber numberWithFloat: [midi midiVelocity].floatValue] ;
beatPosition_0First_15ForLast =[NSNumber numberWithInt: [midi beatPosition_0First_15ForLast].intValue] ;
timeExact0__to_late7 = [NSNumber numberWithInt: [midi timeExact0__to_late7].intValue] ;
midiBar = [NSNumber numberWithInt: [midi midiBar] .intValue];
midiNote = [NSNumber numberWithInt: [midi midiNote].intValue] ;
midiChan = [NSNumber numberWithInt: [midi midiChan].intValue];
eventTimeInTicks =[NSNumber numberWithInt: [midi eventTimeInTicks].intValue ] ;
quantizedTime = [midi quantizedTime];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment