I am working with the MusicPlayer API and I am trying to solve a problem I am having with user callback.
I have user events that are placed at every note event of a MIDI. When the notes are played, these user events pass the integer value of the note to a user callback function as *inEventData:
void noteUserCallback (void *inClientData, MusicSequence inSequence, MusicTrack inTrack, MusicTimeStamp inEventTime, const MusicEventUserData *inEventData, MusicTimeStamp inStartSliceBeat, MusicTimeStamp inEndSliceBeat)
{
UserEvent* event = (UserEvent *)inEventData;
UInt32 size = event->length;
UInt32 note = event->playedNote;
UInt32 timestamp = event->tStamp;
NSLog(@"Size: %lu Note: %lu, Timestamp: %lu", size, note, timestamp);
switch (note) {
case 60:
[whiteKey60 setImage:highlightA];
break;
default:
break;
}
}
Based upon these notes, I would like to makes changes to the UI. Namely, I have a number of UIImageViews that I would like to be able to update with different images based upon the value of the note (see above in switch statement).
The user callback function is associated with the sequence like this:
MusicSequenceSetUserCallback(sequence, noteUserCallback, NULL);
The third parameter of the above function connected with the void *inClientData parameter of the user callback function.
My problem is, that when I try to access the IBOutlets of my view from within the user callback function, I cannot. To fix this, I tried to pass the view controller into the MusicSequenceSetUserCallback function like this:
MusicSequenceSetUserCallback(sequence, noteUserCallback, self);
The problem I am having is that this inClientData parameter is of type void and I cannot pass in a ViewController* object. I tried simply creating a bridge when I set the callback function and then bridging back again within the user callback function but it didn’t seem to work.
If anyone has any thoughts on how I could accomplish this. Even if it’s a completely different methods, I would really appreciate it.
Thanks.
EDIT
I tried the following:
MusicSequenceSetUserCallback(sequence, noteUserCallback, (__bridge_retained void *)self);
and
void noteUserCallback (void *inClientData, MusicSequence inSequence, MusicTrack inTrack, MusicTimeStamp inEventTime, const MusicEventUserData *inEventData, MusicTimeStamp inStartSliceBeat, MusicTimeStamp inEndSliceBeat)
{
PracticeViewController* pvc = (__bridge_transfer PracticeViewController *)inClientData;
[pvc.whiteKey21 setImage:pvc.highlightA];
UserEvent* event = (UserEvent *)inEventData;
UInt32 size = event->length;
UInt32 note = event->playedNote;
UInt32 timestamp = event->tStamp;
NSLog(@"Size: %lu Note: %lu, Timestamp: %lu", size, note, timestamp);
switch (note) {
case 60:
break;
default:
break;
}
}
Unfortunately, it gives me this error: Thread 13 AURemoteIO::IOThread: EXC_BAD_ACCESS (code=2, address=0x10)
EDIT
Changing both bridges to __bridge silences the error but it is still not working properly; the call to change in the image in whiteKey60 does not work. It isn’t a problem with the UIImageView connection because doing the same in viewDidLoad works fine.
What seems to be going on, to me anyways, is that self isn’t making it to the function or perhaps its breaking the connection when it’s passed?
Take a look at the declaration for MusicSequenceSetUserCallback again:
inClientData‘s type isn’tvoid— that wouldn’t make sense, variables in C can never have a type ofvoid. Rather, it’svoid *— roughly, a pointer to something unspecified.You need to cast the variable to a
void *on the way in, and from avoid *on the way out. Assuming thatselfis aMyClass *, then:and in the callback: