⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mixer.c

📁 基于lpc2148(arm7)的wav音乐格式播放器的设计
💻 C
📖 第 1 页 / 共 2 页
字号:
	}
		
	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 + -