📄 mixer.c
字号:
}
channel = &MixChannel[mixingData->Channel];
eint16* mixAudioBuffer = channel->outputPointer;
int length;
if(framePointer != NULL && channel->mixingFrame < playingFrame)
{
length = bufferLength(mixAudioBuffer, framePointer);
}
else
{
length = bufferLength(mixAudioBuffer, playPointer);
}
if((mixAudioBuffer + (length<<1)) > audioBufferEnd)
{
// Lets make sure the mixing loop doesn't have to
// cross the end of the play buffer boundary
//rprintf("mixPtr: %X len: %d", mixPtr, length);
length = (audioBufferEnd - mixAudioBuffer) >> 1;
//rprintf(" -> %d", length);
}
if(length > 0)
{
// FIOSET = BIT(REDLED);
length = mix(channel, length);
if(mixingData == NULL || mixingData->Channel == -1)
{
GRAPHDBG('M');
}
else
{
GRAPHDBG('m');
}
}
// printStatus(2);
return length;
}
void copyEventToChannel(MixChannelType* channel, EventChannelType* eventChannel)
{
if(eventChannel->flags & SET_ACTIVE)
{
channel->bActive = (eventChannel->flags & IS_ACTIVE);
}
if(eventChannel->flags & SET_iLoc)
{
if(channel->iLoc != eventChannel->iLoc)
{
channel->iLoc = eventChannel->iLoc;
// invalidate RAM buffer.
// this channel is no longer pointing at the same sample data as before.
waitingData = NULL;
mixingData = NULL;
}
}
if(eventChannel->flags & SET_SAMPLE)
{
if(channel->iSDLocation != eventChannel->sample->iSDLocation)
{
channel->iSDLocation = eventChannel->sample->iSDLocation;
mixingData = NULL; // this channel is no longer pointing at the same sample data as before,
waitingData = NULL; // so we need to invalidate the RAM buffers.
}
if(eventChannel->sample->iLoopEnd == 0)
{
channel->bLoop = 0;
channel->iEnd = eventChannel->sample->iLength;
if(channel->iLoc >= channel->iEnd)
{
channel->bActive = 0;
}
}
else
{
channel->bLoop = 1;
channel->iLoopStart = eventChannel->sample->iLoopStart;
channel->iEnd = eventChannel->sample->iLoopEnd;
if(channel->iLoc >= channel->iEnd)
{
channel->iLoc = channel->iLoopStart;
}
}
}
if(eventChannel->flags & SET_VOLUME)
{
if(eventChannel->iPan == 0xA4)
{
channel->iVolLeft = (0x80 * eventChannel->iVolume) >> 7;
channel->iVolRight = 0 - ((0x80 * eventChannel->iVolume) >> 7);
}
else
{
channel->iVolLeft = ((0x80 - eventChannel->iPan) * eventChannel->iVolume) >> 7;
channel->iVolRight = ((eventChannel->iPan) * eventChannel->iVolume) >> 7;
}
}
if(eventChannel->flags & SET_STEP)
{
channel->iStep = eventChannel->iStep;
channel->iStepFract = eventChannel->iStepFract;
}
if(eventChannel->flags & SET_iLocFract)
channel->iLocFract = eventChannel->iLocFract;
}
void initMixer(void)
{
unsigned int i;
//iPlayPtr = 0;
playPointer = audioBuffer;
framePointer = &audioBuffer[2];
// First, clear out the play buffer so that it contains silence.
for(i = 0; i < audioSize; ++i)
{
audioBuffer[i] = 0;
}
// Now set all of the channels as non-active.
for(i = 0; i < CHANNELS; ++i)
{
MixChannelType* p = &MixChannel[i];
p->outputPointer = &audioBuffer[2];
p->bActive = 0;
}
}
int mix(MixChannelType *channel, unsigned int iLength)
{
unsigned int i;
unsigned int iSampleStep, iSampleStepC;
unsigned int iSampleLocFract, iSampleStepFract;
int iSampleEnd = channel->iEnd - mixingData->iSDLoc;
int iSampleLoc = channel->iLoc - mixingData->iSDLoc;
int iSampleLocBegin = iSampleLoc;
int iLoc = -1;
int iMixStop;
eint32 iTmpLFT, iTmpRGT;
eint32 iVolLeft, iVolRight;
eint16* pBuffer = channel->outputPointer;
eint8* pSample = mixingData->Data;
iVolLeft = channel->iVolLeft;
iVolRight = channel->iVolRight;
iSampleStep = channel->iStep;
iSampleLocFract = channel->iLocFract;
iSampleStepFract = channel->iStepFract;
/*
if(iSampleLoc < 0)
{
rprintf("iSampleLoc: %d iLoc: %X SDLoc: %X!!!\n", iSampleLoc, channel->iLoc, mixingData->iSDLoc);
}
*/
if(mixingData->Length == 0 || iSampleLoc >= mixingData->Length)
{
// ABORT: we don't have enough data read into RAM to do any mixing right now.
if(iSampleLoc == iSD_BlockLength)
{
// we ran out of data in this buffer, but there might be another buffer waiting for us (or not).
mixingData->Channel = -1; // flush if we finished mixing readingData before finishReading() got to it.
mixingData = waitingData;
waitingData = NULL;
return 0;
}
FIOCLR = BIT(REDLED);
return 0;
}
FIOSET = BIT(REDLED);
if(iSampleEnd >= mixingData->Length)
{
iMixStop = mixingData->Length;
}
else
{
iMixStop = iSampleEnd;
}
// iSample = pSample[iSampleLoc];
// iTmpLFT = CALC_SAMPLE(iSample, iVolLeft);
// iTmpRGT = CALC_SAMPLE(iSample, iVolRight);
asm("ldrsb %0, [%2, %3]" "\n\t"
"mov %1, %0" "\n\t"
"mul %0, %4" "\n\t"
"mul %1, %5" "\n\t"
/* output */ : "=r"(iTmpLFT), "=r"(iTmpRGT)
/* intput */ : "r"(pSample), "r"(iSampleLoc), "r"(iVolLeft), "r"(iVolRight)
/* clobber */ : "cc");
for(i = 0; i < iLength; i++)
{
// *pBuffer += iTmpLFT;
// pBuffer++;
// *pBuffer += iTmpRGT;
// pBuffer++;
asm("ldrsh r3, [%0, #0]" "\n\t" // retrieve existing data in the output audio buffer and sign extend
"add r3, r3, %[sampleLeft]" "\n\t" // add sample to output audio buffer data
"strh r3, [%0], #2" "\n\t" // store result back to output audio buffer and increment pointer
"ldrsh r3, [%0, #0]" "\n\t" // retrieve existing data in the output audio buffer and sign extend
"add r3, r3, %[sampleRight]" "\n\t" // add sample to output audio buffer data
"strh r3, [%0], #2" "\n\t" // store result back to output audio buffer and increment pointer
: "+r"(pBuffer), "=m"(*pBuffer) // OUTPUT
: [sampleLeft] "r"(iTmpLFT), [sampleRight] "r"(iTmpRGT) // INPUT
: "r3", "memory"); // CLOBBER
// iSampleLocFract = iSampleLocFract + iSampleStepFract
// iSampleStepC = iSampleStep + CARRY(iSampleLocFract + iSampleStepFract)
// iSampleLoc = iSampleLoc + iSampleStepC
asm("adds %0, %0, %3" "\n\t" // add and set flags
"adc %1, %5, %4" "\n\t" // add iSampleStep and Carry flag into iSampleStepC
"add %2, %1, %2" "\n\t" // add to iSampleStepC to iSampleLoc
/* output */ : "+r"(iSampleLocFract), "=r"(iSampleStepC), "+r"(iSampleLoc)
/* intput */ : "r"(iSampleStepFract), "r"(iSampleStep), "r"(0)
/* clobber */ : "cc");
// Did the sample offset change at all?
if(iSampleStepC != 0)
{
// channel->iLoc += iSampleStepC;
if(iSampleLoc >= iMixStop)
{
if(iSampleLoc < iSampleEnd)
{
// we haven't reached the sample's end or loop end yet.
// - waiting for more data to be read into RAM on the current mixingData buffer.
// - reached the end of an SD Block and need a new block
if(iSampleLoc < iSD_BlockLength)
{
// okay, we haven't reached the sample's end or loop end yet, but we also haven't
// reached the end of an SD block. That means we must be waiting for more data to
// be read into RAM on the current mixingData buffer.
FIOCLR = BIT(REDLED);
break;
}
// rprintf("Loc: %X End: %X Stop: %X mixData: %X waitData: %X\n", iSampleLoc, iSampleEnd, iMixStop, mixingData, waitingData);
// we ran out of data in this buffer, but there might be another buffer waiting for us (or not).
//rprintf("waitingData taker iLoc: %X/%X iSDLoc: %X/%X iSampleLoc %X \n", channel->iLoc, channel->iEnd, mixingData->iSDLoc, waitingData->iSDLoc, iSampleLoc);
mixingData->Channel = -1; // flush if we finished mixing readingData before finishReading() got to it.
if(waitingData != NULL)
{
GRAPHDBG('W');
mixingData = waitingData;
waitingData = NULL;
}
else
{
if(mixingData != readingData)
{
GRAPHDBG('K');
mixingData = readingData;
}
else
{
mixingData = NULL;
FIOCLR = BIT(REDLED);
}
}
break;
}
if(channel->bLoop == 0)
{
// ABORT: sample is done playing.
channel->bActive = 0;
// waitingForFrame |= (1<<iChannel);
mixingData->Channel = -1; // flush if we finished mixing readingData before finishReading() got to it.
mixingData = NULL;
waitingData = NULL; // flush waiting data, this sample is finished and won't need that additional data.
break;
}
else
{
if(channel->iLoopStart >= mixingData->iSDLoc)
{
// Loop start is already in RAM, yay!
iSampleLoc = channel->iLoopStart - mixingData->iSDLoc;
waitingData = NULL; // sample has looped without needing waitingData, so it will never need waitingData.
}
else
{
// ABORT: we can't loop because the data in RAM doesn't go back that far.
if(readingData != NULL && mixingData->Channel == readingData->Channel)
{
// flush next data buffer down the toilet because this channel has
// looped and thus the next channel data is not going to be relevant when it finally finishes loading.
readingData->Channel = -1;
}
mixingData->Channel = -1; // flush if we finished mixing readingData before finishReading() got to it.
mixingData = NULL;
waitingData = NULL;
iLoc = channel->iLoopStart;
break;
}
}
}
// Load the new sample
// iSample = pSample[iSampleLoc];
// iTmpLFT = CALC_SAMPLE(iSample, iVolLeft);
// iTmpRGT = CALC_SAMPLE(iSample, iVolRight);
asm ("ldrsb %0, [%2, %3]" "\n\t"
"mov %1, %0" "\n\t"
"mul %0, %4" "\n\t"
"mul %1, %5" "\n\t"
/* output */ : "=r"(iTmpLFT), "=r"(iTmpRGT)
/* intput */ : "r"(pSample), "r"(iSampleLoc), "r"(iVolLeft), "r"(iVolRight)
/* clobber */ : "cc");
}
}
if(iLoc == -1)
{
channel->iLoc += iSampleLoc - iSampleLocBegin;
}
else
{
channel->iLoc = iLoc;
}
channel->iLocFract = iSampleLocFract;
if(pBuffer == audioBufferEnd)
{
channel->outputPointer = audioBuffer;
}
else
{
channel->outputPointer = pBuffer;
}
/*
if(pBuffer > audioBufferEnd)
{
rprintf("ERR MixPtr: %X audioBufferEnd: %X\n", channel->outputPointer, audioBufferEnd);
channel->outputPointer = audioBuffer;
}
*/
return i;
}
/**
* Given a mix pointer, determines how many pairs of samples (stereo) can be written to
* the audio buffer without hitting the currently playing pair of samples.
*
* @author edwards
* @date 4/18/2008
*/
int bufferLength(eint16* mixPtr /* tail */, eint16* playPtr /* head */)
{
if(mixPtr > playPtr)
{
return(((audioBufferEnd - mixPtr) + (playPtr - audioBuffer)) >> 1);
}
else
{
return((playPtr - mixPtr) >> 1);
}
}
/*
#define SCALEBITS 1
void PostProcess(unsigned int iPtr, unsigned int iLength)
{
eint32* p = (eint32*)&audioBuffer[iPtr];
unsigned int i;
for(i = 0; i < iLength; ++i, ++p)
{
*p = *p << 16;
}
}
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -