------- oops. Just noticed that I sent my last reply to you directly, David, not to the list. Reposting... ---------
Hi David,
You know, I actually like your approach, the more I think about it... I did manage to get my iterator-based approach working, but it may be kind of clunky. I'll post it here, for anyone who might find a need for something similar (note that anyone wanting to use this should add all the necessary error handling -- I just slapped it together as a test).
- (void) updateTrackingOfPlayer:(MusicPlayer)aPlayer { UInt32 ntracks; MusicSequence sequence; MusicPlayerGetSequence(aPlayer, &sequence); MusicSequenceGetTrackCount(sequence, &ntracks); for (UInt32 i = 0; i < ntracks; ++i) { MusicTrack track; MusicSequenceGetIndTrack(sequence, i, &track); MusicEventIterator iter; NewMusicEventIterator(track, &iter); Boolean hasCurrentEvent; MusicEventIteratorSeek(iter, playerCurrentTime); MusicEventIteratorHasCurrentEvent(iter, &hasCurrentEvent); if (hasCurrentEvent) { MidiEventInfo info; MusicEventIteratorGetEventInfo(iter, &info.stamp, &info.type, (const void**)&info.data, &info.size);
NSLog(@"TRACK %lu: Playback time %f, event time %f...", i, playerCurrentTime, info.stamp); } } }
-- the variable variable "playerCurrentTime" is being updated by the polling mechanism (which calls this method). Seems to work okay, except that it posts the event every time the polling runs, which is really not ideal (could work around that easily enough, mind you).
Anyway, thanks for the suggestion. I may give your approach a try, since it should be easy enough to implement (I'm already "spooling" my GUI events when I hit playback, so writing them to a user track should be simple enough).
cheers,
J.
On 2012-02-28, at 7:58 AM, David Hicks wrote:
Hi James, The first
thing to note is that there arent too many of us MIDI
guys on the CoreAudio list. And, not totally coincidentally, Apple isnt
putting much effort into this end of their technology. When I did
my first OS X app, I didnt know about MusicSequence, and created my own
Note and Track classes. It appears that Apple forces separate tracks from
channels in loading SMFs, and my own data includes many multi-channel tracks,
and so this would have bugged me. Though now I see MusicTrackMerge... But Im
working on a new app and am thinking about using the technique I mentioned. Since
I have to analyze my tracks specifically to get Duration into my Note instances
anyway, I think it wouldnt cost much to create a method that returns an
array of all Notes, with durations, and another that adds UserEvents (and
replaces NoteOn and NoteOff events with extendedNoteEvents??) to a track. And, if I
put the UserEvents in ahead of the (extendedNote) events, I could consult UI-generated
changes (velocity, pitch) and change the note events (especially
extendedNoteEvents, with duration!) on the fly, in the track, by using
MusicTrackClear and AddNewExtendedNoteEvent. Id be jammin! Well, good
luck! David
Hi David,
Thanks for the tip. I had thought of using the user
event/SequenceCallback system, but was kind of hoping somebody out there had
some alternative magic! It just seems like a very fussy way to go about
something that should be quite simple; i.e., adding events that are already all
in the sequence, and are thus entirely redundant. I can see that this probably
isn't a common request, but I know there have been plenty of posts here in the
past by people wanting to "track" events during playback, which is
basically what I'm trying to do. I wish Apple would add a simpler way...
I was wondering whether there might be a way to use the
MusicEventIterator. For example, starting the iterator when MusicPlayer is
started, then using MusicEventIteratorNextEvent to grab the coming event. I'd
just store it until MusicPlayerGetTime (which I'd have to poll) returns a value
greater than the event's time. It wouldn't be perfect, since the timing would
depend on the poll rate, but the function I'm writing doesn't actually need
perfect timing, it just needs to know what it's playing at any given time, so
it can "think ahead", so to speak.
I'll look into both options, but if anybody has any other tricks
they've used, I'd love to hear them.
On 2012-02-28, at 6:47 AM, David Hicks
wrote:
James,
I
havent done this, but it looks like it would work. If youre
willing to fiddle with the events in your tracks, you could do this by adding
UserEvents to a MusicSequences MusicTracks (at the same timestamps as
your NoteOn events). If you analyze the track before playback and know the
durations, you could add the duration info to these UserEvents. Then, with a
SequenceCallback registered, you will get alerted at every UserEvent with your
duration Info. See MusicSequence & MusicTrack references.
David
MusicSequenceSetUserCallbackRegisters
a user callback function with a music sequence.
OSStatus MusicSequenceSetUserCallback (
MusicSequence inSequence,
MusicSequenceUserCallback inCallback,
void *inClientData
);
ParametersinSequence
The music sequence
that you want to add a user callback function to. inCallback
A reference to your
callback function. Use NULL to remove a registered callback function. inClientData
Your data that the
music sequence provides back to your callback function when it is invoked.
Return
ValueA result code.
DiscussionThe music sequence invokes your callback for each user
event added to any music track owned by the sequence. If there is a callback
registered, then UserEvents will be chased when MusicPlayerSetTime is called.
In that case the inStartSliceBeat and inEndSliceBeat will both be the same
value and will be the beat that the player is chasing to.
MusicTrackNewUserEventAdds an event of
type MusicEventUserData to a music track.
OSStatus MusicTrackNewUserEvent (
MusicTrack inTrack,
MusicTimeStamp inTimeStamp,
const MusicEventUserData *inUserData
);
I'm wondering if there's a good way to grab MusicPlayer events within
an application, during playback, **without** using a MIDI endpoint? I have a system that has to
"listen" to its own playback, but I don't want to use the actual MIDI endpoint, in order to avoid feedback
loops. Also, it would be great to be able to get the duration info, which I
wouldn't normally have in "live" playback (i.e., I don't know when a
note will end), but would have directly from the sequence/track. Any way to do
this?
------------------------------------------------------
Composer/Researcher/PhD
Candidate
------------------------------------------------------
Composer/Researcher/PhD
Candidate
------------------------------------------------------ James B. Maxwell Composer/Researcher/PhD Candidate
|