2014-04-14 17 views
6

İyi akşamlar. Kaliteli ses bankası ile basit bir midi oyuncu yazmaya çalışıyorum. Midi dosyalarını oynatma sorunu ile karşı karşıya. Sorun şu ki midi (davul, ped, bas, synth vb) tüm parçaları çaldı, ama tek bir enstrüman çalıyorlar. OS X için bir çözüm buldum iOS için bir çözüme ihtiyacım var. kAudioUnitSubType_Sampler ile her bir Instrument audioUnit için oluşturmam gerekecek mi?Çok enstrümanlı MIDI dosyasını oynatın IOS

Seçilen kanaldaki Enstrümanı gerçek zamanlı olarak değiştirmek mümkün mü? Nasıl uygulanabilir? .. Ingilizcem ((Burada

düzgün çalışmıyor, benim kodudur için üzgünüm:

// 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; 
} 

cevap

3

ben cevap buldu sırayla her parça için ayrı bir AUSampler gerektirir

EDITED: 1 Ekim 2016 uzun cevap için üzgünüm.

oyun midi dosyası için benim kod yoktur.

- (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); 
} 
- (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]; 
} 

grafikten midi parçaları al:Yani midi parçaları kodu ayrıştırmak

- (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

Merhaba, bu yüzden nasıl parçalarını ayırmak ve farklı bir AUSampler her birini atamak için yönetilen vermedi ?? Son saatlerde bunu anlamaya çalışıyorum> _ < – Hazneliel

+0

İstenen sayıda midi enstrümanı oluşturun -> AudioUnit midiUnit_0, midiUnit_1, midiUnit_2, midiUnit_3, midiUnit_4, midiUnit_5; Grafiği Yapılandır -> Denetle (AUGraphConnectNodeInput (graph, midiNode_0, 0, mixerNode, 0)); Check (AUGraphConnectNodeInput (grafik, midiNode_1, 0, mikserNode, 1)); Check (AUGraphConnectNodeInput (grafik, midiNode_2, 0, mikserNode, 2)); Check (AUGraphConnectNodeInput (grafik, midiNode_3, 0, mikserNode, 3)); Check (AUGraphConnectNodeInput (grafik, midiNode_4, 0, mikserNode, 4)); Check (AUGraphConnectNodeInput (grafik, midiNode_5, 0, mikserNode, 5)); – John

+0

Merhaba John Aynı şeyi yapmaya çalışıyorum ama başarıya ulaşamadım. Kodunuzun geri kalanını, örneğin "NewMusicSequence" ve "NewMusicPlayer" yöntemlerini vererek yardımcı olabilir misiniz? Çok teşekkürler –