Вопрос

I am new to Objective C and I am trying to make an application that will play a midi file when a button is pressed. I also want it not respond to additional button presses while the file is playing. I made a custom button class and put this code (from a tutorial) into the .m file:

- (IBAction)MIDItest:(id)sender
{
    MusicSequence s;
    NewMusicSequence(&s);
    NSString *midiFilePath = [[NSBundle mainBundle]
                              pathForResource:@"eDom"
                              ofType:@"mid"];
    NSURL *midiFileURL = [NSURL fileURLWithPath:midiFilePath];
    MusicSequenceFileLoad(s, (__bridge CFURLRef)(midiFileURL), 0, 0);

    MusicPlayer p;
    NewMusicPlayer(&p);
    MusicPlayerSetSequence(p, s);
    MusicPlayerPreroll(p);
    MusicPlayerStart(p);

    MusicTrack t;
    MusicTimeStamp len;
    UInt32 sz = sizeof(MusicTimeStamp);
    MusicSequenceGetIndTrack(s, 1, &t);
    MusicTrackGetProperty(t, kSequenceTrackProperty_TrackLength, &len, &sz);

    while (1) {
        usleep (3 *1000 *1000);
        MusicTimeStamp now = 0;
        MusicPlayerGetTime(p, &now);
        if (now >= len)
            break;
    }

    MusicPlayerStop(p);
    DisposeMusicSequence(s);
    DisposeMusicPlayer(p);
}

However, when I press the button, nothing happens. I did set the button to be the custom class, so I think the problem is in the midi player code. Can anyone tell me what I have done wrong and how I can fix this?

Это было полезно?

Решение

There are a number of problems with that code. Using while (1) with usleep as a control structure is a very bad idea. It locks up the user interface for the duration of the midi file. My guess is that that is just some poor tutorial code meant to show how to use the MusicPlayer API but inadvertently showing a very bad way to implement it.

The right way to do this is to declare the MusicPlayer as a @property so that it persists for the life of the app (or however long it is needed) and set and remove MusicSequences as needed.

The specific problem with your code is that MusicTracks are zero based (header definition below) and you are asking for track 1, which I am guessing does not exist. An error is returned but you are not checking for it. All MusicPlayer functions return a result code and you should always check for them (or suffer blindly in debug hell ... ;-)

You check for error like this:

   OSStatus result = noErr;
   result =  MusicSequenceGetIndTrack(s, 1, &t);
   if (result) {[self printErrorMessage: @"MusicSequenceGetIndTrack" withStatus: result];}

The printErrorMessage function (included below) is just a convenience to be able to log strings and result codes easily.

As to why your code isn't working: if the track doesn't exist, its length is going to be zero and so your sleep code is not going to work and the method will exit immediately. You can check this with:

 printf(" len    %f\n", len);

The MusicPlayer API is very powerful and fun to work with but always check for error result codes (listed here) since will fail silently and you won't have a clue without them.


- (void) printErrorMessage: (NSString *) errorString withStatus: (OSStatus) result
{
    char str[20];
    // see if it appears to be a 4-char-code
    *(UInt32 *)(str + 1) = CFSwapInt32HostToBig(result);
    if (isprint(str[1]) && isprint(str[2]) && isprint(str[3]) && isprint(str[4])) {
        str[0] = str[5] = '\'';
        str[6] = '\0';
    } else
        // no, format it as an integer
        sprintf(str, "%d", (int)result);

    //  fprintf(stderr, "Error: %s (%s)\n", operation, str);


    NSLog (
           @"*** %@ error: %s\n",
           errorString,
           str
           );
}

/*!
    @function   MusicSequenceGetIndTrack
    @abstract   Get a track at the specified index
    @discussion Index is zero based. It will return kAudio_ParamError if index is not in the range: 0 < TrackCount
                The track count and accessors exclude the tempo track (which is treated as a special case)
    @param      inSequence      the sequence
    @param      inTrackIndex    the index
    @param      outTrack        the track at that index
*/
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top