Files
perfect_dark/src/lib/naudio/n_csplayer.c
T
2021-10-17 11:24:07 +10:00

1333 lines
35 KiB
C

#include "versions.h"
#include <libaudio.h>
#include <os_internal.h>
#include <ultraerror.h>
#include <assert.h>
#include "n_libaudio.h"
#include "n_seqp.h"
#include "cseq.h"
#include "n_cseqp.h"
void __n_CSPRepostEvent(ALEventQueue *evtq, N_ALEventListItem *item);
void __n_setUsptFromTempo(N_ALCSPlayer *seqp, f32 tempo);
void __n_CSPHandleMetaMsg(N_ALCSPlayer *seqp, N_ALEvent *event);
ALMicroTime __n_vsDelta(N_ALVoiceState *vs, ALMicroTime t);
u32 var8009c350[16];
u32 var8005f150[] = {
0x00000000, 0x00002710, 0x00004e20, 0x00007530,
0x00009c40, 0x0000c350, 0x0000ea60, 0x00011170,
0x00013880, 0x00015f90, 0x000186a0, 0x0001adb0,
0x0001adb0, 0x0001d4c0, 0x0001fbd0, 0x000222e0,
0x000249f0, 0x00027100, 0x00029810, 0x0002e630,
0x00030d40, 0x00035b60, 0x00038270, 0x0003d090,
0x00041eb0, 0x00046cd0, 0x0004baf0, 0x00050910,
0x00055730, 0x0005cc60, 0x00064190, 0x0006b6c0,
0x00072bf0, 0x0007a120, 0x00083d60, 0x0008d9a0,
0x000975e0, 0x000a1220, 0x000ad570, 0x000b98c0,
0x000c8320, 0x000d6d80, 0x000e57e0, 0x000f4240,
0x000f4240, 0x0010c8e0, 0x00124f80, 0x0013d620,
0x00155cc0, 0x0016e360, 0x00186a00, 0x0019f0a0,
0x001b7740, 0x001e8480, 0x00200b20, 0x00231860,
0x00249f00, 0x0027ac40, 0x002ab980, 0x002dc6c0,
0x0030d400, 0x003567e0, 0x00387520, 0x003d0900,
0x00419ce0, 0x004630c0, 0x004ac4a0, 0x0050df20,
0x0056f9a0, 0x005d1420, 0x00632ea0, 0x006acfc0,
0x007270e0, 0x007b98a0, 0x008339c0, 0x008de820,
0x00970fe0, 0x00989680, 0x00a7d8c0, 0x00b71b00,
0x00c65d40, 0x00d59f80, 0x00e4e1c0, 0x00f42400,
0x01036640, 0x0112a880, 0x0121eac0, 0x01406f40,
0x014fb180, 0x016e3600, 0x018cba80, 0x01ab3f00,
0x01c9c380, 0x01e84800, 0x0206cc80, 0x02349340,
0x025317c0, 0x0280de80, 0x02aea540, 0x02ebae40,
0x02faf080, 0x03473bc0, 0x03938700, 0x03dfd240,
0x042c1d80, 0x047868c0, 0x04c4b400, 0x0510ff40,
0x055d4a80, 0x05a995c0, 0x05f5e100, 0x06422c40,
0x068e7780, 0x06dac2c0, 0x07270e00, 0x07735940,
0x07bfa480, 0x080befc0, 0x08583b00, 0x08a48640,
0x08f0d180, 0x093d1cc0, 0x09896800, 0x09d5b340,
0x0a21fe80, 0x0a6e49c0, 0x0aba9500,
};
u32 var8005f34c = 0x3d4ccccd;
u32 var8005f350 = 0x3d4ccccd;
u32 var8005f354 = 0x3d75c28f;
u32 var8005f358 = 0x3d75c28f;
u32 var8005f35c = 0x3d75c28f;
u32 var8005f360 = 0x3d8f5c29;
u32 var8005f364 = 0x3d8f5c29;
u32 var8005f368 = 0x3da3d70a;
u32 var8005f36c = 0x3da3d70a;
u32 var8005f370 = 0x3db851ec;
u32 var8005f374 = 0x3dcccccd;
u32 var8005f378 = 0x3de147ae;
u32 var8005f37c = 0x3e051eb8;
u32 var8005f380 = 0x3e0f5c29;
u32 var8005f384 = 0x3e2e147b;
u32 var8005f388 = 0x3e4ccccd;
u32 var8005f38c = 0x3e800000;
u32 var8005f390 = 0x3ea8f5c3;
u32 var8005f394 = 0x3f000000;
u32 var8005f398 = 0x3f800000;
u32 var8005f39c = 0x3fa00000;
u32 var8005f3a0 = 0x3fc00000;
u32 var8005f3a4 = 0x3fe00000;
u32 var8005f3a8 = 0x40000000;
u32 var8005f3ac = 0x40100000;
u32 var8005f3b0 = 0x40200000;
u32 var8005f3b4 = 0x40300000;
u32 var8005f3b8 = 0x40400000;
u32 var8005f3bc = 0x40500000;
u32 var8005f3c0 = 0x40600000;
u32 var8005f3c4 = 0x40700000;
u32 var8005f3c8 = 0x40800000;
u32 var8005f3cc = 0x40880000;
u32 var8005f3d0 = 0x40900000;
u32 var8005f3d4 = 0x40980000;
u32 var8005f3d8 = 0x40a00000;
u32 var8005f3dc = 0x40a80000;
u32 var8005f3e0 = 0x40b00000;
u32 var8005f3e4 = 0x40b80000;
u32 var8005f3e8 = 0x40c00000;
u32 var8005f3ec = 0x40c80000;
u32 var8005f3f0 = 0x40d00000;
u32 var8005f3f4 = 0x40d80000;
u32 var8005f3f8 = 0x40e00000;
u32 var8005f3fc = 0x40e80000;
u32 var8005f400 = 0x40f00000;
u32 var8005f404 = 0x40f80000;
u32 var8005f408 = 0x41000000;
u32 var8005f40c = 0x41040000;
u32 var8005f410 = 0x41080000;
u32 var8005f414 = 0x410c0000;
u32 var8005f418 = 0x41100000;
u32 var8005f41c = 0x41140000;
u32 var8005f420 = 0x41180000;
u32 var8005f424 = 0x411c0000;
u32 var8005f428 = 0x41200000;
u32 var8005f42c = 0x41240000;
u32 var8005f430 = 0x41280000;
u32 var8005f434 = 0x412c0000;
u32 var8005f438 = 0x41300000;
u32 var8005f43c = 0x41340000;
u32 var8005f440 = 0x41380000;
u32 var8005f444 = 0x413c0000;
u32 var8005f448 = 0x41400000;
u32 var8005f44c = 0x41440000;
u32 var8005f450 = 0x41480000;
u32 var8005f454 = 0x414c0000;
u32 var8005f458 = 0x41500000;
u32 var8005f45c = 0x41540000;
u32 var8005f460 = 0x41580000;
u32 var8005f464 = 0x415c0000;
u32 var8005f468 = 0x41600000;
u32 var8005f46c = 0x41640000;
u32 var8005f470 = 0x41680000;
u32 var8005f474 = 0x416c0000;
u32 var8005f478 = 0x41700000;
u32 var8005f47c = 0x41740000;
u32 var8005f480 = 0x41780000;
u32 var8005f484 = 0x417c0000;
u32 var8005f488 = 0x41800000;
u32 var8005f48c = 0x41820000;
u32 var8005f490 = 0x41840000;
u32 var8005f494 = 0x41860000;
u32 var8005f498 = 0x41880000;
u32 var8005f49c = 0x418a0000;
u32 var8005f4a0 = 0x418c0000;
u32 var8005f4a4 = 0x418e0000;
u32 var8005f4a8 = 0x41900000;
u32 var8005f4ac = 0x41920000;
u32 var8005f4b0 = 0x41940000;
u32 var8005f4b4 = 0x41960000;
u32 var8005f4b8 = 0x41980000;
u32 var8005f4bc = 0x419a0000;
u32 var8005f4c0 = 0x419c0000;
u32 var8005f4c4 = 0x419e0000;
u32 var8005f4c8 = 0x41a00000;
u32 var8005f4cc = 0x41a20000;
u32 var8005f4d0 = 0x41a40000;
u32 var8005f4d4 = 0x41a60000;
u32 var8005f4d8 = 0x41a80000;
u32 var8005f4dc = 0x00000000;
ALMicroTime __n_CSPVoiceHandler(void *node);
void n_alCSPNew(N_ALCSPlayer *seqp, ALSeqpConfig *c)
{
s32 i;
N_ALEventListItem *items;
N_ALVoiceState *vs;
N_ALVoiceState *voices;
ALHeap *hp = c->heap;
/*
* initialize member variables
*/
seqp->bank = 0;
seqp->target = NULL;
seqp->drvr = n_syn;
seqp->chanMask = 0xffff;
func00039cd0(seqp);
seqp->uspt = 488;
seqp->nextDelta = 0;
seqp->state = AL_STOPPED;
seqp->vol = 0x7fff; /* full volume */
seqp->debugFlags = c->debugFlags;
seqp->frameTime = AL_USEC_PER_FRAME; /* should get this from driver */
seqp->curTime = 0;
seqp->initOsc = c->initOsc;
seqp->updateOsc = c->updateOsc;
seqp->stopOsc = c->stopOsc;
seqp->unk7c = 0;
seqp->unk80 = 1;
seqp->queue = 0;
seqp->unk89 = 0;
seqp->unk88 = c->maxVoices;
seqp->nextEvent.type = AL_SEQP_API_EVT; /* this will start the voice handler "spinning" */
/*
* init the channel state
*/
seqp->maxChannels = c->maxChannels;
seqp->chanState = alHeapAlloc(hp, c->maxChannels, sizeof(ALChanState) );
__n_initChanState((N_ALSeqPlayer*)seqp);
/*
* init the voice state array
*/
voices = alHeapAlloc(hp, c->maxVoices, sizeof(N_ALVoiceState));
seqp->vFreeList = 0;
for (i = 0; i < c->maxVoices; i++) {
vs = &voices[i];
vs->next = seqp->vFreeList;
seqp->vFreeList = vs;
}
seqp->vAllocHead = 0;
seqp->vAllocTail = 0;
/*
* init the event queue
*/
items = alHeapAlloc(hp, c->maxEvents, sizeof(N_ALEventListItem));
n_alEvtqNew(&seqp->evtq, items, c->maxEvents);
/*
* add ourselves to the driver
*/
seqp->node.next = NULL;
seqp->node.handler = __n_CSPVoiceHandler;
seqp->node.clientData = seqp;
n_alSynAddSeqPlayer(&seqp->node);
}
void __n_CSPHandleNextSeqEvent(N_ALCSPlayer *seqp);
void __n_CSPHandleMIDIMsg(N_ALCSPlayer *seqp, N_ALEvent *event);
void func0003e3e0(N_ALVoice *v, f32 arg1);
u8 func0003d9cc(N_ALVoiceState *vs, N_ALCSPlayer *seqp);
ALFxRef func0003e540(u8 arg0);
ALFxRef func0003e5b8(u8 arg0);
void func0003e674(struct fx *fx, u8 arg1, void *param);
f32 func0003b9d4(s32 arg0);
ALMicroTime __n_CSPVoiceHandler(void *node)
{
N_ALCSPlayer *seqp = (N_ALCSPlayer *) node;
N_ALEvent evt;
N_ALVoice *voice;
ALMicroTime delta;
N_ALVoiceState *vs;
void *oscState;
f32 oscValue;
u8 chan;
do {
switch (seqp->nextEvent.type) {
case (AL_SEQ_REF_EVT):
__n_CSPHandleNextSeqEvent(seqp);
break;
case (AL_SEQP_API_EVT):
evt.type = AL_SEQP_API_EVT;
n_alEvtqPostEvent(&seqp->evtq, (N_ALEvent *)&evt, seqp->frameTime, 1);
break;
case (AL_NOTE_END_EVT):
voice = seqp->nextEvent.msg.note.voice;
n_alSynStopVoice(voice);
n_alSynFreeVoice(voice);
vs = (N_ALVoiceState *)voice->clientPrivate;
if (vs->flags) {
__n_seqpStopOsc((N_ALSeqPlayer*)seqp,vs);
}
__n_unmapVoice((N_ALSeqPlayer*)seqp, voice);
break;
case (AL_SEQP_ENV_EVT):
voice = seqp->nextEvent.msg.vol.voice;
vs = (N_ALVoiceState *)voice->clientPrivate;
if (vs->envPhase == AL_PHASE_ATTACK) {
vs->envPhase = AL_PHASE_DECAY;
}
delta = seqp->nextEvent.msg.vol.delta;
vs->envEndTime = seqp->curTime + delta;
vs->envGain = seqp->nextEvent.msg.vol.vol;
n_alSynSetVol(voice, __n_vsVol(vs, (N_ALSeqPlayer*)seqp), delta);
break;
case (AL_TREM_OSC_EVT):
vs = seqp->nextEvent.msg.osc.vs;
oscState = seqp->nextEvent.msg.osc.oscState;
delta = (*seqp->updateOsc)(oscState,&oscValue);
vs->tremelo = (u8)oscValue;
n_alSynSetVol(&vs->voice, __n_vsVol(vs,(N_ALSeqPlayer*)seqp), __n_vsDelta(vs,seqp->curTime));
evt.type = AL_TREM_OSC_EVT;
evt.msg.osc.vs = vs;
evt.msg.osc.oscState = oscState;
n_alEvtqPostEvent(&seqp->evtq, &evt, delta, 0);
break;
case (AL_VIB_OSC_EVT):
vs = seqp->nextEvent.msg.osc.vs;
oscState = seqp->nextEvent.msg.osc.oscState;
chan = seqp->nextEvent.msg.osc.chan;
delta = (*seqp->updateOsc)(oscState,&oscValue);
vs->vibrato = oscValue;
n_alSynSetPitch( &vs->voice, vs->pitch * vs->vibrato * seqp->chanState[chan].pitchBend);
if (seqp->chanState[chan].unk11) {
func0003e3e0(&vs->voice,
440
* func0003b9d4(seqp->chanState[chan].unk12 + (vs->key - vs->sound->keyMap->keyBase) - 64)
* seqp->chanState[chan].pitchBend
* vs->vibrato);
}
evt.type = AL_VIB_OSC_EVT;
evt.msg.osc.vs = vs;
evt.msg.osc.oscState = oscState;
evt.msg.osc.chan = chan;
n_alEvtqPostEvent(&seqp->evtq, &evt, delta, 0);
break;
case (AL_SEQP_MIDI_EVT):
case (AL_CSP_NOTEOFF_EVT): /* nextEvent is a note off midi message */
__n_CSPHandleMIDIMsg(seqp, &seqp->nextEvent);
break;
case (AL_SEQP_META_EVT):
__n_CSPHandleMetaMsg(seqp, &seqp->nextEvent);
break;
case (AL_SEQP_VOL_EVT):
seqp->vol = seqp->nextEvent.msg.spvol.vol;
for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) {
n_alSynSetVol(&vs->voice,
__n_vsVol(vs, (N_ALSeqPlayer*)seqp),
__n_vsDelta(vs, seqp->curTime));
}
break;
case (AL_18_EVT):
seqp->unk7c = seqp->nextEvent.msg.evt18.unk00;
seqp->unk80 = seqp->nextEvent.msg.evt18.unk04;
for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) {
n_alSynSetFXMix(&vs->voice, func0003d9cc(vs, seqp));
}
break;
case (AL_19_EVT):
if (seqp->nextEvent.msg.evt19.unk01 < 8) {
ALFxRef fx = func0003e540(seqp->nextEvent.msg.evt19.unk00);
if (fx) {
n_alSynSetFXParam(fx, seqp->nextEvent.msg.evt19.unk02 << 3 |
seqp->nextEvent.msg.evt19.unk01 & 7, &seqp->nextEvent.msg.evt19.param);
}
} else {
ALFxRef fx = func0003e5b8(seqp->nextEvent.msg.evt19.unk00);
if (fx) {
func0003e674((struct fx *) fx, seqp->nextEvent.msg.evt19.unk01, &seqp->nextEvent.msg.evt19.param);
}
}
break;
case (AL_SEQP_PLAY_EVT):
if (seqp->state != AL_PLAYING) {
seqp->state = AL_PLAYING;
__n_CSPPostNextSeqEvent(seqp);
/* seqp must be AL_PLAYING before we call this routine. */
}
break;
case (AL_SEQP_STOP_EVT):
if (seqp->state == AL_STOPPING ) {
for (vs = seqp->vAllocHead; vs != 0; vs = seqp->vAllocHead) {
n_alSynStopVoice(&vs->voice);
n_alSynFreeVoice(&vs->voice);
if (vs->flags) {
__n_seqpStopOsc((N_ALSeqPlayer*)seqp,vs);
}
__n_unmapVoice((N_ALSeqPlayer*)seqp, &vs->voice);
}
seqp->state = AL_STOPPED;
/* alEvtqFlush(&seqp->evtq); - Don't flush event queue
anymore. */
/* sct 1/3/96 - Don't overwrite nextEvent with
AL_SEQP_API_EVT or set nextDelta to
AL_USEC_PER_FRAME since we're not stopping event
processing. */
/* sct 1/3/96 - Don't return here since we keep
processing events as usual. */
}
break;
case (AL_SEQP_STOPPING_EVT):
if (seqp->state == AL_PLAYING) {
/* sct 12/29/95 - Remove events associated with the
* stopping sequence. For compact sequence player,
* also remove all queued note off events since they
* are not contained in a compact sequence but are
* generated in response to note ons. Note that
* flushing AL_SEQP_MIDI_EVTs may flush events that
* were posted after the call to alSeqpStop, so the
* application must queue these events either when
* the player is fully stopped, or when it is
* playing. */
n_alEvtqFlushType(&seqp->evtq, AL_SEQ_REF_EVT);
n_alEvtqFlushType(&seqp->evtq, AL_CSP_NOTEOFF_EVT);
n_alEvtqFlushType(&seqp->evtq, AL_SEQP_MIDI_EVT);
/* sct 1/3/96 - Check to see which voices need to be
killed and release them. */
/* Unkilled voices should have note end events
occurring prior to KILL_TIME. */
for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) {
if (__n_voiceNeedsNoteKill ((N_ALSeqPlayer*)seqp, &vs->voice, KILL_TIME)) {
__n_seqpReleaseVoice((N_ALSeqPlayer*)seqp, &vs->voice, KILL_TIME);
}
}
for (chan = 0; chan < 16; chan++) {
seqp->chanState[chan].unk0d = seqp->chanState[chan].unk0e;
if (seqp->chanState[chan].unk0d == 0) {
seqp->chanMask &= (1 << chan) ^ 0xffff;
} else {
seqp->chanMask |= 1 << chan;
}
}
seqp->state = AL_STOPPING;
evt.type = AL_SEQP_STOP_EVT;
n_alEvtqPostEvent(&seqp->evtq, &evt, AL_EVTQ_END, 0);
}
break;
case (AL_SEQP_PRIORITY_EVT):
chan = seqp->nextEvent.msg.sppriority.chan;
seqp->chanState[chan].priority = seqp->nextEvent.msg.sppriority.priority;
break;
case (AL_SEQP_SEQ_EVT):
/* Must be done playing to change sequences. */
seqp->target = seqp->nextEvent.msg.spseq.seq;
seqp->chanMask = 0xffff;
if (seqp->bank) {
__n_initFromBank((N_ALSeqPlayer *)seqp, seqp->bank);
}
break;
case (AL_SEQP_BANK_EVT):
/* Must be fully stopped to change banks. */
seqp->bank = seqp->nextEvent.msg.spbank.bank;
__n_initFromBank((N_ALSeqPlayer *)seqp, seqp->bank);
break;
/* sct 11/6/95 - these events should
now be handled by __n_CSPHandleNextSeqEvent */
case (AL_SEQ_END_EVT):
case (AL_TEMPO_EVT):
case (AL_SEQ_MIDI_EVT):
break;
}
seqp->nextDelta = n_alEvtqNextEvent(&seqp->evtq, &seqp->nextEvent);
} while (seqp->nextDelta == 0);
/*
* assume that next callback won't be more than half an
* hour away
*/
seqp->curTime += seqp->nextDelta; /* sct 11/7/95 */
return seqp->nextDelta;
}
/**
* Calculates the delta time in ticks until the next sequence
* event and posts a sequence reference event with the time in usecs.
* Loops are handled automatically by the compact sequence.
*
* Does nothing if the sequence player is not playing or if there
* is no target sequence.
*
* sct 11/7/95
*/
void __n_CSPHandleNextSeqEvent(N_ALCSPlayer *seqp)
{
N_ALEvent evt;
/* sct 1/5/96 - Do nothing if we don't have a target sequence. */
if (seqp->target == NULL) {
return;
}
n_alCSeqNextEvent(seqp->target, &evt, 1);
switch (evt.type) {
case AL_SEQ_MIDI_EVT:
__n_CSPHandleMIDIMsg(seqp, &evt);
__n_CSPPostNextSeqEvent(seqp);
break;
case AL_TEMPO_EVT:
__n_CSPHandleMetaMsg(seqp, &evt);
__n_CSPPostNextSeqEvent(seqp);
break;
case AL_SEQ_END_EVT:
if (!var8005f4dc) {
seqp->state = AL_STOPPING;
evt.type = AL_SEQP_STOP_EVT;
n_alEvtqPostEvent(&seqp->evtq, &evt, AL_EVTQ_END, 0);
}
break;
case AL_TRACK_END:
case AL_CSP_LOOPSTART:
case AL_CSP_LOOPEND:
__n_CSPPostNextSeqEvent(seqp);
break;
default:
break;
}
}
void func00034f0c(N_ALCSPlayer *seqp, u8 channel)
{
N_ALVoiceState *vs;
for (vs = seqp->vAllocHead; vs != NULL; vs = vs->next) {
if (vs->channel == channel && vs->envPhase != AL_PHASE_RELEASE) {
s16 volume = __n_vsVol(vs, (N_ALSeqPlayer *) seqp);
n_alSynSetVol(&vs->voice, volume, __n_vsDelta(vs, seqp->curTime));
}
}
}
void func00034fb8(N_ALCSPlayer *seqp, u8 channel)
{
N_ALVoiceState *vs;
s16 sp2a;
s8 sp29 = (s8)seqp->chanState[channel].unk12 - 64;
f32 sp24 = seqp->chanState[channel].pitchBend;
for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) {
if (vs->channel == channel) {
sp2a = seqp->chanState[channel].unk11;
func0003e490(&vs->voice, sp2a);
if (sp2a) {
func0003e3e0(&vs->voice, func0003b9d4((vs->key - vs->sound->keyMap->keyBase) + sp29) * 440 * sp24);
}
}
}
}
void snd0001036c(u8 arg0);
f32 func0002fc60(u8 arg0);
void __n_CSPHandleMIDIMsg(N_ALCSPlayer *seqp, N_ALEvent *event)
{
N_ALVoice *voice;
N_ALVoiceState *vs;
s32 status;
u8 chan;
u8 key;
u8 vel;
u8 byte1;
u8 byte2;
ALMIDIEvent *midi = &event->msg.midi;
s16 vol;
N_ALEvent evt;
ALMicroTime deltaTime;
N_ALVoiceState *vstate;
ALPan pan;
ALChanState *chanstate;
s32 sp90;
ALVoiceConfig config;
ALSound *sound;
s16 cents;
f32 pitch,oscValue;
u8 fxmix;
u8 sp76;
f32 sp70;
void *oscState;
ALInstrument *inst;
u8 sp67;
u8 sp66;
s32 sp60;
status = midi->status & AL_MIDI_StatusMask;
chan = midi->status & AL_MIDI_ChannelMask;
byte1 = key = midi->byte1;
byte2 = vel = midi->byte2;
switch (status) {
case (AL_MIDI_NoteOn):
if (vel != 0) /* a real note on */ {
oscState = 0;
/* If we're not playing, don't process note ons. */
if (seqp->state != AL_PLAYING || (seqp->chanMask & (1 << chan)) == 0) {
if (midi->duration) {
evt.type = AL_CSP_NOTEOFF_EVT;
evt.msg.midi.status = chan | 0x80;
evt.msg.midi.byte1 = key;
evt.msg.midi.byte2 = 0;
deltaTime = seqp->uspt * midi->duration;
var8009c350[chan] = deltaTime;
n_alEvtqPostEvent(&seqp->evtq, &evt, deltaTime, 0);
}
break;
}
chanstate = &seqp->chanState[chan];
sound = __n_lookupSoundQuick((N_ALSeqPlayer*)seqp, key, vel, chan);
ALFlagFailIf(!sound, seqp->debugFlags & NO_SOUND_ERR_MASK,
ERR_ALSEQP_NO_SOUND);
config.priority = chanstate->priority;
config.fxBus = chanstate->unk0b;
config.unityPitch = 0;
vstate = __n_mapVoice((N_ALSeqPlayer*)seqp, key, vel, chan);
ALFlagFailIf(!vstate, seqp->debugFlags & NO_VOICE_ERR_MASK,
ERR_ALSEQP_NO_VOICE );
voice = &vstate->voice;
n_alSynAllocVoice(voice, &config);
/*
* set up the voice state structure
*/
vstate->sound = sound;
vstate->envPhase = AL_PHASE_ATTACK;
if (chanstate->sustain > AL_SUSTAIN) {
vstate->phase = AL_PHASE_SUSTAIN;
} else {
vstate->phase = AL_PHASE_NOTEON;
}
cents = (key - sound->keyMap->keyBase) * 100 + sound->keyMap->detune;
if (chanstate->unk24) {
cents += chanstate->unk27;
}
vstate->pitch = alCents2Ratio(cents);
if (chanstate->unk24) {
vstate->envGain = chanstate->attackVolume;
vstate->envEndTime = seqp->curTime + chanstate->attackTime;
} else {
vstate->envGain = sound->envelope->attackVolume;
vstate->envEndTime = seqp->curTime + sound->envelope->attackTime;
}
/*
* setup tremelo and vibrato if active
*/
vstate->flags = 0;
if (chanstate->unk24) {
sp90 = chanstate->tremType;
} else {
inst = seqp->chanState[chan].instrument;
sp90 = inst->tremType;
}
oscValue = (f32)AL_VOL_FULL; /* set this as a default */
if (sp90) {
if (seqp->initOsc) {
if (chanstate->unk24) {
deltaTime = (*seqp->initOsc)(&oscState,&oscValue,chanstate->tremType,
chanstate->tremRate,chanstate->tremDepth,chanstate->tremDelay, chanstate->unk31);
} else {
deltaTime = (*seqp->initOsc)(&oscState,&oscValue,inst->tremType,
inst->tremRate,inst->tremDepth,inst->tremDelay, chanstate->unk31);
}
if (deltaTime) /* a deltaTime of zero means don't run osc */ {
evt.type = AL_TREM_OSC_EVT;
evt.msg.osc.vs = vstate;
evt.msg.osc.oscState = oscState;
n_alEvtqPostEvent(&seqp->evtq, &evt, deltaTime, 0);
vstate->flags |= 0x01; /* set tremelo flag bit */
vstate->oscState = oscState;
}
}
}
vstate->tremelo = (u8)oscValue;
/* will default if not changed by initOsc */
oscValue = 1.0f; /* set this as a default */
if (chanstate->unk24) {
sp90 = chanstate->vibType;
} else {
sp90 = inst->vibType;
}
if (sp90) {
if (seqp->initOsc) {
if (chanstate->unk24) {
deltaTime = (*seqp->initOsc)(&oscState,&oscValue,chanstate->vibType,
chanstate->vibRate,chanstate->vibDepth,chanstate->vibDelay, chanstate->unk31);
} else {
deltaTime = (*seqp->initOsc)(&oscState,&oscValue,inst->vibType,
inst->vibRate,inst->vibDepth,inst->vibDelay, chanstate->unk31);
}
if (deltaTime) /* a deltaTime of zero means don't run osc. */ {
evt.type = AL_VIB_OSC_EVT;
evt.msg.osc.vs = vstate;
evt.msg.osc.oscState = oscState;
evt.msg.osc.chan = chan;
n_alEvtqPostEvent(&seqp->evtq, &evt, deltaTime, 0);
vstate->flags |= 0x02; /* set the vibrato flag bit */
vstate->oscState2 = oscState;
}
}
}
vstate->vibrato = oscValue; /* will default if not changed by initOsc */
/*
* calculate the note on parameters
*/
pitch = vstate->pitch * chanstate->pitchBend * vstate->vibrato;
fxmix = func0003d9cc(vstate, seqp);
sp76 = chanstate->unk11;
if (sp76) {
sp70 = 440 * func0003b9d4(cents / 100 + chanstate->unk12 - 64) * chanstate->pitchBend;
} else {
sp70 = 127.0f;
}
pan = __n_vsPan(vstate, (N_ALSeqPlayer*)seqp);
vol = __n_vsVol(vstate, (N_ALSeqPlayer*)seqp);
if (chanstate->unk24) {
deltaTime = chanstate->attackTime;
} else {
deltaTime = sound->envelope->attackTime;
}
n_alSynStartVoiceParams(voice, sound->wavetable,
pitch, vol, pan, fxmix, sp76, sp70, chanstate->unk13, deltaTime);
/*
* set up callbacks for envelope
*/
evt.type = AL_SEQP_ENV_EVT;
evt.msg.vol.voice = voice;
if (chanstate->unk24) {
evt.msg.vol.vol = chanstate->decayVolume;
evt.msg.vol.delta = chanstate->decayTime;
} else {
evt.msg.vol.vol = sound->envelope->decayVolume;
evt.msg.vol.delta = sound->envelope->decayTime;
}
n_alEvtqPostEvent(&seqp->evtq, &evt, deltaTime, 0);
if (midi->duration) {
/*
* set up note off evt. if no duration don't do this
*/
evt.type = AL_CSP_NOTEOFF_EVT;
evt.msg.midi.status = chan | AL_MIDI_NoteOff;
evt.msg.midi.byte1 = key;
evt.msg.midi.byte2 = 0; /* not needed ? */
deltaTime = seqp->uspt * midi->duration;
var8009c350[chan] = deltaTime;
/* max time would be about one hour ten minutes */
n_alEvtqPostEvent(&seqp->evtq, &evt, deltaTime, 0);
}
if ((chanstate->unk10 & 1) && seqp->queue) {
osSendMesg(seqp->queue, (OSMesg)(var8009c350[chan] & 0xffffff00 | chanstate->unk10 >> 2), OS_MESG_NOBLOCK);
}
break;
}
/*
* NOTE: intentional fall-through for note on with zero
* velocity (Should never happen with compact midi sequence,
* but could happen with real time midi.)
*/
case (AL_MIDI_NoteOff):
vstate = __n_lookupVoice((N_ALSeqPlayer*)seqp, key, chan);
ALFlagFailIf(!vstate, seqp->debugFlags & NOTE_OFF_ERR_MASK,
ERR_ALSEQP_OFF_VOICE );
chanstate = &seqp->chanState[chan];
if (vstate->phase == AL_PHASE_SUSTAIN) {
vstate->phase = AL_PHASE_SUSTREL;
} else {
vstate->phase = AL_PHASE_RELEASE;
if (chanstate->unk24) {
__n_seqpReleaseVoice((N_ALSeqPlayer*)seqp, &vstate->voice,
chanstate->releaseTime);
} else {
__n_seqpReleaseVoice((N_ALSeqPlayer*)seqp, &vstate->voice,
vstate->sound->envelope->releaseTime);
}
}
if ((chanstate->unk10 & 2) && seqp->queue) {
osSendMesg(seqp->queue, (OSMesg)(key << 16 | 8 | chanstate->unk10 >> 2), OS_MESG_NOBLOCK);
}
break;
case (AL_MIDI_PolyKeyPressure):
/*
* Aftertouch per key (hardwired to volume). Note that
* aftertouch affects only notes that are already
* sounding.
*/
vstate = __n_lookupVoice((N_ALSeqPlayer*)seqp, key, chan);
ALFailIf(!vstate, ERR_ALSEQP_POLY_VOICE );
vstate->velocity = byte2;
n_alSynSetVol( &vstate->voice,
__n_vsVol(vstate, (N_ALSeqPlayer*)seqp),
__n_vsDelta(vstate,seqp->curTime));
break;
case (AL_MIDI_ChannelPressure):
/*
* Aftertouch per channel (hardwired to volume). Note that
* aftertouch affects only notes that are already
* sounding.
*/
for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) {
if (vs->channel == chan) {
vs->velocity = byte1;
n_alSynSetVol( &vs->voice,
__n_vsVol(vs, (N_ALSeqPlayer*)seqp),
__n_vsDelta(vs,seqp->curTime));
}
}
break;
case (AL_MIDI_ControlChange):
switch (byte1) {
case (AL_MIDI_PAN_CTRL):
seqp->chanState[chan].pan = byte2;
for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) {
if (vs->channel == chan) {
pan = __n_vsPan(vs, (N_ALSeqPlayer*)seqp);
n_alSynSetPan( &vs->voice, pan);
}
}
break;
case (0xfd):
seqp->chanState[chan].unk0f = byte2;
break;
case (0xff):
if (seqp->chanState[chan].unk0f == 0) {
seqp->chanState[chan].unk0f = 0x90;
}
if (seqp->chanState[chan].unk0e != byte2) {
if (seqp->chanState[chan].unk0e == seqp->chanState[chan].unk0d) {
seqp->chanState[chan].unk0e = byte2;
} else {
seqp->chanState[chan].unk0e = byte2;
break;
}
} else {
break;
}
midi->byte1 = 0xfe;
// fall-through
case (0xfe):
sp67 = seqp->chanState[chan].unk0d;
sp66 = seqp->chanState[chan].unk0e;
vel = seqp->chanState[chan].unk0f;
sp60 = sp66 - sp67;
if (sp60 > 0) {
if (vel & 0x80) {
vel = (vel & 0x7f) << 1;
}
if (sp60 > vel) {
sp60 = vel;
}
} else {
vel &= 0x7f;
if (sp60 < -vel) {
sp60 = -vel;
}
}
sp67 += sp60;
seqp->chanState[chan].unk0d = sp67;
if (sp67 != sp66) {
n_alEvtqPostEvent(&seqp->evtq, event, seqp->uspt * 100, 0);
}
if (sp67) {
seqp->chanMask |= 1 << chan;
} else {
seqp->chanMask &= ~(1 << chan);
}
func00034f0c(seqp, chan);
break;
case (0xfc):
seqp->chanState[chan].unk0d = byte2;
seqp->chanState[chan].unk0e = byte2;
if (byte2 == 0) {
seqp->chanMask &= (1 << chan) ^ 0xffff;
} else {
seqp->chanMask |= 1 << chan;
}
func00034f0c(seqp, chan);
break;
case (0x21):
seqp->chanState[chan].unk11 = byte2;
func00034fb8(seqp, chan);
break;
case (0x22):
seqp->chanState[chan].unk12 = byte2;
func00034fb8(seqp, chan);
break;
case (0x23):
seqp->chanState[chan].unk13 = byte2;
for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) {
if (vs->channel == chan) {
func0003e730(&vs->voice, byte2);
}
}
break;
case (0x1e):
if (seqp->queue) {
osSendMesg(seqp->queue, (OSMesg)(byte2 & 7 | 0x10 | (seqp->node.samplesLeft << 5) & 0xffffff00), OS_MESG_NOBLOCK);
}
break;
case (AL_MIDI_VOLUME_CTRL):
seqp->chanState[chan].vol = byte2;
for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) {
if ((vs->channel == chan) && (vs->envPhase != AL_PHASE_RELEASE)) {
vol = __n_vsVol(vs, (N_ALSeqPlayer*)seqp);
n_alSynSetVol(&vs->voice, vol, __n_vsDelta(vs,seqp->curTime));
}
}
break;
case (AL_MIDI_PRIORITY_CTRL):
/* leave current voices where they are */
seqp->chanState[chan].priority = byte2;
break;
case (AL_MIDI_SUSTAIN_CTRL):
seqp->chanState[chan].sustain = byte2;
for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) {
if ((vs->channel == chan) && (vs->phase != AL_PHASE_RELEASE)) {
if ( byte2 > AL_SUSTAIN ) {
/*
* sustain pedal down
*/
if (vs->phase == AL_PHASE_NOTEON) {
vs->phase = AL_PHASE_SUSTAIN;
}
} else {
/*
* sustain pedal up
*/
if (vs->phase == AL_PHASE_SUSTAIN) {
vs->phase = AL_PHASE_NOTEON;
} else if (vs->phase == AL_PHASE_SUSTREL) {
vs->phase = AL_PHASE_RELEASE;
#define MIN_RELEASE_TIME (PAL ? 20000 : 16000)
if (chanstate->unk24) {
__n_seqpReleaseVoice((N_ALSeqPlayer*)seqp,
&vs->voice,
(seqp->chanState[chan].releaseTime < MIN_RELEASE_TIME ? MIN_RELEASE_TIME : seqp->chanState[chan].releaseTime));
} else {
__n_seqpReleaseVoice((N_ALSeqPlayer*)seqp,
&vs->voice,
vstate->sound->envelope->releaseTime < MIN_RELEASE_TIME ? MIN_RELEASE_TIME : vstate->sound->envelope->releaseTime);
}
}
}
}
}
break;
case (AL_MIDI_FX1_CTRL):
seqp->chanState[chan].fxmix = (seqp->chanState[chan].fxmix & 0x80) | byte2;
byte2 = seqp->chanState[chan].fxmix >> 7;
// fall-through
case (0x41):
seqp->chanState[chan].fxmix = (seqp->chanState[chan].fxmix & 0x7f) | (byte2 << 7);
for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) {
if (vs->channel == chan) {
n_alSynSetFXMix(&vs->voice, seqp->chanState[chan].fxmix);
}
}
break;
case (0x5c):
if (byte2 < n_syn->maxAuxBusses) {
seqp->chanState[chan].unk0b = byte2;
}
break;
case (AL_MIDI_FX_CTRL_6):
snd0001036c(byte2);
break;
case (0x20):
seqp->chanState[chan].unk32 = byte2;
break;
case (AL_MIDI_FX_CTRL_0):
seqp->chanState[chan].attackTime = var8005f150[byte2];
seqp->chanState[chan].unk24 = 1;
break;
case (AL_MIDI_FX_CTRL_1):
seqp->chanState[chan].attackVolume = byte2;
seqp->chanState[chan].unk24 = 1;
break;
case (AL_MIDI_FX_CTRL_2):
seqp->chanState[chan].decayTime = var8005f150[byte2];
seqp->chanState[chan].unk24 = 1;
break;
case (AL_MIDI_FX_CTRL_3):
seqp->chanState[chan].decayVolume = byte2;
seqp->chanState[chan].unk24 = 1;
break;
case (AL_MIDI_FX_CTRL_4):
seqp->chanState[chan].releaseTime = var8005f150[byte2];
seqp->chanState[chan].unk24 = 1;
break;
case (0x02):
seqp->chanState[chan].unk27 = byte2 - 64;
seqp->chanState[chan].unk24 = 1;
break;
case (0x03):
seqp->chanState[chan].bendRange /= 100;
seqp->chanState[chan].bendRange *= 100;
seqp->chanState[chan].bendRange += byte2;
break;
case (0x04):
seqp->chanState[chan].bendRange %= 100;
seqp->chanState[chan].bendRange += byte2 * 100;
break;
case (0x0b):
if (byte2) {
byte2 += 0x80;
}
seqp->chanState[chan].vibType = byte2;
seqp->chanState[chan].unk24 = 1;
break;
case (0x0c):
seqp->chanState[chan].vibRate = byte2;
seqp->chanState[chan].unk24 = 1;
break;
case (0x0d):
seqp->chanState[chan].vibDepth = byte2 * 2;
seqp->chanState[chan].unk24 = 1;
break;
case (0x0e):
seqp->chanState[chan].vibDelay = byte2;
seqp->chanState[chan].unk24 = 1;
break;
case (0x0f):
seqp->chanState[chan].tremType = byte2;
seqp->chanState[chan].unk24 = 1;
break;
case (0x11):
seqp->chanState[chan].tremRate = byte2;
seqp->chanState[chan].unk24 = 1;
break;
case (0x12):
seqp->chanState[chan].tremDepth = byte2;
seqp->chanState[chan].unk24 = 1;
break;
case (0x13):
seqp->chanState[chan].tremDelay = byte2;
seqp->chanState[chan].unk24 = 1;
break;
case (0x01):
byte2 *= 2;
for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) {
if (vs->channel == chan && vs->oscState2) {
struct oscstate *sp5c = vs->oscState2;
switch (sp5c->unk04 & 0xffffff7f) {
case 0x02:
sp5c->unk10 = -func0002fc60(byte2);
// fall-through
case 0x03:
case 0x04:
case 0x05:
sp5c->unk0c = func0002fc60(byte2);
break;
case 0x07:
case 0x09:
case 0x0d:
sp5c->unk0c = func0002fc60(byte2) / 2.0f;
break;
case 0x0a:
sp5c->unk0c = func0002fc60(byte2) * 2.0f;
break;
default:
sp5c->unk0c = func0002fc60(byte2);
break;
}
}
}
break;
case 0x19:
seqp->chanState[chan].unk31 = byte2;
break;
default:
break;
}
break;
case (AL_MIDI_ProgramChange):
/* sct 1/16/96 - We must have a valid bank in order to process the program change. */
sp90 = (seqp->chanState[chan].unk32 << 7) + key;
if (sp90 < seqp->bank->instCount) {
ALInstrument *inst = seqp->bank->instArray[sp90];
__n_setInstChanState((N_ALSeqPlayer*)seqp, inst, chan); /* sct 11/6/95 */
} else {
// empty
}
break;
case (AL_MIDI_PitchBendChange):
{
s32 bendVal;
f32 bendRatio;
s32 cents;
/* get 14-bit unsigned midi value */
bendVal = ((byte2 << 7) + byte1) - 8192;
/* calculate pitch bend in cents */
cents = seqp->chanState[chan].bendRange * bendVal / 8192;
/* calculate the corresponding ratio */
bendRatio = alCents2Ratio(cents);
seqp->chanState[chan].pitchBend = bendRatio;
for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) {
if (vs->channel == chan) {
n_alSynSetPitch( &vs->voice, vs->pitch * bendRatio * vs->vibrato);
if (seqp->chanState[chan].unk11) {
func0003e3e0(&vs->voice, 440 * func0003b9d4(seqp->chanState[chan].unk12 + (vs->key - vs->sound->keyMap->keyBase) - 64) * bendRatio * vs->vibrato);
}
}
}
}
break;
default:
break;
}
}
void __n_CSPHandleMetaMsg(N_ALCSPlayer *seqp, N_ALEvent *event)
{
ALTempoEvent *tevt = &event->msg.tempo;
s32 tempo;
s32 oldUspt;
u32 ticks;
ALMicroTime tempDelta, curDelta = 0;
N_ALEventListItem *thisNode, *nextNode, *firstTemp = 0;
if (event->msg.tempo.status == AL_MIDI_Meta) {
if (event->msg.tempo.type == AL_MIDI_META_TEMPO) {
oldUspt = seqp->uspt;
tempo = (tevt->byte1 << 16) | (tevt->byte2 << 8) | (tevt->byte3 << 0);
__n_setUsptFromTempo(seqp, (f32)tempo);
thisNode = (N_ALEventListItem*)seqp->evtq.allocList.next;
while (thisNode) {
curDelta += thisNode->delta;
nextNode = (N_ALEventListItem*)thisNode->node.next;
if (thisNode->evt.type == AL_CSP_NOTEOFF_EVT) {
alUnlink((ALLink*)thisNode);
if (firstTemp) {
alLink((ALLink*)thisNode,(ALLink*)firstTemp);
} else {
thisNode->node.next = 0;
thisNode->node.prev = 0;
firstTemp = thisNode;
}
tempDelta = curDelta; /* record the current delta */
if (nextNode) {/* don't do this if no nextNode */
curDelta -= thisNode->delta; /* subtract out this delta */
nextNode->delta += thisNode->delta; /* add it to next event */
}
thisNode->delta = tempDelta; /* set this event delta from current */
}
thisNode = nextNode;
}
thisNode = firstTemp;
while (thisNode) {
nextNode = (N_ALEventListItem*)thisNode->node.next;
ticks = thisNode->delta/oldUspt;
thisNode->delta = ticks * seqp->uspt;
__n_CSPRepostEvent(&seqp->evtq,thisNode);
thisNode = nextNode;
}
}
}
}
void __n_CSPRepostEvent(ALEventQueue *evtq, N_ALEventListItem *item)
{
OSIntMask mask;
ALLink *node;
N_ALEventListItem *nextItem;
mask = osSetIntMask(OS_IM_NONE);
for (node = &evtq->allocList; node != 0; node = node->next) {
if (!node->next) {
alLink((ALLink *)item, node);
break;
} else {
nextItem = (N_ALEventListItem *)node->next;
if (item->delta < nextItem->delta) {
nextItem->delta -= item->delta;
alLink((ALLink *)item, node);
break;
}
item->delta -= nextItem->delta;
}
}
osSetIntMask(mask);
}
void __n_setUsptFromTempo(N_ALCSPlayer *seqp, f32 tempo)
{
if (seqp->target) {
seqp->uspt = (s32)((f32)tempo * seqp->target->qnpt);
} else {
seqp->uspt = 488;
}
}
void __n_CSPPostNextSeqEvent(N_ALCSPlayer *seqp)
{
N_ALEvent evt;
s32 deltaTicks;
if (seqp->state != AL_PLAYING || seqp->target == NULL) {
return;
}
/* Get the next event time in ticks. */
/* If false is returned, then there is no next delta (ie. end of sequence reached). */
if (!__alCSeqNextDelta(seqp->target, &deltaTicks)) {
return;
}
evt.type = AL_SEQ_REF_EVT;
n_alEvtqPostEvent(&seqp->evtq, &evt, deltaTicks * seqp->uspt, 0);
}
void func00037634(N_ALCSPlayer *seqp, u8 value)
{
seqp->unk88 = value;
}