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

📄 effects.c

📁 基于lpc2148(arm7)的wav音乐格式播放器的设计
💻 C
字号:
// -*- tab-width: 4 -*-
// TRAXMOD/ARM Digital Audio Player
//
// 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 "modplay/effects.h"
#include "modplay/music.h"
#include "modplay/mixer.h"
#include "modplay/modplay.h"

euint8 iEffectFlags;
euint8 iLoopRow;
euint8 iLoopCount;

eint16 VibrateTable[] =
	{   0, 24, 49, 74, 97,120,141,161,
	  180,197,212,224,235,244,250,253,
	  255,253,250,244,235,224,212,197,
	  180,161,141,120, 97, 74, 49, 24 };

inline euint8 Hex2Dec(euint8 iData)
{
	return ((iData & 0xF0) >> 4) * 10 + (iData & 0x0F);
}

void StartEffect(EventChannelType* eventChannel, euint8 iEffect, euint8 iData)
{
	switch(iEffect)
	{
		case 0x1: // Porta Up
		case 0x2: // Porta Down
		case 0x3: // Porta to Note
			if(iData != 0)
			{
				eventChannel->iPortaSpeed = iData;
			}
			eventChannel->iEffect = iEffect;
			eventChannel->iEffectData = iData;
			break;
			
		case 0x4: // Vibrato
			if(iData != 0)
			{
				eventChannel->iVibratoSpeed = iData;
			}
			
			if((eventChannel->iWaveform & 0x0F) < 4)
			{
				eventChannel->iVibratoPosition = 0;
			}
			
			// fall through...
			
		case 0x0: // Arpeggio
		case 0x5: // Porta to Note + Volume Slide
		case 0x6: // Vibrato + Volume Slide			
		case 0xA: // Volume Slide
			eventChannel->iEffect = iEffect;
			eventChannel->iEffectData = iData;
			break;

		case 0x7: // Tremolo
			if(iData != 0)
			{
				eventChannel->iTremoloSpeed = iData;
			}
			
			if(((eventChannel->iWaveform & 0xF0) >> 4) < 4)
			{
				eventChannel->iTremoloPosition = 0;
			}
			eventChannel->iEffect = iEffect;
			eventChannel->iEffectData = iData;
			break;
			
		case 0x8: // Set Pan
			eventChannel->iPan = iData;
			SetVolume(eventChannel, eventChannel->iVolume);
			break;
			
		case 0x9: // Set Sample Offset
			eventChannel->flags |= SET_iLoc;
			
			eventChannel->iLoc = (iData << 8);
			if(eventChannel->iLoc > eventChannel->sample->iLength)
			{
				eventChannel->iLoc = eventChannel->sample->iLength;
				eventChannel->flags |= SET_ACTIVE;
				eventChannel->flags &= ~IS_ACTIVE;
			}
			break;

		case 0xB: // Order Jump
			if(iData > iOrder)
			{
				SetOrder(iData);
			}
			iEffectFlags |= ORDER_JUMP;
			break;
			
		case 0xC: // Set Volume
			SetVolume(eventChannel, iData);
			break;
			
		case 0xD: // Pattern Break
			if((iEffectFlags & ORDER_JUMP) == 0)
			{
				SetOrder(iOrder + 1);
				iEffectFlags |= ORDER_JUMP;
			}
			iRow = Hex2Dec(iData);
			break;
			
		case 0xE:
			switch((iData & 0xF0) >> 4)
			{
				case 0: // Set filter
					break;
					
				case 1: // Fine Porta Up
					SetPeriodCheckLimits(eventChannel, eventChannel->iPeriod - (iData & 0x0F));
					break;
					
				case 2: // Fine Porta Down
					SetPeriodCheckLimits(eventChannel, eventChannel->iPeriod + (iData & 0x0F));
					break;
				
				case 3: // Set Glissando
					break;
				
				case 4: // Set Vibrato Waveform
					eventChannel->iWaveform = (eventChannel->iWaveform & 0xF0) | (iData & 0x0F);
					break;
					
				case 5: // Set Finetune
					eventChannel->iFinetune = (iData & 0x0F);
					break;
					
				case 6: // Loop Pattern
					if((iData & 0x0F) == 0)
					{
						// If we are already inside this loop, don't reset Loopcount
						if(iLoopCount == 0xFF)
						{
							// Set Loop Beginning
							iLoopRow = iRow - 1;
							iLoopCount = 0xFF;
						}
					}
					else
					{
						// Are we looping for the first time?
						if(iLoopCount == 0xFF)
						{
							iLoopCount = iData & 0x0F;
						}

						if(iLoopCount--)
						{
							iRow = iLoopRow;
						}
						else
						{
							iLoopCount = 0xFF;
						}
					}
					break;
				
				case 7: // Set Tremolo Waveform
					eventChannel->iWaveform = (eventChannel->iWaveform & 0x0F) | ((iData & 0x0F) << 4);
					break;
					
				case 8: // Set Pan
					eventChannel->iPan = (iData & 0x0F) << 3;
					SetVolume(eventChannel, eventChannel->iVolume);
					break;
					
				case 9: // Retrigger
				case 0xC: // Cut Sample
				case 0xD: // Delay sample
					eventChannel->iEffect = iEffect;
					eventChannel->iEffectData = iData;
					break;
					
				case 0xA: // Fine Volume Up
					SetVolume(eventChannel, eventChannel->iVolume + (iData & 0x0F));
					break;
					
				case 0xB: // Fine Volume Down
					SetVolume(eventChannel, eventChannel->iVolume - (iData & 0x0F));
					break;

				case 0xE: // Delay Pattern
					iPatternDelay = iData & 0x0F;
					break;
				
				case 0xF: // Invert Loop
					break;
			}
			break;
			
		case 0xF:
			if(iData > 32)
			{
				SetBPM(iData);
			}
			else if(iData > 0)
			{
				iTempoPeriod = iData;
			}
			break;
	}
}

/**
 * This procedure is called on each frame between rows to update
 * effects that may be in process.
 */
void DoEffects(void)
{
	for(int i = 0; i < CHANNELS; ++i)
	{
		EventChannelType *eventChannel = &EventChannel[i];
		euint8 iEffect = eventChannel->iEffect;
		euint8 iData = eventChannel->iEffectData;
		
		switch(iEffect)
		{
			case 0x0: // Arpeggio
				if(iData)
				{
					switch(iTempoCount % 3)
					{
						case 0:
//							SetPeriodCheckLimitsDontSetActive(p, p->iPeriod);
							break;
							
						case 1:
//							SetPeriodCheckLimitsDontSetActive(p, p->
							break;
						case 2:
							break;
					}
				}
				break;
			
			case 0x1: // Porta Up
				SetPeriodCheckLimits(eventChannel, eventChannel->iPeriod - eventChannel->iPortaSpeed);
				break;
				
			case 0x2: // Porta Down
				SetPeriodCheckLimits(eventChannel, eventChannel->iPeriod + eventChannel->iPortaSpeed);
				break;
			
			case 0x5: // Porta to Note + Volume Slide
				DoVolumeSlide(eventChannel, iData);
				// fall through...
				
			case 0x3: // Porta to Note
				DoPortaNote(eventChannel);
				break;
			
			case 0x6: // Vibrato + Volume Slide
				DoVolumeSlide(eventChannel, iData);
				// fall through...
				
			case 0x4: // Vibrato
				{
					int iDelta = 0;
					int iPos = eventChannel->iVibratoPosition & 0x1F;
					switch(eventChannel->iWaveform & 0x0F)
					{
						default:
						case 3:
						case 7:
						case 0:
						case 4:
							iDelta = VibrateTable[iPos];
							break;
							
						case 1:
						case 5:
							iPos <<= 3;
							if(eventChannel->iVibratoPosition > 31)
							{
								iPos = 255 - iPos;
							}
							iDelta = iPos;
							break;
							
						case 2:
						case 6:
							iDelta = 255;
							break;
					}
					
					iDelta = (iDelta * (eventChannel->iVibratoSpeed & 0x0F)) >> 7;
					if(eventChannel->iVibratoPosition > 31)
					{
						iDelta += eventChannel->iPeriod;
					}
					else
					{
						iDelta = eventChannel->iPeriod - iDelta;
					}
					
					SetPeriod(eventChannel, iDelta);
					
					eventChannel->iVibratoPosition += (eventChannel->iVibratoSpeed & 0xF0) >> 4;
					if(eventChannel->iVibratoPosition > 64)
					{
						eventChannel->iVibratoPosition -= 64;
					}
				}
				break;
				
			case 0x7: // Tremolo
				{
					int iDelta = 0;
					int iPos = eventChannel->iTremoloPosition & 0x1F;
					switch(((eventChannel->iWaveform) & 0xF0) >> 4)
					{
						default:
						case 3:
						case 7:
						case 0:
						case 4:
							iDelta = VibrateTable[iPos];
							break;
							
						case 1:
						case 5:
							iPos <<= 3;
							if(eventChannel->iTremoloPosition > 31)
							{
								iPos = 255 - iPos;
							}
							iDelta = iPos;
							break;
							
						case 2:
						case 6:
							iDelta = 255;
							break;
					}
					
					iDelta = (iDelta * (eventChannel->iTremoloSpeed & 0x0F)) >> 6;
					if(eventChannel->iTremoloPosition > 31)
					{
						iDelta += eventChannel->iVolume;
					}
					else
					{
						iDelta = eventChannel->iVolume - iDelta;
					}
					
					SetVolume(eventChannel, iDelta);
					
					eventChannel->iTremoloPosition += (eventChannel->iTremoloSpeed & 0xF0) >> 4;
					if(eventChannel->iTremoloPosition > 64)
					{
						eventChannel->iTremoloPosition -= 64;
					}
				}
				break;
				
			case 0xA: // Volume Slide
				DoVolumeSlide(eventChannel, iData);
				break;
				
			case 0xE: // Extended Effects
				switch((iData & 0xF0) >> 4)
				{
					case 0x9: // Retrigger
						if((iTempoCount % (iData & 0x0F)) == 0)
						{
							//SetSample(p, p->iSample);
							eventChannel->flags |= 
								SET_ACTIVE|IS_ACTIVE|SET_iLoc|SET_iLocFract;
							
							eventChannel->iLoc = 0;
							eventChannel->iLocFract = 0;
						}
						break;
						
					case 0xC: // Note Cut
						if((iData & 0x0F) == iTempoCount)
						{
							eventChannel->flags |= SET_ACTIVE;
							eventChannel->flags &= ~IS_ACTIVE;
							eventChannel->iVolume = 0;
						}
						break;
					case 0xD: // Note Delay
						if((iData & 0x0F) == iTempoCount)
						{
							eventChannel->flags |= SET_ACTIVE|IS_ACTIVE|SET_iLoc;
							eventChannel->iLoc = 0;
						}
						break;
				}
				break;
		}
	}
}

void DoPortaNote(EventChannelType* eventChannel)
{
	if(eventChannel->iPeriod > eventChannel->iPortaDest)
	{
		int iPeriod = eventChannel->iPeriod - eventChannel->iPortaSpeed;
		if(iPeriod < eventChannel->iPortaDest)
		{
			iPeriod = eventChannel->iPortaDest;
		}
		SetPeriodCheckLimits(eventChannel, iPeriod);					
	}
	else if(eventChannel->iPeriod < eventChannel->iPortaDest)
	{
		int iPeriod = eventChannel->iPeriod + eventChannel->iPortaSpeed;
		if(iPeriod > eventChannel->iPortaDest)
		{
			iPeriod = eventChannel->iPortaDest;
		}
		SetPeriodCheckLimits(eventChannel, iPeriod);					
	}
}

void DoVolumeSlide(EventChannelType* eventChannel, euint8 iSpeed)
{
	SetVolume(eventChannel, (eventChannel->iVolume - (iSpeed & 0x0F)) + ((iSpeed & 0xF0) >> 4));
}

⌨️ 快捷键说明

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