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

📄 mixer.c

📁 基于lpc2148(arm7)的wav音乐格式播放器的设计
💻 C
📖 第 1 页 / 共 2 页
字号:
// -*- tab-width: 4 -*-
// TRAXMOD Audio Mixer
//
// Copyright (c) 2006-2008, K9spud LLC.
// http://www.k9spud.com/traxmod/
//
// 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; either version 2
// of the License, or (at your option) any later version.
//
// 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.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

#include "main.h"
#include "mixer.h"
#include "modplay.h"
#include "music.h"
#include "mmc.h"

#include "uart.h"

#include "interfaces/lpc2000_dbg_printf.h"
#define rprintf lpc2000_debug_printf

int mix(MixChannelType *mixChannel, unsigned int iLength);

unsigned int iFramePeriod;
int frameCountdown = 0;
eint16* framePointer;
unsigned int waitForFrame;
//int skipMisaligned = 0x100;

MixChannelType MixChannel[CHANNELS];

StreamDataType StreamData[2];
StreamDataType* readingData = NULL;	// data that is being read into RAM and will be ready for mixing eventually
StreamDataType* mixingData  = NULL;	// data that has been fully read into RAM and ready for mixing
StreamDataType* waitingData = NULL;	// data that is has been read into RAM, but is not being mixed until the mixingData buffer is finished mixing.

//euint8 readingChannel = -1;

void startNextReader(void)
{
	// Choose the data buffer to read into next: use buffer that is not being mixed.
	readingData = &StreamData[0];
	if(mixingData == readingData)
	{
		// mixer is using buffer 0, so lets read into buffer 1 instead.
		readingData = &StreamData[1];
	}
	
	euint8 bCurrentChannelIsActive = 0;
	int nextChannel = -1;
	MixChannelType* channel;

/*
	for(int i = 0; i < iNumChannels; i++)
	{
		readingChannel++;
		if(readingChannel >= iNumChannels)
		{
			readingChannel = 0;
		}
		
		channel = &MixChannel[readingChannel];
		
		if(channel->bActive)
		{
			nextChannel = readingChannel;
			break;
		}
	}
*/


	int j;
	int biggestLength = 0;
	int smallestMisalignment = iSD_BlockLength;

	for(int i = 0; i < iNumChannels; i++)
	{
		channel = &MixChannel[i];
		if(channel->bActive == 0)
		{
			// ABORT: this channel is not active, no need to load data for it
			continue;
		}
		
		if(mixingData == NULL)
		{
			// mixer starving, give priority to most aligned data channel first.
			j = (channel->iSDLocation + channel->iLoc) & 0x1FF;
			if(j <= smallestMisalignment)
			{
				// this channel's data has the smallest block misalignment of all channels.

				if(bufferLength(channel->outputPointer, playPointer) < 70)
				{
					// but this channel doesn't have much room to mix into right now, so it's not really going
					// to help us to mix it first. skip it.
					if(nextChannel == -1)
					{
						// well, we don't have any other candidates, so let's put this one up
						// on the roster, but don't list it's block misalignment number, in case some
						// other channel comes along.
						nextChannel = i;
					}
				}
				else
				{
					nextChannel = i;
					smallestMisalignment = j;
				}
			}
		}
		else
		{
			if(i == mixingData->Channel)
			{
				// ABORT: don't want to re-read the channel that is already read and being mixed.
				bCurrentChannelIsActive = 1;	// but if it's the only active channel, we might want to use it afterall
				continue;
			}

			// mixer is working, use aggressive priority algorithm instead.
			j = bufferLength(channel->outputPointer, playPointer);
			if(j > biggestLength)
			{
				// This channel has more mix buffer to fill than any other channel.
				// Make it the next channel to mix.
				nextChannel = i;
				biggestLength = j;
			}
		}
		
	}

	if(nextChannel == -1)
	{
		// couldn't find a new channel to mix next.
		
		if(bCurrentChannelIsActive == 0 || waitingData != NULL)
		{
			// No channels are actively playing, so we don't need to load any more data at the moment.

			// Or: the current mix channel is the only one actively playing right now, 
			// and it already has more data waiting in RAM, so we don't need to read more right now.

			readingData = NULL;
			GRAPHDBG('R');
			return;
		}
		
		readingData->Channel = mixingData->Channel;
		channel = &MixChannel[readingData->Channel];

		// load data one SD Card block ahead of the currently mixing RAM data buffer.
		readingData->iSDLoc = mixingData->iSDLoc + iSD_BlockLength;
	}
	else
	{
		// we found a new channel to mix next, start loading its data from the SD Card
		waitingData = NULL; // dump waiting data (if any), we've got a higher priority channel data to read.
		readingData->Channel = nextChannel;
		channel = &MixChannel[nextChannel];

		// load data beginning at the current mix location of the sample data.
		readingData->iSDLoc = channel->iLoc;

		if(readingData->iSDLoc > channel->iEnd)
		{
			// wait a minute, this is past the end of the sample's data, why bother loading this??
			rprintf("channel: %d SDLoc: %X Loc: %X End: %X\n", readingData->Channel, readingData->iSDLoc, channel->iLoc, channel->iEnd);
		}
	}

	if(readingData->iSDLoc > channel->iEnd)
	{
		// wait a minute, this is past the end of the sample's data, why bother loading this??
		readingData = NULL;		
		GRAPHDBG('H');
		return;
	}
	SD_BeginRead(channel->iSDLocation + readingData->iSDLoc, (unsigned char*)readingData->Data, iSD_BlockLength);
	
/*
	// unfortunately, this optimization causes some MODs to crash the player, dunno why.
	if(mixingData == NULL)
	{
		mixingData = readingData;
		GRAPHDBG('g');
	}
	else
	{
		GRAPHDBG('r');
	}
n*/
}

void stopSD(void)
{
	if(readingData != NULL)
	{
		while(BytesLeftToRead != 0); // wait until done reading block
		SD_StopTransmission();
		readingData = NULL;
	}

	waitingData = NULL;
	mixingData = NULL;
}


void printStatus(int i)
{
	MixChannelType* channel;

	rprintf("%X - Speed: %X Tempo: %d Row: %X Pat: %X playPtr: %X frmCnt: %d frmPtr: %X playFrame: %X waitForFrm: %X active[", 
		SSPIMSC, iFramePeriod, iTempoPeriod, iRow, iPattern, playPointer, frameCountdown, 
		framePointer, playingFrame, waitForFrame);
	
	for(int x = 0; x < iNumChannels; x++)
	{
		channel = &MixChannel[x];
		if(channel->bActive)
		{
			uart0Putch('1');
		}
		else
		{
			uart0Putch('0');
		}
	}
	
	if(mixingData != NULL)
	{
		channel = &MixChannel[mixingData->Channel];
		rprintf("] mixing: %d[%X %X/%X SDPHY: %X] %X ", mixingData->Channel, 
				mixingData->iSDLoc, channel->iLoc, mixingData->Length,
				channel->iSDLocation + mixingData->iSDLoc, channel->outputPointer);
	}
	else
	{
		rprintf("] not mixing ");
	}
	
	if(waitingData != NULL)
	{
		rprintf("waiting: %d[%X] ", waitingData->Channel, waitingData->iSDLoc);
		if(waitingData == mixingData)
		{
			rprintf("waiting==mixing ");
		}
	}

	if(readingData != NULL)
	{
		rprintf("reading: %d[%X] len: %X(%X)", readingData->Channel, readingData->iSDLoc, 
			readingData->Length, BytesLeftToRead);
	}
	else
	{
		rprintf("not reading");	
	}
	
	rprintf("\n");
	
	for(int x = 0; x < iNumChannels; x++)
	{		
		channel = &MixChannel[x];
		rprintf("%d(frmNo: %X outPtr: %X a? %X)", x, channel->mixingFrame, channel->outputPointer, channel->bActive);
	}
	rprintf("\n");
}

void finishReading(void)
{
/*
	if(readingData->Channel == -1)
	{
		// abort read early -- mixer has already stopped using this channel data
	}
	*/
	if(BytesLeftToRead == 0)
	{
		// Done reading next channel's data from SD Card, tell the SD Card to stop
		// sending us data.
		SD_StopTransmission();

		// We have new data read into RAM, mark it as ready to be mixed.			
		
		if(readingData->Channel == -1 || mixingData == readingData)
		{
			// if readingData->Channel equals -1, the mixer has decided to flush this data from
			// being mixed (sample looped back before we could use this data).
			readingData = NULL;
			GRAPHDBG('f');
		}
		else if(mixingData == NULL || mixingData->Channel != readingData->Channel)
		{
			// force mixer to switch channels so that we can keep the SD card busy loading
			// another channel's data into RAM.				
			mixingData = readingData;
			readingData = NULL;	// flag that we're ready to start reading more data
			GRAPHDBG('s');
		}
		else
		{
			// the next buffer is for the same channel as the currently mixing channel.
			// we can not switch RAM buffers until the mixer completely uses up the current RAM buffer.
			waitingData = readingData;
			readingData = NULL; // flag that we can potentially read more data, if it is higher priority than the waitingData.
			GRAPHDBG('w');
		}
	}
}

int doMix(void)
{
	MixChannelType* channel;
	
//	printStatus(0);
	if(readingData != NULL)
	{
		finishReading();
	}

	if(framePointer != NULL)
	{
		euint8 stillMixingOldFrame = 0;
		EventChannelType* eventChannel;
		for(int i = 0; i < iNumChannels; i++)
		{
			channel = &MixChannel[i];
			if(channel->mixingFrame < playingFrame)
			{
				if((channel->bActive == 0) || (channel->outputPointer == framePointer))
				{
					eventChannel = &EventChannel[i];

					copyEventToChannel(channel, eventChannel);				
					channel->mixingFrame = playingFrame;
					channel->outputPointer = framePointer;
				}
				else
				{
					stillMixingOldFrame++;
				}
			}
		}

		if(stillMixingOldFrame == 0)
		{
			FrameInterrupt();
			framePointer = NULL;
			//printStatus(0);
		}
	}

	if(readingData == NULL)
	{
		if(filterFlags & FILTER_DIRTY)
		{
			// give the system a chance to write DAC control registers
			return 0;
		}
		
		startNextReader();
	}

//	printStatus(1);

	if(mixingData == NULL)
	{
		// ABORT: no channel data to mix and nothing being read, can't do jack right now.
		FIOSET = BIT(REDLED);
		for(int i = 0; i < iNumChannels; i++)
		{
			if(MixChannel[i].bActive)
			{
				// no data, but this channel is active, show warning red light.
				FIOCLR = BIT(REDLED);
				return 0;
			}
		}
		
		return 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -