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

📄 ym3812.c

📁 这个是延伸mame的在wince平台下的游戏模拟器的代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*$DEADSERIOUSCLAN$********************************************************************** FILE*	Yamaha 3812 emulator - MAME VERSION** CREATED BY*	(c) Carl-Henrik Skarstedt, Dead Serious Clan. http://www.deadserious.com/** UPDATE LOG*	CHS 1998-10-16	Mame 0.34 specific version - Separated from general version** TO DO*	KSR correction*	Computer Speech Mode (requires real timers and a speech driver which makes testing a bit difficult) (later update)** Version 1.0 (fixed):* --------------------* This version of the ym3812 emulator is now released because it* works in several emulators. This emulator was created mainly due* to the crappy support of the compatible OPL3-SA chip on the* SoundBlaster PC card. The OPL chip on the SB is not permitted to* be used under Windows 95/98, and nothing happens when it is accessed* under Windows NT. Not all cards are SoundBlaster either, there are* much better and cheaper sound cards in the market today.* The emulator was first used in the Shark emulator from The Dead Serious Clan.** Legal:* ------* The ym3812 emulator may not be sold, or sold as a part of a commercial* package without the express written permission of Carl-Henrik Skarstedt* (carl@c64.org). This includes shareware.** Distribution:* -------------* Modified versions of the ym3812 emulator may not be publicly redistributed* without author approval (carl@c64.org). This includes distributing via a* publicly accessible LAN. You may make your own source modifications and* distribute the ym3812 emulator in source or object form, but if you make* modifications to the ym3812 emulator then it should be noted in the top* as a comment in ym3812.h and ym3812.cpp. Please also inform me of any* useful modifications of the source if redistributed (carl@c64.org).* The legal, distribution, licensing, guarantee, support and credits* sections in the file header may not be altered in redistributed modified* source form. The Mame version is available from the Mame source archive,* the non-Mame version is available on request to <carl@c64.org>** Licensing:* ----------* Licensing of ym3812 emulator for commercial applications is available.* Please email carl@c64.org for details.** Do the emulator come with any guarantee or author responsibility?* -----------------------------------------------------------------* No. It just plays some sounds, that's it. The source is provided "as-is".* The author can not be held responsible for any damage done by the use* of the ym3812 emulator. Any hardware patents or licensing infringements* issues are referred to the general legal status of emulation. No* intellectual property has been included from the original chip.** Support?* --------* Sure. I may not always have the time, but feel free to try* carl@c64.org for support.* The ym3812 emulator supports the following sound chips:* ym3526, ym3812, ym3814. The plan is to fix ym2413 as well.* If anyone can provide me with something that can run OPL2* speech, I can fix the Computer Speech Mode.** Credits:* --------* Please add something like "ym3812 emu by Carl-Henrik Skarstedt, DSC."* in your product if you use the emulator, or feel free to expand that in* any appropriate way. The "a" in my last name is supposed to have a* little ring over it if you manage to find that character (a under Win).** How to run the emulator:* ------------------------** You must get drum samples (see ym3812_pDrumNames for a list of* filenames of drums that are programmed into the OPL2 chip). These* samples are 8-bit unsigned .raw (no header) 11025 Hz.* I have unfortunately not got any freeware drum sounds available* at this time. I wish I had the st-01: floppy somewhere....** Initialize with:** // This will allocate a structure and initialize it* pOPL = ym3812_Init( int nReplayFrq, int nClock, int f16Bit );* pOPL->SetTimer = My_Timer_Code;** Where pOPL is the work structure for the ym3812 emulator and* My_Timer_Code handles timer control (You don't NEED to use* your own timers, but it is recommended. If you do not program* your own timers, ignore the second line)** The parameters for the Init function are:* nReplayFrq = The frequency you intend to play the generated sample with (for example 44100 Hz)* nClock = Set to ym3812_StdClock unless you know it is tweaked for something else.* f16Bit = false means generate 8 bit samples, true means generate 16 bit samples.** *1: If you use 16 bit sound, your buffer needs to be twice as big as the* number of samples you pass into the emulator.** Each (sound) frame do the following:* Call ym3812_SetBuffer( appropriate sound buffer )* Call ym3812_Update()** In the place where the hardware writes and reads the* OPL chip registers (2 addresses) do this:** Write to address 0: void ym3812_SetReg( ym3812*, Byte );* Read from address 0: Byte = ym3812_ReadStatus( ym3812* );* Write to address 1: void ym3812_WriteReg( ym3812*, Byte );* Read from address 1: Byte = ym3812_ReadReg( ym3812* );** When you're done emulating, Call ym3812_DeInit( ym3812* ) to free some memory.** If you wish the emulator to subdivide the generated sound* more than each frame ( refresh envelope, vibrato, etc.), put the* number of subdivisions in pOPL->nSubDivide after the initialization.** (And don't forget to replay the buffer)** How to use the timer emulation in the emulator:* -----------------------------------------------* First of all, use of this method is not recommended. Instead,* see below how to create your own timer code. If you still want to* use my placeholder timer routines, this is the way I use them.** Keep the define ym3812_AUTOMATIC which counts up the timers each frame.* Call ym3812_CheckTimer1Int() before the interrupt associated with the* timer. If it returns false you skip the interrupt. Make sure you* perform this check more often than the timers overflow, otherwise they* will only accumulate and not run fast enough. Usually you can get away* by calling the timerchecks two times for each screen frame. Perform the* same procedure with ym3812_CheckTimer2Int() if you have any interrupt* associated with that timer. I have not seen any example of this though.** You can also switch off ym3812_AUTOMATIC and call* ym3812_UpdateTimers( ym3812*, float Time ) with Time being the* (emulated) time between each call of ym3812_UpdateTimers.** Here's how code your own timers:* --------------------------------* Initialize the ym3812 emulator in this way:** pOPL = ym3812_Init();* pOPL->SetTimer = My_Timer_Code;** Where My_Timer_Code is a function that is called each time a timer* is created or removed. The timer will run continously, and generate* signals for the interrupt.** This pseudo code example will probably explain clearer than* just words how to handle the timer code:** void My_Timer_Code(int nTimer, float vPeriod, ym3812_s *pOPL, int fRemove)* {*	 switch( nTimer )*	 {*		case 1:*			if( fRemove )	timer_delete( __Timer1ID );*			else			timer_create( __Timer1ID, My_Timer_Event_1, vPeriod );*			break;*		case 2:*			if( fRemove )	timer_delete( __Timer2ID );*			else			timer_create( __Timer2ID, My_Timer_Event_2, vPeriod );*			break;*	 }* }** void My_Timer_Event_1()* {*	 if( ym3812_TimerEvent( pOPL, 1 ) ) Generate_Sound_Interrupt_From_Timer1();* }** And My_Timer_Event_2() would be similar to My_Timer_Event_1().** You _NEED_ to call ym3812_TimerEvent() to update the Status Register* and to find out if the timer is masked (not generating interrupts).* If you don't call ym3812_TimerEvent() the sound code emulation will* get confused and usually halts the whole game.** My_Timer_Code will ONLY be called when a Timer is to be created or deleted,* unless someone overwrites the timer control byte. The timer event will* of course be continous until the timer is removed.** (END OF INSTRUCTIONS AND WARRANTY INFORMATION)** NOTES*	MAX OPL volume per slot is 47.25 dB (internal note)*	The MAME define is meant to be symbolic to show what is specifically updated for MAME.*****************************************************************************************/#include <stdlib.h>#include <stdio.h>#include <math.h>#if !defined(macintosh) && !defined(ACORN) && !defined(openstep)#include <malloc.h>#include <memory.h>#endif#include "driver.h"#include "common.h"#include "ym3812.h"/* The number of entries in the sinus table! Do not change!*/#define SINTABLE_SIZE 8192#define SINTABLE_MAX 32767#define SINTABLE_SHIFT 15#define SINTABLE_SIZESHIFT 13/* These numbers define attack and decay/sustain rates*/#define cATTMUL 0.11597#define cDECMUL 0.6311*2#ifndef PI#define PI 3.141592654f#endif/*$DEADSERIOUSCLAN$********************************************************************** ARRAY*  int	RegSlot_Relation[] =* NOTES*  Gives the relation between address and slot...****************************************************************************************/int RegSlot_Relation[] ={	0x00,0x02,0x04,0x01,0x03,0x05,-1,-1,	0x06,0x08,0x0a,0x07,0x09,0x0b,-1,-1,	0x0c,0x0e,0x10,0x0d,0x0f,0x11,-1,-1,	  -1,  -1,	-1,  -1,  -1,  -1,-1,-1,};/*$DEADSERIOUSCLAN$********************************************************************** ROUTINE*  int ym3812_Multi[] = { 1,2,4,6,8,10,12,14,16,18,20,20,24,24,30,30 };* NOTES*  Gives the multi. This table is multiplied by 2 since 0 means 1/2.****************************************************************************************/int ym3812_Multi[] = { 1,2,4,6,8,10,12,14,16,18,20,20,24,24,30,30 };/*$DEADSERIOUSCLAN$********************************************************************** ROUTINE*  int16	aSinTable[SINTABLE_SIZE];* FUNCTION* NOTES****************************************************************************************/short	ym3812_aSinTable[4][SINTABLE_SIZE];/*$DEADSERIOUSCLAN$********************************************************************** ROUTINE*  float	ym3812_aAttackTime[16];*  float	ym3812_aDecayTime[16];* NOTES*  Time for attack and decay rates****************************************************************************************/float	ym3812_aAttackTime[16];float	ym3812_aDecayTime[16];/*$DEADSERIOUSCLAN$********************************************************************** ROUTINE*  char *ym3812_pDrumNames* FUNCTION* NOTES*  Sample file names for each drum****************************************************************************************/static const char *ym3812_pDrumNames[] ={	"bassdrum.sam",	"snardrum.sam",	"tomtom.sam",	"topcmbal.sam",	"hihat.sam",	0};/*$DEADSERIOUSCLAN$********************************************************************** ROUTINE*  ym3812* ym3812_Init( int nReplayFrq, int nClock, int f16Bit )* FUNCTION* NOTES****************************************************************************************/ym3812* ym3812_Init( int nReplayFrq, int nClock, int f16Bit ){	int 				k,l;	ym3812				*pOPL;	float				vValue;	struct GameSamples	*psSamples;	signed char 		*pDrum,*pDrum8;	signed short		*pDrum16;	pOPL = (ym3812*)malloc(sizeof(ym3812));	memset( pOPL, 0x00, sizeof(ym3812));	/* Set appropriate sample type (16bit or 8bit)*/	pOPL->f16Bit = f16Bit;	/* Insert stuff from host*/	pOPL->nReplayFrq = nReplayFrq;	pOPL->nYM3812Clk = nClock;	pOPL->nYM3812DivClk = nClock/72;	pOPL->SetTimer = NULL;	pOPL->vTimer1 = 0.01f;	pOPL->vTimer2 = 0.01f;	pOPL->nSubDivide = 1;	/* Generate some volume levels.. (ln)*/		vValue = (float)ym3812_StdVolume;	for( l=0 ; l<256 ; l++ )	{		pOPL->aVolumes[255-l] = (int)(vValue*128.0f+(255-l)/2);		vValue *= 0.985f;	}	/* Generate a sinus table*/	for( l=0 ; l<SINTABLE_SIZE ; l++ )	{		ym3812_aSinTable[0][l] = (short)(SINTABLE_MAX * sin( 2 * PI * l / SINTABLE_SIZE ));		ym3812_aSinTable[1][l] = (l<SINTABLE_SIZE/2) ? ym3812_aSinTable[0][l] : 0;		ym3812_aSinTable[2][l] = abs(ym3812_aSinTable[0][l]);		ym3812_aSinTable[3][l] = ~(l&(SINTABLE_SIZE/4)) ? ym3812_aSinTable[0][l] : 0;	}	/* Calculate attack and decay time (release is same as decay)*/	for( l=1 ; l<16 ; l++ )	{		ym3812_aAttackTime[l] = (float)(( 1<<(15-l) ) * cATTMUL)/1000.0f;		ym3812_aDecayTime[l] = (float)(( 1<<(15-l) ) * cDECMUL)/1000.0f;	}	ym3812_aAttackTime[0] = 0;	ym3812_aDecayTime[0] = 0;	/* Initialize all slots*/	for( l=0 ; l<18 ; l++ )	{		pOPL->vEnvTime[l] = 0.0f;			/* No time*/		pOPL->nEnvState[l] = ADSR_Silent;	/* Envelop is not playing*/		pOPL->nTotalLevel[l] = 0;			/* Envelop volume is 0*/		pOPL->fEGTyp[l] = cFALSE;		pOPL->fVibrato[l] = cFALSE;		pOPL->fAM[l] = cFALSE;		pOPL->fKSR[l] = cFALSE;		pOPL->nKSL[l] = 0;		pOPL->nMulti[l] = 0;		pOPL->nWave[l] = 0;		pOPL->nAttack[l] = 0x8;		pOPL->nDecay[l] = 0x8;		pOPL->nSustain[l] = 0x8;		pOPL->nRelease[l] = 0x8;		pOPL->nCurrPos[l] = rand() * SINTABLE_SIZE / RAND_MAX;	}	/* Initialize all channels*/	for( l=0; l<9; l++ )	{		pOPL->nFNumber[l]=0x100;		pOPL->nOctave[l]=0;		pOPL->nFeedback[l]=0;		pOPL->fConnection[l]=cFALSE;		pOPL->fKeyDown[l]=cFALSE;	}	/* Load Rhythm sounds*/	/* MAME version*/	psSamples = readsamples(ym3812_pDrumNames,"ym3812");	for( l=0; l<5; l++ )	{		pOPL->pDrum[l] = NULL;		pOPL->nDrumOffs[l] = -1;		if( psSamples->sample[l] != 0 )		{			pOPL->nDrumRate[l] = psSamples->sample[l]->smpfreq; 			/* Get frequency*/			pOPL->nDrumSize[l] = psSamples->sample[l]->length;				/* Get size*/			pOPL->pDrum[l] = (signed char*) malloc( pOPL->nDrumSize[l]+1024 );			memset( pOPL->pDrum[l], 0, pOPL->nDrumSize[l]+1024 );			/* Clear buffer*/			pDrum8 = psSamples->sample[l]->data;							/* Get ptr to sample*/			pDrum16 = (signed short*) pDrum8;								/* Get 16 bit ptr to sample*/			pDrum = pOPL->pDrum[l];			for( k=pOPL->nDrumSize[l]; k>0; k-- )			{				if( psSamples->sample[l]->resolution==16 )	*pDrum++ = (*pDrum16++)>>8;				else										*pDrum++ = *pDrum8++;			}		}	}	freesamples( psSamples );	return pOPL;}/*$DEADSERIOUSCLAN$********************************************************************** ROUTINE*  ym3812* ym3812_DeInit( ym3812 *pOPL )* FUNCTION* NOTES****************************************************************************************/ym3812* ym3812_DeInit( ym3812 *pOPL ){	int l;	if( pOPL != NULL )	{		for( l=0; l<5; l++ )		{			if( pOPL->pDrum[l]!=NULL ) free( pOPL->pDrum[l] );		}		free( pOPL );		pOPL = NULL;	}	return pOPL;}/*$DEADSERIOUS$******************************************************************** ROUTINE*	void ym3812_TimerOverflow( pOPL, int nTimer )* AUTHOR*	Carl-Henrik Skarstedt* FUNCTION/NOTES*	Call this every time a timer overflows.**********************************************************************************/int ym3812_TimerEvent( ym3812 *pOPL, int nTimer ){	switch( nTimer )	{		case 1:			if( (~pOPL->nTimerCtrl) & ym3812_TCMASK1)			{				pOPL->nStatus |= ym3812_STFLAG1|ym3812_STIRQ;				return cTRUE;			}			else			{				return cFALSE;	/* Masking timer 1*/			}		case 2:			if( (~pOPL->nTimerCtrl) & ym3812_TCMASK2)			{				pOPL->nStatus |= ym3812_STFLAG2|ym3812_STIRQ;				return cTRUE;			}			else			{				return cFALSE;	/* Masking timer 2*/			}	}

⌨️ 快捷键说明

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