2014-04-14 20 views
6

Chào buổi tối. Tôi đang cố gắng để viết một người chơi midi đơn giản với chất lượng âm thanh ngân hàng. Đối mặt với vấn đề chơi các tập tin midi. Vấn đề là tất cả các bài hát của midi (trống, miếng đệm, bass, synth, vv) đều chơi, nhưng chúng chơi một nhạc cụ duy nhất. Tôi tìm thấy một giải pháp cho OS X bu Tôi cần một giải pháp cho iOS. Tôi có phải tạo ra cho mỗi âm thanh cụUnit with kAudioUnitSubType_Sampler?Phát tệp MIDI nhiều nhạc cụ IOS

Nhắc có thể thay đổi Công cụ trên kênh đã chọn trong thời gian thực? Làm thế nào nó có thể được thực hiện? Xin lỗi vì tiếng anh của tôi ((

Đây là mã của tôi, nó không hoạt động đúng cách:..

// Create a client 
MIDIClientRef virtualMidi; 
Check(MIDIClientCreate(CFSTR("Virtual Client"), 
         MyMIDINotifyProc, 
         NULL, 
         &virtualMidi)); 


// Create an endpoint 
MIDIEndpointRef virtualEndpoint; 
Check(MIDIDestinationCreate(virtualMidi, CFSTR("Virtual Destination"), MyMIDIReadProc, samplerUnit, &virtualEndpoint)); 

// Initialise the music sequence 
NewMusicSequence(&midiSequence); 

if (!midiFilePath) { 
    midiFilePath = [[NSBundle mainBundle] 
        pathForResource:@"carelesswhisper" 
        ofType:@"mid"]; 

} 
NSLog(@"midiFilePath %@", midiFilePath); 

// Create a new URL which points to the MIDI file 
NSURL * midiFileURL = [NSURL fileURLWithPath:midiFilePath]; 

MidiParser *midiParser = [[MidiParser alloc] init]; 
NSData *data = [NSData dataWithContentsOfFile:midiFilePath]; 
[midiParser parseData:data]; 
NSString *midiInfo = [midiParser log]; 
NSLog(@"midiInfo %@", midiInfo); 

MusicSequenceLoadFlags loadFlags = 0; 
loadFlags = kMusicSequenceLoadSMF_ChannelsToTracks; 
MusicSequenceFileLoad(midiSequence, (__bridge CFURLRef) midiFileURL, 0, loadFlags); 

// Initialise the music player 
NewMusicPlayer(&midiPlayer); 

// ************* Set the endpoint of the sequence to be our virtual endpoint 
MusicSequenceSetMIDIEndpoint(midiSequence, virtualEndpoint); 

if (!soundBankFilePath) { 
    soundBankFilePath = [[NSBundle mainBundle] pathForResource:@"SGM-V2.01-1" ofType:@"sf2"]; 
} 
NSLog(@"soundBankFilePath %@", soundBankFilePath); 

NSURL *presetURL = [NSURL fileURLWithPath:soundBankFilePath]; 

// Initialise the sound font 
AUSamplerInstrumentData bpdata; 
bpdata.fileURL = (__bridge CFURLRef) presetURL; 
bpdata.bankMSB = kAUSampler_DefaultMelodicBankMSB; 
bpdata.bankLSB = kAUSampler_DefaultBankLSB; 
bpdata.instrumentType = kInstrumentType_SF2Preset; 

// set the kAUSamplerProperty_LoadPresetFromBank property 
result = AudioUnitSetProperty(samplerUnit, 
           kAUSamplerProperty_LoadInstrument, 
           kAudioUnitScope_Global, 
           0, 
           &bpdata, 
           sizeof(bpdata)); 
MusicPlayerSetSequence(midiPlayer, midiSequence); 
// Called to do some MusicPlayer setup. This just 
// reduces latency when MusicPlayerStart is called 
// MusicPlayerPreroll(midiPlayer); 
// Starts the music playing 
MusicPlayerStart(midiPlayer); 

// Get length of track so that we know how long to kill time for 
MusicTrack track; 
MusicTimeStamp len; 
UInt32 sz = sizeof(MusicTimeStamp); 
MusicSequenceGetIndTrack(midiSequence, 1, &track); 
MusicTrackGetProperty(track, kSequenceTrackProperty_TrackLength, &len, &sz); 


while (1) { // kill time until the music is over 
    usleep (3 * 1000 * 1000); 
    MusicTimeStamp now = 0; 
    MusicPlayerGetTime (midiPlayer, &now); 
    if (now >= len) 
     break; 
} 

Trả lời

3

Tôi tìm thấy câu trả lời Đối với mỗi ca khúc trong chuỗi đòi hỏi một AUSampler riêng

EDITED: 1 Tháng Mười năm 2016. tôi xin lỗi vì câu trả lời dài.

có mã của tôi cho file midi chơi.

- (void)loadMidi:(NSString*)midiFilePath andSoundBank:(NSString*)soundBankFilePath { 

[self setupStereoStreamFormat]; 
[self createGraph]; 
Check(AUGraphInitialize (graph)); 
Check(AUGraphStart (graph)); 

// get URL midi file 
if (!midiFilePath) { 
    midiFilePath = [[NSBundle mainBundle] pathForResource:@"Ресницы" ofType:@"kar"]; 
} 
NSLog(@"midiFilePath %@", midiFilePath); 
NSURL * midiFileURL = [NSURL fileURLWithPath:midiFilePath]; 

// get URL SFbank 
if (!soundBankFilePath) { 
    soundBankFilePath = [[NSBundle mainBundle] pathForResource:@"SGM-V2.01-1" ofType:@"sf2"]; 
} 
NSLog(@"soundBankFilePath %@", soundBankFilePath); 
bankUrl = [NSURL fileURLWithPath:soundBankFilePath]; 

// create sequence from midi 
sequence = 0; 

Check(NewMusicSequence(&sequence)); 
Check(MusicSequenceFileLoad (sequence, (__bridge CFURLRef)(midiFileURL), 0, 0)); 

MidiParser *parser = [[MidiParser alloc] init]; 
[parser parseData:[NSData dataWithContentsOfFile:midiFilePath]]; 
NSLog(@"PARSE MIDI %@", [parser log]); 
metaLyrics = [[NSMutableArray alloc] initWithArray:[parser syllableArray]]; 

// do not delete set sequense to graph 
Check(MusicSequenceSetAUGraph(sequence, graph)); 

[self getMidiNodesArray]; 

// read each track and set instruments & effects & volume for AUSamplers 
[self parseSequence]; 

CAShow(sequence); 
MusicTrack tempoTrack; 
MusicSequenceGetTempoTrack(sequence, &tempoTrack); 
NSDictionary *infoDict = (__bridge NSDictionary *)(MusicSequenceGetInfoDictionary(sequence)); 
float tempo = [[infoDict valueForKey:@"tempo"] floatValue]; 

CAShow(tempoTrack); 

NSLog(@"Tempo in sequence %f", tempo); 

// Load the sequence into the music player 
Check(NewMusicPlayer (&player)); 
// setup speed player 
Check(MusicPlayerSetPlayRateScalar(player, 1)); 
Check(MusicPlayerSetSequence(player, sequence)); 
Check(MusicPlayerSetTime(player, 0)); 
MusicPlayerPreroll(player); 
} 

Vì vậy, phân tích midi track mã:

- (void) parseSequence { 
// get numbers of tracks 
UInt32 numTracks; 
Check(MusicSequenceGetTrackCount(sequence, &numTracks)); 
NSLog(@"Number of tarcks %d", (unsigned int)numTracks); 

// mute some tracks if needed 
NSSet *mutedTracks = [NSSet setWithObjects: @"11", nil]; 

// mute unused channels 
NSLog(@"LOADING TRACKS"); 
for (UInt32 i = 0; i < numTracks; ++i) { 
    MusicTrack track; 
    MusicTimeStamp trackLength; 
    UInt32 propsize = sizeof(MusicTimeStamp); 
    Check(MusicSequenceGetIndTrack(sequence, i, &track)); 
    Check(MusicTrackGetProperty(track, kSequenceTrackProperty_TrackLength, 
           &trackLength, &propsize)); 
    // log track info if needed 
    CAShow(track); 
    MusicEventIterator myIterator; 
    MusicTimeStamp timeStamp; 
    MusicEventType eventType; 
    const void *refData = 0; 
    UInt32 dataSize; 

    Check(NewMusicEventIterator(track, &myIterator)); 
    Boolean hasCurrentEvent; 
    Check(MusicEventIteratorHasCurrentEvent (myIterator, &hasCurrentEvent)); 
    NSMutableSet *instrumentsSet = [[NSMutableSet alloc] init]; 
    int noActions = 0; 

    while (hasCurrentEvent) { 
     MusicEventIteratorGetEventInfo(myIterator, &timeStamp, &eventType, &refData, &dataSize); 


     if (eventType == 7) { 
      NSData *dataChaunk = [[NSData alloc] initWithBytes:refData length:dataSize]; 
      void *channelByte_0 = 0; 
      void *channelByte_1 = 0; 
      void *channelByte_2 = 0; 
      void *channelByte_3 = 0; 

      [dataChaunk getBytes:&channelByte_0 range:NSMakeRange(0, 1)]; 
      [dataChaunk getBytes:&channelByte_1 range:NSMakeRange(1, 1)]; 
      [dataChaunk getBytes:&channelByte_2 range:NSMakeRange(2, 1)]; 
      [dataChaunk getBytes:&channelByte_3 range:NSMakeRange(3, 1)]; 
      Byte command = (int)channelByte_0; 


      if (command < 208 && command >= 192) { 
       // setup track on AUsampler 
       if (![instrumentsSet containsObject:[NSString stringWithFormat:@"%d",(command & 0xf)]]) { 
        [self setDestNode:(command & 0xf) forTrack:track]; 
        [self setInstrumentMSB:(int)channelByte_1 presetLSB:0 trackID:(command & 0xf)]; 
       } 
       [instrumentsSet addObject:[NSString stringWithFormat:@"%d",(command & 0xf)]]; 

      } else if (command <192 && command >= 176){ 
       switch ((NSInteger)channelByte_1) { 
        case 0: // bank select MSB 
         NSLog(@"CHANNEL %d CONTROLLER 0xB bankMSB value %d", command & 0xf, (int)channelByte_2); 
         break; 
        case 7: // chanell volume 
         [self setVolume:(int)channelByte_2 inChannel:(command & 0xf)]; 
         break; 
        case 10: // pan 
         [self setPan:(int)channelByte_2 inChannel:(command & 0xf)]; 
         break; 
        case 32: // bank select LSB 
         NSLog(@"CHANNEL %d CONTROLLER 0xB bankLSB value %d", command & 0xf, (int)channelByte_2); 
         break; 
        case 94: 
         NSLog(@"CHANNEL %d CONTROLLER 0xB setEffect value %d", command & 0xf, (int)channelByte_2); 
         break; 


        default: 
         break; 
       } 
      } else 

       noActions++; 
     } 
     // do work here 
     MusicEventIteratorNextEvent (myIterator); 
     MusicEventIteratorHasCurrentEvent (myIterator, &hasCurrentEvent); 
    } 
    NSLog(@"No actions count %d", noActions); 


    if ([mutedTracks count] > 0 && [mutedTracks containsObject:[NSString stringWithFormat:@"%d", (unsigned int)i]]) 
    { 
     Boolean mute = true; 
     Check(MusicTrackSetProperty(track, kSequenceTrackProperty_MuteStatus, &mute, sizeof(mute))); 
     printf ("played tracks %u\n", (unsigned int)i); 
    } 
    instrumentsSet = nil; 
} 


UInt32 nodeInd = [[midiNodesArray objectAtIndex:9] intValue]; 
NSLog(@"setPercussionBankMSB %d for %d track %d node", 1, 9, (unsigned int)nodeInd); 
AUNode node; 
AudioUnit unit; 
Check(AUGraphGetIndNode(graph, nodeInd, &node)); 
Check(AUGraphNodeInfo(graph, node, 0, &unit)); 


AUSamplerInstrumentData bpdata; 
bpdata.fileURL = (__bridge CFURLRef) bankUrl; 
bpdata.bankMSB = kAUSampler_DefaultPercussionBankMSB; 
bpdata.bankLSB = kAUSampler_DefaultBankLSB; 
bpdata.instrumentType = kInstrumentType_SF2Preset; 
bpdata.presetID = (UInt8) 1; 
Check(AudioUnitSetProperty (unit, 
          kAUSamplerProperty_LoadInstrument, 
          kAudioUnitScope_Global, 0, 
          &bpdata, sizeof(bpdata))); 

[self setVolume:20 inChannel:0]; 
} 

Nhận track midi từ biểu đồ:

- (void) getMidiNodesArray { 
UInt32 nodeCount; 
Check(AUGraphGetNodeCount (graph, &nodeCount)); 
AudioUnit outSynth; 

if (!midiNodesArray) { 
    midiNodesArray = [[NSMutableArray alloc] init]; 
} 

for (UInt32 i = 0; i < nodeCount; ++i) 
{ 
    AUNode node; 
    Check(AUGraphGetIndNode(graph, i, &node)); 

    AudioComponentDescription desc; 
    Check(AUGraphNodeInfo(graph, node, &desc, 0)); 

    if (desc.componentSubType == kAudioUnitSubType_Sampler) { 
     Check(AUGraphNodeInfo(graph, node, 0, &outSynth)); 
     [midiNodesArray addObject:[NSString stringWithFormat:@"%d", (unsigned int)i]]; 
    } 
} 
} 
+0

Xin chào, vì vậy làm thế nào bạn quản lý để tách các track và gán mỗi một đến một AUSampler khác nhau ?? Tôi đã cố gắng tìm ra điều này trong những giờ qua> _ < – Hazneliel

+0

Tạo số lượng nhạc cụ midi mong muốn -> AudioUnit midiUnit_0, midiUnit_1, midiUnit_2, midiUnit_3, midiUnit_4, midiUnit_5; Định cấu hình biểu đồ -> Kiểm tra (AUGraphConnectNodeInput (biểu đồ, midiNode_0, 0, mixerNode, 0)); Kiểm tra (AUGraphConnectNodeInput (đồ thị, midiNode_1, 0, mixerNode, 1)); Kiểm tra (AUGraphConnectNodeInput (biểu đồ, midiNode_2, 0, mixerNode, 2)); Kiểm tra (AUGraphConnectNodeInput (đồ thị, midiNode_3, 0, mixerNode, 3)); Kiểm tra (AUGraphConnectNodeInput (biểu đồ, midiNode_4, 0, mixerNode, 4)); Kiểm tra (AUGraphConnectNodeInput (đồ thị, midiNode_5, 0, mixerNode, 5)); – John

+0

Xin chào John Tôi đang cố gắng làm điều tương tự nhưng không thành công. Bạn có thể trợ giúp bằng cách cung cấp phần còn lại của mã không? Ví dụ: phương thức "NewMusicSequence" và "NewMusicPlayer". Cảm ơn rất nhiều –

Các vấn đề liên quan