Rev. | 8 |
---|---|
大小 | 29,624 字节 |
时间 | 2011-10-02 01:24:49 |
作者 | toshinagata1964 |
Log Message | Solo track capability is implemented. |
/*
MDSequence.c
Created by Toshi Nagata, 2000.11.24.
Copyright (c) 2000-2011 Toshi Nagata. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "MDHeaders.h"
#include <stdio.h> /* for sprintf() */
#include <stdlib.h> /* for malloc(), realloc(), and free() */
#include <string.h> /* for memset() */
#include <limits.h> /* for LONG_MAX */
#include <pthread.h> /* for mutex */
#ifdef __MWERKS__
#pragma mark ====== Private definitions ======
#endif
struct MDSequence {
long refCount; /* the reference count */
long timebase; /* the timebase */
long num; /* the number of tracks (including the conductor track) */
unsigned char single; /* non-zero if single channel mode */
MDArray * tracks; /* the array of tracks (the 0-th is the conductor track) */
MDCalibrator * calib; /* the first MDCalibrator related to this sequence */
MDMerger * merger; /* the first MDMerger related to this sequence */
pthread_mutex_t *mutex; /* the mutex for lock/unlock */
};
/* A private struct for MDMerger */
typedef struct MDMergerInfo {
MDTrack * track;
MDPointer * ptr;
MDEvent * eptr;
MDTickType tick;
MDTickType lastTick;
} MDMergerInfo;
struct MDMerger {
long refCount;
MDSequence * sequence;
MDMerger * next;
long currentTrack;
MDEvent * eptr;
MDTickType tick;
MDArray *info; // MDMergerInfo の array
};
#ifdef __MWERKS__
#pragma mark -
#pragma mark ====== MDSequence functions ======
#endif
#ifdef __MWERKS__
#pragma mark ====== New/Retain/Release ======
#endif
/* --------------------------------------
・ MDSequenceNew
-------------------------------------- */
MDSequence *
MDSequenceNew(void)
{
MDSequence *newSequence = (MDSequence *)malloc(sizeof(*newSequence));
if (newSequence == NULL)
return NULL; /* out of memory */
memset(newSequence, 0, sizeof(MDSequence));
newSequence->num = 0;
newSequence->refCount = 1;
newSequence->timebase = 480;
newSequence->tracks = MDArrayNew(sizeof(MDTrack *));
if (newSequence->tracks == NULL) {
free(newSequence);
return NULL;
}
newSequence->calib = NULL;
return newSequence;
}
/* --------------------------------------
・ MDSequenceRetain
-------------------------------------- */
void
MDSequenceRetain(MDSequence *inSequence)
{
inSequence->refCount++;
}
/* --------------------------------------
・ MDSequenceRelease
-------------------------------------- */
void
MDSequenceRelease(MDSequence *inSequence)
{
if (--inSequence->refCount == 0) {
MDSequenceClear(inSequence);
MDArrayRelease(inSequence->tracks);
/* Remove the MDCache's from the linked list */
/* while (inSequence->calib != NULL)
MDCacheSetSequence(inSequence->cache, NULL);
*/
free(inSequence);
}
}
/* --------------------------------------
・ MDSequenceClear
-------------------------------------- */
void
MDSequenceClear(MDSequence *inSequence)
{
MDTrack *track;
int i;
if (inSequence->num != 0) {
for (i = 0; i < inSequence->num; i++) {
track = MDSequenceGetTrack(inSequence, i);
if (track != NULL) {
MDTrackClear(track);
MDTrackRelease(track);
}
}
MDArrayEmpty(inSequence->tracks);
inSequence->num = 0;
}
}
#ifdef __MWERKS__
#pragma mark ====== MDCalibrator manipulations ======
#endif
static void
MDSequenceRemoveCalibratorForTrack(MDSequence *inSequence, MDTrack *inTrack)
{
MDCalibrator *calib;
int index;
MDTrack *track;
if (inSequence == NULL || inTrack == NULL)
return;
for (calib = inSequence->calib; calib != NULL; calib = MDCalibratorNextInList(calib)) {
index = 0;
while (MDCalibratorGetInfo(calib, index, &track, NULL, NULL) == kMDNoError) {
if (track == inTrack) {
MDCalibratorRemoveAtIndex(calib, index);
} else index++;
}
}
}
void
MDSequenceAttachCalibrator(MDSequence *inSequence, MDCalibrator *inCalib)
{
if (inSequence == NULL || inCalib == NULL)
return;
MDCalibratorSetNextInList(inCalib, inSequence->calib);
inSequence->calib = inCalib;
}
void
MDSequenceDetachCalibrator(MDSequence *inSequence, MDCalibrator *inCalib)
{
MDCalibrator *curr, *prev, *next;
if (inSequence == NULL || inCalib == NULL)
return;
curr = inSequence->calib;
prev = NULL;
next = MDCalibratorNextInList(inCalib);
while (curr != NULL) {
if (curr == inCalib) {
if (prev == NULL) {
inSequence->calib = next;
} else {
MDCalibratorSetNextInList(prev, next);
}
break;
}
prev = curr;
curr = MDCalibratorNextInList(curr);
}
}
#ifdef __MWERKS__
#pragma mark ====== Accessor functions ======
#endif
/* --------------------------------------
・ MDSequenceSetTimebase
-------------------------------------- */
void
MDSequenceSetTimebase(MDSequence *inSequence, long inTimebase)
{
inSequence->timebase = inTimebase;
}
/* --------------------------------------
・ MDSequenceGetTimebase
-------------------------------------- */
long
MDSequenceGetTimebase(const MDSequence *inSequence)
{
return inSequence->timebase;
}
/* --------------------------------------
・ MDSequenceGetNumberOfTracks
-------------------------------------- */
long
MDSequenceGetNumberOfTracks(const MDSequence *inSequence)
{
return inSequence->num;
}
/* --------------------------------------
・ MDSequenceGetDuration
-------------------------------------- */
MDTickType
MDSequenceGetDuration(const MDSequence *inSequence)
{
MDTrack *track;
long n;
MDTickType duration, maxDuration;
maxDuration = 0;
for (n = inSequence->num - 1; n >= 0; n--) {
track = MDSequenceGetTrack(inSequence, n);
if (track != NULL) {
duration = MDTrackGetDuration(track);
if (duration > maxDuration)
maxDuration = duration;
}
}
return maxDuration;
}
/* --------------------------------------
・ MDSequenceGetTrack
-------------------------------------- */
MDTrack *
MDSequenceGetTrack(const MDSequence *inSequence, long index)
{
MDTrack *track;
if (MDArrayFetch(inSequence->tracks, index, 1, &track) == 1)
return track;
else return NULL;
}
#ifdef __MWERKS__
#pragma mark ====== MDTrack attribute manipulations ======
#endif
void
MDSequenceUpdateMuteBySoloFlag(MDSequence *inSequence)
{
MDTrack *track;
long n, solo;
MDTrackAttribute attr;
solo = 0;
for (n = inSequence->num - 1; n >= 0; n--) {
track = MDSequenceGetTrack(inSequence, n);
if (track != NULL) {
attr = MDTrackGetAttribute(track);
if (attr & kMDTrackAttributeSolo)
solo++;
}
}
for (n = inSequence->num - 1; n >= 0; n--) {
track = MDSequenceGetTrack(inSequence, n);
if (track != NULL) {
attr = MDTrackGetAttribute(track);
if (solo > 0)
attr = (attr & ~kMDTrackAttributeMuteBySolo) |
((attr & kMDTrackAttributeSolo) ? 0 : kMDTrackAttributeMuteBySolo);
else
attr = (attr & ~kMDTrackAttributeMuteBySolo);
MDTrackSetAttribute(track, attr);
}
}
}
/* --------------------------------------
・ MDSequenceSetRecordFlagOnTrack
-------------------------------------- */
int
MDSequenceSetRecordFlagOnTrack(MDSequence *inSequence, long index, int flag)
{
MDTrack *track;
long n;
MDTrackAttribute attr, newAttr;
if (index < 0 || index >= inSequence->num || (track = MDSequenceGetTrack(inSequence, index)) == NULL)
return 0;
attr = MDTrackGetAttribute(track);
if (flag < 0)
attr ^= kMDTrackAttributeRecord;
else {
newAttr = (attr & ~kMDTrackAttributeRecord) | (flag ? kMDTrackAttributeRecord : 0);
if (newAttr == attr)
return 0;
attr = newAttr;
}
MDTrackSetAttribute(track, attr);
if (attr & kMDTrackAttributeRecord) {
for (n = inSequence->num - 1; n >= 0; n--) {
if (n == index || (track = MDSequenceGetTrack(inSequence, n)) == NULL)
continue;
attr = MDTrackGetAttribute(track);
attr &= ~kMDTrackAttributeRecord;
MDTrackSetAttribute(track, attr);
}
}
return 1;
}
/* --------------------------------------
・ MDSequenceSetSoloFlagOnTrack
-------------------------------------- */
int
MDSequenceSetSoloFlagOnTrack(MDSequence *inSequence, long index, int flag)
{
MDTrack *track;
MDTrackAttribute attr, newAttr;
if (index < 0 || index >= inSequence->num || (track = MDSequenceGetTrack(inSequence, index)) == NULL)
return 0;
attr = MDTrackGetAttribute(track);
if (flag < 0)
attr ^= kMDTrackAttributeSolo;
else {
newAttr = (attr & ~kMDTrackAttributeSolo) | (flag ? kMDTrackAttributeSolo : 0);
if (attr == newAttr)
return 0;
attr = newAttr;
}
MDTrackSetAttribute(track, attr);
MDSequenceUpdateMuteBySoloFlag(inSequence);
return 1;
}
/* --------------------------------------
・ MDSequenceSetMuteFlagOnTrack
-------------------------------------- */
int
MDSequenceSetMuteFlagOnTrack(MDSequence *inSequence, long index, int flag)
{
MDTrack *track;
MDTrackAttribute attr, newAttr;
if (index < 0 || index >= inSequence->num || (track = MDSequenceGetTrack(inSequence, index)) == NULL)
return 0;
attr = MDTrackGetAttribute(track);
if (flag < 0)
attr ^= kMDTrackAttributeMute;
else {
newAttr = (attr & ~kMDTrackAttributeMute) | (flag ? kMDTrackAttributeMute : 0);
if (attr == newAttr)
return 0;
attr = newAttr;
}
MDTrackSetAttribute(track, attr);
return 1;
}
/* --------------------------------------
・ MDSequenceGetIndexOfRecordingTrack
-------------------------------------- */
long
MDSequenceGetIndexOfRecordingTrack(MDSequence *inSequence)
{
long index;
for (index = 0; index < inSequence->num; index++) {
MDTrack *track = MDSequenceGetTrack(inSequence, index);
if (track != NULL && (MDTrackGetAttribute(track) & kMDTrackAttributeRecord) != 0)
return index;
}
return -1;
}
#ifdef __MWERKS__
#pragma mark ====== MDTrack Insert/Delete ======
#endif
/* --------------------------------------
・ MDSequenceInsertTrack
-------------------------------------- */
long
MDSequenceInsertTrack(MDSequence *inSequence, long index, MDTrack *inTrack)
{
if (index < -1)
index = 0;
else if (index == -1 || index > inSequence->num)
index = inSequence->num;
if (MDArrayInsert(inSequence->tracks, index, 1, &inTrack) == kMDNoError) {
inSequence->num++;
MDTrackRetain(inTrack);
/* Check track attributes */
if (MDTrackGetAttribute(inTrack) & kMDTrackAttributeRecord)
MDSequenceSetRecordFlagOnTrack(inSequence, index, 1);
MDSequenceUpdateMuteBySoloFlag(inSequence);
return index;
} else return -1;
}
/* --------------------------------------
・ MDSequenceDeleteTrack
-------------------------------------- */
long
MDSequenceDeleteTrack(MDSequence *inSequence, long index)
{
MDTrack *track;
if (index < 0 || index >= inSequence->num)
return -1;
track = MDSequenceGetTrack(inSequence, index);
MDSequenceRemoveCalibratorForTrack(inSequence, track);
if (MDArrayDelete(inSequence->tracks, index, 1) == kMDNoError) {
inSequence->num--;
if (track != NULL)
MDTrackRelease(track);
MDSequenceUpdateMuteBySoloFlag(inSequence);
return index;
} else return -1;
}
/* --------------------------------------
・ MDSequenceReplaceTrack
-------------------------------------- */
long
MDSequenceReplaceTrack(MDSequence *inSequence, long index, MDTrack *inTrack)
{
long n;
if (index < 0 || index >= inSequence->num)
return -1;
n = MDSequenceDeleteTrack(inSequence, index);
if (n >= 0)
return MDSequenceInsertTrack(inSequence, index, inTrack);
else return n;
}
/* --------------------------------------
・ MDSequenceResetCalibrators
-------------------------------------- */
void
MDSequenceResetCalibrators(MDSequence *inSequence)
{
MDCalibrator *calib;
for (calib = inSequence->calib; calib != NULL; calib = MDCalibratorNextInList(calib)) {
MDCalibratorReset(calib);
}
}
#ifdef __MWERKS__
#pragma mark ====== Single/Multi channel mode ======
#endif
/* --------------------------------------
・ MDSequenceSingleChannelMode
-------------------------------------- */
MDStatus
MDSequenceSingleChannelMode(MDSequence *inSequence)
{
long n;
long nch[16];
MDStatus sts = kMDNoError;
if (inSequence == NULL)
return kMDNoError;
/* Pass 1: Separate multi-channel tracks */
for (n = inSequence->num - 1; n >= 0; n--) {
MDTrack *track, *ntrack[16];
MDPointer *pt;
MDPointSet *pset;
int nnch, i;
track = MDSequenceGetTrack(inSequence, n);
nnch = 0;
for (i = 0; i < 16; i++) {
nch[i] = MDTrackGetNumberOfChannelEvents(track, i);
if (nch[i] > 0)
nnch++;
}
if (nnch <= 1)
continue;
memset(ntrack, 0, sizeof(ntrack));
ntrack[0] = MDTrackNewFromTrack(track); /* Duplicate */
if (ntrack[0] == NULL)
return kMDErrorOutOfMemory;
pt = MDPointerNew(ntrack[0]);
pset = MDPointSetNew();
if (pt == NULL || pset == NULL)
return kMDErrorOutOfMemory;
for (i = 15; i >= 1; i--) {
MDEvent *ep;
if (nch[i] == 0)
continue;
MDPointerSetPosition(pt, -1);
MDPointSetClear(pset);
while ((ep = MDPointerForward(pt)) != NULL) {
if (MDIsChannelEvent(ep) && MDGetChannel(ep) == i) {
sts = MDPointSetAdd(pset, MDPointerGetPosition(pt), 1);
if (sts != kMDNoError)
break;
}
}
if (sts == kMDNoError)
sts = MDTrackUnmerge(ntrack[0], &ntrack[i], pset);
if (sts == kMDNoError) {
nnch--;
if (nnch == 1)
break;
} else break;
}
MDPointSetRelease(pset);
MDPointerRelease(pt);
if (sts == kMDNoError) {
for (i = 15; i >= 0; i--) {
if (ntrack[i] == NULL)
continue;
if (MDSequenceInsertTrack(inSequence, n + 1, ntrack[i]) < 0) {
sts = kMDErrorOutOfMemory;
break;
} else {
ntrack[i] = NULL;
}
}
}
if (sts == kMDNoError) {
MDSequenceDeleteTrack(inSequence, n);
} else {
/* Dispose all temporary objects and returns error */
for (i = 0; i < 16; i++) {
if (ntrack[i] != NULL)
MDTrackRelease(ntrack[i]);
}
return sts;
}
}
/* Pass 2: Remap all events to MIDI channel 0, and set the track channels */
for (n = inSequence->num - 1; n >= 0; n--) {
MDTrack *track;
int i, nnch;
unsigned char newch[16];
track = MDSequenceGetTrack(inSequence, n);
if (track == NULL)
continue;
memset(newch, 0, 16);
nnch = 0;
/* Sanity check */
for (i = 0; i < 16; i++) {
if (MDTrackGetNumberOfChannelEvents(track, i) > 0) {
MDTrackSetTrackChannel(track, i);
if (nnch++ > 0)
fprintf(stderr, "Warning: Internal inconsistency in function MDSequenceSingleChannelMode, file %s, line %d\n", __FILE__, __LINE__);
}
}
MDTrackRemapChannel(track, newch);
}
inSequence->single = 1;
return kMDNoError;
}
/* --------------------------------------
・ MDSequenceMultiChannelMode
-------------------------------------- */
MDStatus
MDSequenceMultiChannelMode(MDSequence *inSequence)
{
long n;
MDTrack *track;
unsigned char newch[16];
if (inSequence == NULL)
return kMDNoError;
memset(newch, 0, 16);
for (n = 0; n < inSequence->num; n++) {
track = MDSequenceGetTrack(inSequence, n);
if (track == NULL)
continue;
if (MDTrackGetNumberOfChannelEvents(track, -1) == 0)
continue;
newch[0] = MDTrackGetTrackChannel(track) & 15;
MDTrackRemapChannel(track, newch);
MDTrackSetTrackChannel(track, 0);
}
inSequence->single = 0;
return kMDNoError;
}
/* --------------------------------------
・ MDSequenceIsSingleChannelMode
-------------------------------------- */
int
MDSequenceIsSingleChannelMode(const MDSequence *inSequence)
{
if (inSequence != NULL)
return (inSequence->single != 0);
else return 0;
}
#ifdef __MWERKS__
#pragma mark ====== MDMerger manipulations ======
#endif
static void
MDSequenceAttachMerger(const MDSequence *inSequence, MDMerger *inMerger)
{
if (inSequence == NULL || inMerger == NULL)
return;
inMerger->next = inSequence->merger;
/* merger is a 'mutable' member, so this cast is acceptable */
((MDSequence *)inSequence)->merger = inMerger;
}
static void
MDSequenceDetachMerger(const MDSequence *inSequence, MDMerger *inMerger)
{
MDMerger *currRef, *prevRef;
if (inSequence == NULL || inMerger == NULL)
return;
currRef = inSequence->merger;
prevRef = NULL;
while (currRef != NULL) {
if (currRef == inMerger) {
if (prevRef == NULL) {
/* merger is a 'mutable' member, so this cast is acceptable */
((MDSequence *)inSequence)->merger = currRef->next;
} else {
prevRef->next = currRef->next;
}
break;
}
prevRef = currRef;
currRef = currRef->next;
}
}
#pragma mark ====== MDSequence Lock/Unlock ======
MDStatus
MDSequenceCreateMutex(MDSequence *inSequence)
{
int n;
if (inSequence == NULL)
return kMDErrorInternalError;
else if (inSequence->mutex != NULL)
return kMDErrorOnSequenceMutex;
else {
inSequence->mutex = (pthread_mutex_t *)calloc(sizeof(pthread_mutex_t), 1);
if (inSequence->mutex == NULL)
return kMDErrorOutOfMemory;
n = pthread_mutex_init(inSequence->mutex, NULL);
if (n != 0)
return kMDErrorOnSequenceMutex;
}
return kMDNoError;
}
MDStatus
MDSequenceDisposeMutex(MDSequence *inSequence)
{
int n;
if (inSequence == NULL || inSequence->mutex == NULL)
return kMDErrorInternalError;
n = pthread_mutex_destroy(inSequence->mutex);
free(inSequence->mutex);
inSequence->mutex = NULL;
if (n != 0)
return kMDErrorOnSequenceMutex;
else return kMDNoError;
}
void
MDSequenceLock(MDSequence *inSequence)
{
int n;
if (inSequence == NULL || inSequence->mutex == NULL)
return;
n = pthread_mutex_lock(inSequence->mutex);
}
void
MDSequenceUnlock(MDSequence *inSequence)
{
int n;
if (inSequence == NULL || inSequence->mutex == NULL)
return;
n = pthread_mutex_unlock(inSequence->mutex);
}
int
MDSequenceTryLock(MDSequence *inSequence)
{
int n;
if (inSequence == NULL || inSequence->mutex == NULL)
return 0;
n = pthread_mutex_trylock(inSequence->mutex);
if (n == 0)
return 0;
else if (n == EBUSY)
return 1;
else return -1;
}
#ifdef __MWERKS__
#pragma mark -
#pragma mark ====== MDMerger functions ======
#endif
/* --------------------------------------
・ MDMergerNew
-------------------------------------- */
MDMerger *
MDMergerNew(MDSequence *inSequence)
{
MDMerger *newMerger = (MDMerger *)malloc(sizeof(*newMerger));
if (newMerger == NULL)
return NULL; /* out of memory */
memset(newMerger, 0, sizeof(*newMerger));
newMerger->refCount = 1;
newMerger->sequence = NULL;
newMerger->next = NULL;
newMerger->currentTrack = 0;
newMerger->eptr = NULL;
newMerger->tick = -1;
newMerger->info = NULL;
if (inSequence != NULL)
MDMergerSetSequence(newMerger, inSequence);
return newMerger;
}
/* --------------------------------------
・ MDMergerRetain
-------------------------------------- */
void
MDMergerRetain(MDMerger *inMerger)
{
inMerger->refCount++;
}
/* --------------------------------------
・ MDMergerRelease
-------------------------------------- */
void
MDMergerRelease(MDMerger *inMerger)
{
long i, num;
if (--inMerger->refCount == 0) {
if (inMerger->info != NULL) {
num = MDArrayCount(inMerger->info);
for (i = 0; i < num; i++) {
MDMergerInfo info;
if (MDArrayFetch(inMerger->info, i, 1, &info) == 1) {
if (info.ptr != NULL)
MDPointerRelease(info.ptr);
if (info.track != NULL)
MDTrackRelease(info.track);
}
}
MDArrayRelease(inMerger->info);
}
if (inMerger->sequence != NULL) {
MDSequenceDetachMerger(inMerger->sequence, inMerger);
MDSequenceRelease(inMerger->sequence);
}
free(inMerger);
}
}
/* --------------------------------------
・ MDMergerDuplicate
-------------------------------------- */
MDMerger *
MDMergerDuplicate(const MDMerger *inSrc)
{
MDMergerInfo anInfo, aSrcInfo;
long n;
MDMerger *dest = MDMergerNew(NULL);
if (dest != NULL) {
dest->info = MDArrayNew(sizeof(MDMergerInfo));
if (dest->info == NULL) {
MDMergerRelease(dest);
return NULL;
}
for (n = MDArrayCount(inSrc->info) - 1; n >= 0; n--) {
if (MDArrayFetch(inSrc->info, n, 1, &aSrcInfo) == 1) {
anInfo.track = aSrcInfo.track;
MDTrackRetain(anInfo.track);
anInfo.ptr = MDPointerNew(anInfo.track);
MDPointerSetAutoAdjust(anInfo.ptr, 1);
MDPointerCopy(anInfo.ptr, aSrcInfo.ptr);
anInfo.eptr = aSrcInfo.eptr;
anInfo.tick = aSrcInfo.tick;
anInfo.lastTick = aSrcInfo.lastTick;
} else {
anInfo.track = NULL;
anInfo.ptr = NULL;
anInfo.eptr = NULL;
anInfo.tick = kMDMaxTick;
anInfo.lastTick = kMDNegativeTick;
}
MDArrayReplace(dest->info, n, 1, &anInfo);
}
dest->currentTrack = inSrc->currentTrack;
dest->eptr = inSrc->eptr;
dest->tick = inSrc->tick;
dest->sequence = inSrc->sequence;
if (dest->sequence != NULL) {
MDSequenceRetain(dest->sequence);
MDSequenceAttachMerger(dest->sequence, dest);
}
}
return dest;
}
/* --------------------------------------
・ MDMergerSetSequence
-------------------------------------- */
MDStatus
MDMergerSetSequence(MDMerger *inMerger, MDSequence *inSequence)
{
if (inMerger->sequence != inSequence) {
if (inMerger->sequence != NULL) {
MDSequenceDetachMerger(inMerger->sequence, inMerger);
MDSequenceRelease(inMerger->sequence);
}
inMerger->sequence = inSequence;
if (inSequence != NULL) {
MDSequenceRetain(inSequence);
MDSequenceAttachMerger(inSequence, inMerger);
}
MDMergerReset(inMerger);
}
return kMDNoError;
}
/* --------------------------------------
・ MDMergerGetSequence
-------------------------------------- */
MDSequence *
MDMergerGetSequence(MDMerger *inMerger)
{
return inMerger->sequence;
}
/* --------------------------------------
・ MDMergerReset
-------------------------------------- */
void
MDMergerReset(MDMerger *inMerger)
{
long num;
MDMergerInfo info;
if (inMerger == NULL || inMerger->sequence == NULL)
return;
if (inMerger->info == NULL) {
inMerger->info = MDArrayNew(sizeof(MDMergerInfo));
if (inMerger->info == NULL)
return;
} else {
num = MDArrayCount(inMerger->info);
while (--num >= 0) {
if (MDArrayFetch(inMerger->info, num, 1, &info) == 1) {
if (info.track != NULL)
MDTrackRelease(info.track);
if (info.ptr != NULL)
MDPointerRelease(info.ptr);
}
}
}
num = MDSequenceGetNumberOfTracks(inMerger->sequence);
MDArraySetCount(inMerger->info, num);
while (--num >= 0) {
info.track = MDSequenceGetTrack(inMerger->sequence, num);
MDTrackRetain(info.track);
info.eptr = NULL;
if (info.track != NULL) {
info.ptr = MDPointerNew(info.track);
if (info.ptr != NULL) {
MDPointerSetAutoAdjust(info.ptr, 1);
info.eptr = MDPointerForward(info.ptr);
}
} else info.ptr = NULL;
info.tick = (info.eptr != NULL ? MDGetTick(info.eptr) : LONG_MAX);
info.lastTick = -1.0;
MDArrayReplace(inMerger->info, num, 1, &info);
}
inMerger->tick = -1.0;
inMerger->currentTrack = -1;
inMerger->eptr = NULL;
}
/* --------------------------------------
・ MDMergerJumpToTick
-------------------------------------- */
int
MDMergerJumpToTick(MDMerger *inMerger, MDTickType inTick)
{
long i, num, minIndex;
MDTickType minTick;
MDEvent *eptr;
if (inMerger == NULL || inMerger->info == NULL)
return 0;
num = MDArrayCount(inMerger->info);
minIndex = -1;
minTick = kMDMaxTick;
eptr = NULL;
for (i = 0; i < num; i++) {
MDMergerInfo info;
if (MDArrayFetch(inMerger->info, i, 1, &info) == 1) {
if (info.ptr != NULL) {
MDEvent *last_eptr;
MDPointerJumpToTick(info.ptr, inTick);
last_eptr = MDPointerBackward(info.ptr);
info.eptr = MDPointerForward(info.ptr);
info.tick = (info.eptr != NULL ? MDGetTick(info.eptr) : kMDMaxTick);
info.lastTick = (last_eptr != NULL ? MDGetTick(last_eptr) : kMDNegativeTick);
if (info.tick < minTick) {
minIndex = i;
minTick = info.tick;
eptr = info.eptr;
}
MDArrayReplace(inMerger->info, i, 1, &info);
}
}
}
inMerger->eptr = eptr;
inMerger->tick = minTick;
inMerger->currentTrack = minIndex;
return 1;
}
/* --------------------------------------
・ MDMergerCurrent
-------------------------------------- */
MDEvent *
MDMergerCurrent(const MDMerger *inMerger)
{
if (inMerger != NULL)
return inMerger->eptr;
else return NULL;
}
/* --------------------------------------
・ MDMergerForward
-------------------------------------- */
MDEvent *
MDMergerForward(MDMerger *inMerger)
{
MDMergerInfo info;
MDTickType minTick;
long minIndex, i, num;
MDEvent *eptr;
if (inMerger == NULL || inMerger->tick == kMDMaxTick)
return NULL;
/* 現在位置を持っているトラックをインクリメントする */
if (inMerger->info == NULL)
return NULL;
if (inMerger->currentTrack != -1) {
if (MDArrayFetch(inMerger->info, inMerger->currentTrack, 1, &info) != 1)
return NULL;
if (info.ptr != NULL) {
info.eptr = MDPointerForward(info.ptr);
info.lastTick = info.tick;
info.tick = (info.eptr != NULL ? MDGetTick(info.eptr) : kMDMaxTick);
}
MDArrayReplace(inMerger->info, inMerger->currentTrack, 1, &info);
}
/* tick 最小のトラックをさがす */
minTick = kMDMaxTick;
minIndex = -1;
num = MDArrayCount(inMerger->info);
for (i = 0; i < num; i++) {
if (MDArrayFetch(inMerger->info, i, 1, &info) == 1) {
if (info.tick < minTick) {
minTick = info.tick;
minIndex = i;
eptr = info.eptr;
}
}
}
inMerger->currentTrack = minIndex;
if (minTick != kMDMaxTick) {
inMerger->eptr = eptr;
inMerger->tick = minTick;
} else {
inMerger->currentTrack = -1;
inMerger->eptr = NULL;
inMerger->tick = kMDMaxTick;
}
return inMerger->eptr;
}
/* --------------------------------------
・ MDMergerBackward
-------------------------------------- */
MDEvent *
MDMergerBackward(MDMerger *inMerger)
{
MDMergerInfo info;
MDTickType maxLastTick;
long maxIndex, i, num;
MDEvent *eptr;
if (inMerger == NULL || inMerger->info == NULL || inMerger->tick == kMDNegativeTick)
return NULL;
/* lastTick が最大のトラックを探す */
maxLastTick = kMDNegativeTick;
maxIndex = -1;
num = MDArrayCount(inMerger->info);
for (i = num - 1; i >= 0; i--) {
if (MDArrayFetch(inMerger->info, i, 1, &info) == 1) {
if (info.lastTick > maxLastTick) {
maxLastTick = info.lastTick;
maxIndex = i;
eptr = info.eptr;
}
}
}
if (maxIndex == -1) {
/* 全部のトラックが先頭位置にある */
inMerger->tick = kMDNegativeTick;
inMerger->eptr = NULL;
inMerger->currentTrack = -1;
return NULL; /* 前のイベントはない */
}
/* そのトラックをデクリメントする */
if (MDArrayFetch(inMerger->info, maxIndex, 1, &info) != 1)
return NULL;
if (info.ptr != NULL) {
info.eptr = MDPointerBackward(info.ptr);
if (info.eptr != NULL) {
info.tick = MDGetTick(info.eptr);
eptr = MDPointerBackward(info.ptr);
info.lastTick = (eptr != NULL ? MDGetTick(eptr) : kMDNegativeTick);
MDPointerForward(info.ptr);
}
MDArrayReplace(inMerger->info, maxIndex, 1, &info);
inMerger->currentTrack = maxIndex;
inMerger->eptr = info.eptr;
inMerger->tick = info.tick;
}
return inMerger->eptr;
}
/* --------------------------------------
・ MDMergerGetCurrentTrack
-------------------------------------- */
long
MDMergerGetCurrentTrack(MDMerger *inMerger)
{
if (inMerger != NULL)
return inMerger->currentTrack;
else return -1;
}
/* --------------------------------------
・ MDMergerGetCurrentPositionInTrack
-------------------------------------- */
long
MDMergerGetCurrentPositionInTrack(MDMerger *inMerger)
{
MDMergerInfo info;
if (inMerger != NULL && inMerger->info != NULL
&& MDArrayFetch(inMerger->info, inMerger->currentTrack, 1, &info) == 1) {
if (info.ptr != NULL)
return MDPointerGetPosition(info.ptr);
}
return -1;
}
/* --------------------------------------
・ MDMergerGetTick
-------------------------------------- */
MDTickType
MDMergerGetTick(MDMerger *inMerger)
{
if (inMerger != NULL)
return inMerger->tick;
else return kMDNegativeTick;
}