如何将sysex数据添加到MusicTrack? (AudioToolbox)

时间:2014-05-07 13:58:08

标签: ios c midi audiotoolbox sysex

我正在尝试用二十一点等编写我的小midi音序器,但坚持将sysex数据写入MusicTrack。我使用以下代码插入sysex事件

// ---- Some code here --- //

PatternData pattern = { sizeof(PatternData), i, signature.numerator, signature.denominator };
CABarBeatTime beattime = CABarBeatTime((i * signature.numerator * signature.denominator) + 1, 1, 0, SUBBEAT_DIVISOR_DEFAULT);
// Convert beattime to timestamp 
if ((MusicSequenceBarBeatTimeToBeats(sequence, &beattime, &timestamp)) != noErr) 
{
return status; 
} 
// Add event 
if ((status = MusicTrackNewMIDIRawDataEvent(track, timestamp, (MIDIRawData*)&pattern)) != noErr) 
{ 
return status; 
}

// ---- Some code here --- //

PatternData是

typedef struct PatternData 
{ 
UInt32 length; // Struct length 
UInt8 index; // Pattern index 
UInt8 bars; // Number of bars in patten 
UInt8 beats; // Number of beats in pattern 
} PatternData;

我做错了,因为在调用MusicSequenceFileCreate后我得到了损坏的文件。 有人有一个如何将sysex数据添加到音乐曲目的示例吗?

2 个答案:

答案 0 :(得分:0)

确定。我找到了正确的方法,就是这样:

    UInt8 data[] = { 0xF0, manufacturerId, databyte1, databyte2, databyte3, 0xF7 };
    MIDIRawData raw;
    memcpy(raw.data, data, 0, sizeof(data));
    raw.length = sizeof(data);

    if ((status = MusicTrackNewMIDIRawDataEvent(track, timestamp, &raw)) != noErr)
    {
        return status;
    }

答案 1 :(得分:0)

这是一个例子,如何在MIDI轨道中录制普通的MIDI和SYSEX消息,并将它们保存在共享iTunes文件夹中的MIDI文件中(设置"应用程序支持iTunes文件共享"到&#34 ;是"在.plist中): 特别见" calloc"在代码!!

#import "ViewController.h"
#import <CoreMIDI/MIDIServices.h>
#import <CoreMIDI/CoreMIDI.h>
#import "AppDelegate.h"
#include <sys/time.h>
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#import <AVFoundation/AVFoundation.h>

@interface ViewController ()

@end

@implementation ViewController

@synthesize SYSEX_8;

long secTempA = 0;
float secTempB = 0;
long secStartA = 0;
float secStartB = 0;
MusicTimeStamp timeStamp = 0;
MusicSequence recordSequence;
MusicTrack recordTrack;
MusicTimeStamp lenRec = 0;
MIDINoteMessage noteMessage;
MusicTrack track;
NSString *fileNameForSave = @"";
NSString *midiFileWritePath = @"";
NSString *documentsDirectoryPath = @"";
UIAlertView *infoStore;
UIAlertView *infoStoreError;
MIDIRawData *sysexData;

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    // Get documents Directory
    // (don't forget the ".plist" entry "Application supports iTunes file sharing YES"
    NSArray *pathDocDir = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    documentsDirectoryPath = [pathDocDir objectAtIndex:0];

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (IBAction)SYSEX_8_touchdown:(id)sender { 
    NewMusicSequence(&recordSequence);
    MusicSequenceNewTrack(recordSequence, &recordTrack);
    MusicSequenceSetSequenceType(recordSequence, kMusicSequenceType_Beats);

    timeStamp = 0;
    struct timeval time;
    gettimeofday(&time, NULL);
    secStartA = time.tv_sec;
    secStartB = time.tv_usec * 0.000001;

    noteMessage.channel = 0x90; // Note ON 
    noteMessage.note = 0x3C;
    noteMessage.velocity = 0x7F;
    MusicTrackNewMIDINoteEvent(recordTrack, timeStamp, &noteMessage);
    NSLog(@"%02x %02x %02x", 0x90, 0x3C, 0x7F);

    usleep(10000);

    gettimeofday(&time, NULL);
    secTempA = time.tv_sec;
    secTempB = time.tv_usec * 0.000001;
    secTempA = secTempA - secStartA;
    secTempB = secTempB - secStartB;
    timeStamp = (secTempA + secTempB) * 2;

    noteMessage.channel = 0x90; // Note OFF
    noteMessage.note = 0x3C;
    noteMessage.velocity = 0x00;
    MusicTrackNewMIDINoteEvent(recordTrack, timeStamp, &noteMessage);
    NSLog(@"%02x %02x %02x", 0x90, 0x3C, 0x00);

    usleep(100000);

    gettimeofday(&time, NULL);
    secTempA = time.tv_sec;
    secTempB = time.tv_usec * 0.000001;
    secTempA = secTempA - secStartA;
    secTempB = secTempB - secStartB;
    timeStamp = (secTempA + secTempB) * 2;

    Byte datatest[8];
    UInt32 theSize = offsetof(MIDIRawData, data[0]) + (sizeof(UInt8) * sizeof(datatest));
    sysexData = (MIDIRawData *)calloc(1, theSize);
    sysexData->length = sizeof(datatest);

    datatest[0] = 0xF0;  // Start SYSEX
    datatest[1] = 0x26;
    datatest[2] = 0x79;
    datatest[3] = 0x0E;
    datatest[4] = 0x00;
    datatest[5] = 0x00;
    datatest[6] = 0x00;
    datatest[7] = 0xF7;  // End SYSEX

    for (int j = 0; j < sizeof(datatest); j++) {
        sysexData->data[j] = datatest[j];
        NSLog(@"%02x", sysexData->data[j]);
    }

    int status;
    if ((status = MusicTrackNewMIDIRawDataEvent(recordTrack, timeStamp, sysexData) != noErr)) {
        NSLog(@"error %i", status);
    }
    else {
        [self stopRecording];
    }
}

- (void) stopRecording {

    CAShow(recordSequence);  // To show all MIDI events !!!

    UInt32 sz = sizeof(MusicTimeStamp);
    lenRec = 0;
    MusicSequenceGetIndTrack(recordSequence, 0, &track);
    MusicTrackGetProperty(track, kSequenceTrackProperty_TrackLength, &lenRec, &sz);

    if (lenRec > 0.1){
        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
        [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss +zzzz"];
        NSDate *startDate = [NSDate date];

        NSTimeZone *zone = [NSTimeZone systemTimeZone];
        NSInteger interval = [zone secondsFromGMTForDate:startDate];
        startDate = [startDate dateByAddingTimeInterval:interval];
        //    NSLog(@"Date: %@", startDate);

        NSString *strDate = [[NSString alloc] initWithFormat:@"%@", startDate];
        NSArray *arr = [strDate componentsSeparatedByString:@" "];
        NSString *str;
        str = [arr objectAtIndex:0];
        NSArray *arr_date = [str componentsSeparatedByString:@"-"];

        int year = [[arr_date objectAtIndex:0] intValue];
        int month = [[arr_date objectAtIndex:1] intValue];
        int day = [[arr_date objectAtIndex:2] intValue];

        str = [arr objectAtIndex:1];
        NSArray *arr_time = [str componentsSeparatedByString:@":"];

        int hours = [[arr_time objectAtIndex:0] intValue];
        int minutes = [[arr_time objectAtIndex:1] intValue];
        int seconds = [[arr_time objectAtIndex:2] intValue];

        fileNameForSave = [NSString stringWithFormat:@"%@_%04d%02d%02d_%02d%02d%02d%@", @"$Record", year, month, day, hours, minutes, seconds, @".mid"];
        midiFileWritePath = [documentsDirectoryPath stringByAppendingPathComponent:fileNameForSave];

        infoStore = [[UIAlertView alloc]initWithTitle: @"Save as MIDI file ?"
                                              message: [NSString stringWithFormat:@"\n%@", fileNameForSave]
                                             delegate: self
                                    cancelButtonTitle: @"YES"
                                    otherButtonTitles: @"NO",nil];
        [infoStore show];  // rest siehe unten !!!!!
    }
    else {
        MusicSequenceDisposeTrack(recordSequence, track);
        DisposeMusicSequence(recordSequence);
    }

}

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(int)buttonIndex {
    // deletion code here
    if (alertView == infoStore) {
        if (buttonIndex == 0) {
            NSURL *midiURL = [NSURL fileURLWithPath:midiFileWritePath];
            OSStatus status = 0;
            status = MusicSequenceFileCreate(recordSequence, (__bridge CFURLRef)(midiURL), kMusicSequenceFile_MIDIType, kMusicSequenceFileFlags_EraseFile, 0);
            if (status != noErr) {
                infoStoreError = [[UIAlertView alloc]initWithTitle: @"Information"
                                                           message: [NSString stringWithFormat:@"\nError storing MIDI file in: %@", documentsDirectoryPath]
                                                          delegate: self
                                                 cancelButtonTitle: nil
                                                 otherButtonTitles:@"OK",nil];
                [infoStoreError show];
            }
        }
        MusicSequenceDisposeTrack(recordSequence, track);
        DisposeMusicSequence(recordSequence);
    }

}

@end