From 85d9163a63c4654af6abf51681afe192de8e1034 Mon Sep 17 00:00:00 2001 From: "R. Belmont" Date: Thu, 19 Jun 2008 16:21:46 +0000 Subject: [PATCH] MultiPCM/315-5560 rewrite by ElSemi. All features are now supported including PLFO and ALFO. --- src/emu/sound/multipcm.c | 988 +++++++++++++++++++++++---------------- 1 file changed, 581 insertions(+), 407 deletions(-) diff --git a/src/emu/sound/multipcm.c b/src/emu/sound/multipcm.c index d6ee7e9adb3..e69fdcd0a9d 100644 --- a/src/emu/sound/multipcm.c +++ b/src/emu/sound/multipcm.c @@ -1,29 +1,33 @@ /* - * Sega System 32 Multi/Model 1 custom PCM chip (315-5560) emulation. + * Sega System 32 Multi/Model 1/Model 2 custom PCM chip (315-5560) emulation. * - * by R. Belmont. Info from AMUSE, Hoot, and the YMF278B (OPL4). - * This chip is sort of a dry run for the PCM section of the YMF278B, - * and it has many obvious similarities to that chip. + * by Miguel Angel Horna (ElSemi) for Model 2 Emulator and MAME. + * Information by R.Belmont and the YMF278B (OPL4) manual. * * voice registers: - * 0: pan - * 1: sample to play (PCM chip uses table to figure out) - * 2: LSB of pitch - * 3: MSB of pitch + * 0: Pan + * 1: Index of sample + * 2: LSB of pitch (low 2 bits seem unused so) + * 3: MSB of pitch (ooooppppppppppxx) (o=octave (4 bit signed), p=pitch (10 bits), x=unused? * 4: voice control: top bit = 1 for key on, 0 for key off - * 5: bit 0: loop, bits 1-7 = volume attenuate (0=max, 7f=min) - * 6: LFO (OutRunners engine, singing man in Daytona) - * 7: LFO + * 5: bit 0: 0: interpolate volume changes, 1: direct set volume, + bits 1-7 = volume attenuate (0=max, 7f=min) + * 6: LFO frequency + Phase LFO depth + * 7: Amplitude LFO size * * The first sample ROM contains a variable length table with 12 - * bytes per instrument/sample. The end of the table is marked - * by 12 bytes of 0xFF. This is very similar to the YMF278B. + * bytes per instrument/sample. This is very similar to the YMF278B. * * The first 3 bytes are the offset into the file (big endian). * The next 2 are the loop start offset into the file (big endian) * The next 2 are the 2's complement of the total sample size (big endian) - * The next byte is unknown. - * The next 3 are envelope attack / decay / release parameters (not yet emulated) + * The next byte is LFO freq + depth (copied to reg 6 ?) + * The next 3 are envelope params (Attack, Decay1 and 2, sustain level, release, Key Rate Scaling) + * The next byte is Amplitude LFO size (copied to reg 7 ?) + * + * TODO + * - The YM278B manual states that the chip supports 512 instruments. The MultiPCM probably supports them + * too but the high bit position is unknown (probably reg 2 low bit). Any game use more than 256? * */ @@ -33,99 +37,388 @@ #include "streams.h" #include "multipcm.h" -#define MULTIPCM_CLOCKDIV (360.0) -#define MULTIPCM_ONE (18) -#define ICLIP16(x) (x<-32768)?-32768:((x>32767)?32767:x) +//¿?¿? +#define MULTIPCM_CLOCKDIV (180.0) -static const int ctbl[] = +struct _Sample { - 0, 1, 2, 3, 4, 5, 6 , -1, // voice number mapping + unsigned int Start; + unsigned int Loop; + unsigned int End; + unsigned char AR,DR1,DR2,DL,RR; + unsigned char KRS; + unsigned char LFOVIB; + unsigned char AM; +}; + +typedef enum {ATTACK,DECAY1,DECAY2,RELEASE} _STATE; +struct _EG +{ + int volume; // + _STATE state; + int step; + //step vals + int AR; //Attack + int D1R; //Decay1 + int D2R; //Decay2 + int RR; //Release + int DL; //Decay level +}; + +struct _LFO +{ + unsigned short phase; + UINT32 phase_step; + int *table; + int *scale; +}; + + +struct _SLOT +{ + unsigned char Num; + unsigned char Regs[8]; + int Playing; + struct _Sample *Sample; + unsigned int Base; + unsigned int offset; + unsigned int step; + unsigned int Pan,TL; + unsigned int DstTL; + int TLStep; + signed int Prev; + struct _EG EG; + struct _LFO PLFO; //Phase lfo + struct _LFO ALFO; //AM lfo +}; + +struct _MultiPCM +{ + sound_stream * stream; + struct _Sample Samples[0x200]; //Max 512 samples + struct _SLOT Slots[28]; + unsigned int CurSlot; + unsigned int Address; + unsigned int BankR,BankL; + float Rate; + INT8 *ROM; + //I include these in the chip because they depend on the chip clock + unsigned int ARStep[0x40],DRStep[0x40]; //Envelope step table + unsigned int FNS_Table[0x400]; //Frequency step table +}; + + +static signed int LPANTABLE[0x800],RPANTABLE[0x800]; + +#define FIX(v) ((UINT32) ((float) (1<EG.state) { - int inum = mpcm->registers[j][1] | ((mpcm->registers[j][2]&0x1)<<8); - mpcm->Voices[j].pSamp = &mpcm->romptr[mpcm->samples[inum].st]; + case ATTACK: + slot->EG.volume+=slot->EG.AR; + if(slot->EG.volume>=(0x3ff<EG.state=DECAY1; + if(slot->EG.D1R>=(0x400<EG.state=DECAY2; + slot->EG.volume=0x3ff<EG.volume-=slot->EG.D1R; + if(slot->EG.volume<=0) + slot->EG.volume=0; + if(slot->EG.volume>>EG_SHIFT<=(slot->EG.DL<<(10-4))) + slot->EG.state=DECAY2; + break; + case DECAY2: + slot->EG.volume-=slot->EG.D2R; + if(slot->EG.volume<=0) + slot->EG.volume=0; + break; + case RELEASE: + slot->EG.volume-=slot->EG.RR; + if(slot->EG.volume<=0) + { + slot->EG.volume=0; + slot->Playing=0; + } + break; + default: + return 1<EG.volume>>EG_SHIFT]; +} + +unsigned int Get_RATE(unsigned int *Steps,unsigned int rate,unsigned int val) +{ + int r=4*val+rate; + if(val==0) + return Steps[0]; + if(val==0xf) + return Steps[0x3f]; + if(r>0x3f) + r=0x3f; + return Steps[r]; +} + +static void EG_Calc(struct _MultiPCM *ptChip,struct _SLOT *slot) +{ + int octave=((slot->Regs[3]>>4)-1)&0xf; + int rate; + if(octave&8) octave=octave-16; + if(slot->Sample->KRS!=0xf) + rate=(octave+slot->Sample->KRS)*2+((slot->Regs[3]>>3)&1); + else + rate=0; + + slot->EG.AR=Get_RATE(ptChip->ARStep,rate,slot->Sample->AR); + slot->EG.D1R=Get_RATE(ptChip->DRStep,rate,slot->Sample->DR1); + slot->EG.D2R=Get_RATE(ptChip->DRStep,rate,slot->Sample->DR2); + slot->EG.RR=Get_RATE(ptChip->DRStep,rate,slot->Sample->RR); + slot->EG.DL=0xf-slot->Sample->DL; + +} + +/***************************** + LFO SECTION +*****************************/ + +#define LFO_SHIFT 8 + + +#define LFIX(v) ((unsigned int) ((float) (1<phase+=LFO->phase_step; + p=LFO->table[(LFO->phase>>LFO_SHIFT)&0xff]; + p=LFO->scale[p+128]; + return p<<(SHIFT-LFO_SHIFT); +} + +static signed int inline ALFO_Step(struct _LFO *LFO) +{ + int p; + LFO->phase+=LFO->phase_step; + p=LFO->table[(LFO->phase>>LFO_SHIFT)&0xff]; + p=LFO->scale[p]; + return p<<(SHIFT-LFO_SHIFT); +} + +static void LFO_ComputeStep(struct _MultiPCM *ptChip,struct _LFO *LFO,UINT32 LFOF,UINT32 LFOS,int ALFO) +{ + float step=(float) LFOFreq[LFOF]*256.0/(float) ptChip->Rate; + LFO->phase_step=(unsigned int) ((float) (1<table=ALFO_TRI; + LFO->scale=ASCALES[LFOS]; + } + else + { + LFO->table=PLFO_TRI; + LFO->scale=PSCALES[LFOS]; + } +} + + + +void WriteSlot(struct _MultiPCM *ptChip,struct _SLOT *slot,int reg,unsigned char data) +{ + slot->Regs[reg]=data; + + switch(reg) + { + case 0: //PANPOT + slot->Pan=(data>>4)&0xf; + break; + case 1: //Sample + //according to YMF278 sample write causes some base params written to the regs (envelope+lfos) + //the game should never change the sample while playing. + { + struct _Sample *Sample=ptChip->Samples+slot->Regs[1]; + WriteSlot(ptChip,slot,6,Sample->LFOVIB); + WriteSlot(ptChip,slot,7,Sample->AM); + } + break; + case 2: //Pitch + case 3: + { + unsigned int oct=((slot->Regs[3]>>4)-1)&0xf; + unsigned int pitch=((slot->Regs[3]&0xf)<<6)|(slot->Regs[2]>>2); + pitch=ptChip->FNS_Table[pitch]; + if(oct&0x8) + pitch>>=(16-oct); + else + pitch<<=oct; + slot->step=pitch/ptChip->Rate; + } + break; + case 4: //KeyOn/Off (and more?) + { + if(data&0x80) //KeyOn + { + slot->Sample=ptChip->Samples+slot->Regs[1]; + slot->Playing=1; + slot->Base=slot->Sample->Start; + slot->offset=0; + slot->Prev=0; + slot->TL=slot->DstTL<EG.state=ATTACK; + slot->EG.volume=0; + + if(slot->Base>=0x100000) + { + if(slot->Pan&8) + slot->Base=(slot->Base&0xfffff)|(ptChip->BankL); + else + slot->Base=(slot->Base&0xfffff)|(ptChip->BankR); + } + + } + else + { + if(slot->Playing) + { + if(slot->Sample->RR!=0xf) + slot->EG.state=RELEASE; + else + slot->Playing=0; + } + } + } + break; + case 5: //TL+Interpolation + { + slot->DstTL=(data>>1)&0x7f; + if(!(data&1)) //Interpolate TL + { + if((slot->TL>>SHIFT)>slot->DstTL) + slot->TLStep=TLSteps[0]; //decrease + else + slot->TLStep=TLSteps[1]; //increase + } + else + slot->TL=slot->DstTL<PLFO),(slot->Regs[6]>>3)&7,slot->Regs[6]&7,0); + LFO_ComputeStep(ptChip,&(slot->ALFO),(slot->Regs[6]>>3)&7,slot->Regs[7]&7,1); + } + } + break; + case 7: //ALFO + { + if(data) + { + LFO_ComputeStep(ptChip,&(slot->PLFO),(slot->Regs[6]>>3)&7,slot->Regs[6]&7,0); + LFO_ComputeStep(ptChip,&(slot->ALFO),(slot->Regs[6]>>3)&7,slot->Regs[7]&7,1); + } + } + break; } } static void MultiPCM_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length ) { - MultiPCMT *mpcm = param; + struct _MultiPCM *ptChip = param; stream_sample_t *datap[2]; - int i, j; - signed long lvol, rvol, mlvol, mrvol; - INT8 *pSamp; - long cnt, ptsum, ptoffset, ptdelta, end; - VoiceT *vptr; - float decTemp; - char relstage; - int relcount, relamt; - float invrelamt; + int i,sl; datap[0] = buffer[0]; datap[1] = buffer[1]; @@ -133,366 +426,246 @@ static void MultiPCM_update(void *param, stream_sample_t **inputs, stream_sample memset(datap[0], 0, sizeof(*datap[0])*length); memset(datap[1], 0, sizeof(*datap[1])*length); - for (j = 0; j < 28; j++) + + for(i=0;iVoices[j]; - - // is voice playing? - if ((vptr->active) || (vptr->relstage)) - { // only calculate volume once per voice per update cycle - rvol = mpcm->pantbl[vptr->pan]; - lvol = mpcm->pantbl[15-vptr->pan]; - - mrvol = rvol = (rvol * vptr->vol)>>8; - mlvol = lvol = (lvol * vptr->vol)>>8; - - decTemp = 1.0f; - - // copy our "working set" into locals - ptsum = vptr->ptsum; - ptoffset = vptr->ptoffset; - ptdelta = vptr->ptdelta; - end = vptr->end; - pSamp = vptr->pSamp; - relstage = vptr->relstage; - relcount = vptr->relcount; - relamt = vptr->relamt; - invrelamt = 1.f / (float)relamt; - - for (i = 0; i < length; i++) + signed int smpl=0; + signed int smpr=0; + for(sl=0;sl<28;++sl) + { + struct _SLOT *slot=ptChip->Slots+sl; + if(slot->Playing) { - cnt = ptsum >> MULTIPCM_ONE; - ptsum &= ((1<TL>>SHIFT)|(slot->Pan<<7); + unsigned int adr=slot->offset>>SHIFT; + signed int sample; + unsigned int step=slot->step; + signed int csample=(signed short) (ptChip->ROM[slot->Base+adr]<<8); + signed int fpart=slot->offset&((1<Prev*((1<>SHIFT; - if (ptoffset >= end) + if(slot->Regs[6]&7) //Vibrato enabled { - if (vptr->loop) - { - ptoffset = vptr->loopst; - } - else - { - vptr->active = 0; - break; - } + step=step*PLFO_Step(&(slot->PLFO)); + step>>=SHIFT; } - if (relstage) + slot->offset+=step; + if(slot->offset>=(slot->Sample->End< relamt) - { - relstage = 0; - vptr->relstage = 0; - break; - } - - if(relamt!=0) - { - decTemp = 1.0f - (relcount * invrelamt); - } - else - { - decTemp=0; - } - - lvol = mlvol * decTemp; - rvol = mrvol * decTemp; + slot->offset=slot->Sample->Loop<offset>>SHIFT)) + { + slot->Prev=csample; } - ptsum += ptdelta; + if((slot->TL>>SHIFT)!=slot->DstTL) + slot->TL+=slot->TLStep; - datap[0][i] += ICLIP16((pSamp[ptoffset] * lvol)>>2); - datap[1][i] += ICLIP16((pSamp[ptoffset] * rvol)>>2); + if(slot->Regs[7]&7) //Tremolo enabled + { + sample=sample*ALFO_Step(&(slot->ALFO)); + sample>>=SHIFT; + } + + sample=(sample*EG_Update(slot))>>10; + + smpl+=(LPANTABLE[vol]*sample)>>SHIFT; + smpr+=(RPANTABLE[vol]*sample)>>SHIFT; } - - // copy back the working values we need to keep - vptr->ptsum = ptsum; - vptr->ptoffset = ptoffset; - vptr->relcount = relcount; } +#define ICLIP16(x) (x<-32768)?-32768:((x>32767)?32767:x) + datap[0][i]=ICLIP16(smpl); + datap[1][i]=ICLIP16(smpr); } } +unsigned char MultiPCM_reg_r(int chip, int offset) +{ +// struct _MultiPCM *ptChip = sndti_token(SOUND_MULTIPCM, chip); + return 0; +} + static void *multipcm_start(int sndindex, int clock, const void *config) { + struct _MultiPCM *ptChip; int i; - double unity = (double)(1<ROM=(INT8 *)memory_region(intf->region); + ptChip->Rate=(float) clock / MULTIPCM_CLOCKDIV; - for (i = 0; i < 128; i++) + ptChip->stream = stream_create(0, 2, ptChip->Rate, ptChip, MultiPCM_update); + + //Volume+pan table + for(i=0;i<0x800;++i) { - mpcm->voltbl[i]=max; - max /= pow(10.0,db/20.0); - } - mpcm->voltbl[127]=0; + float SegaDB=0; + float TL; + float LPAN,RPAN; - // make pan table - for(i=0; i<16; i++) - { - mpcm->pantbl[i]=(long)( (255/sqrt(15)) * sqrt(i)); - } + unsigned char iTL=i&0x7f; + unsigned char iPAN=(i>>7)&0xf; - mpcm->curreg = mpcm->curvoice = 0; + SegaDB=(float) iTL*(-24.0)/(float) 0x40; - mpcm->romptr = (INT8 *)memory_region(intf->region); + TL=pow(10.0,SegaDB/20.0); + - for (i = 0; i < 28; i++) - { - mpcm->Voices[i].active = 0; - mpcm->Voices[i].ptsum = 0; - mpcm->Voices[i].ptoffset = 0; - mpcm->Voices[i].loop = 0; - mpcm->Voices[i].loopst = 0; - mpcm->Voices[i].end = 0; - mpcm->Voices[i].pan = 0; - mpcm->Voices[i].vol = 0; - mpcm->Voices[i].relamt = 0; - mpcm->Voices[i].relcount = 0; - mpcm->Voices[i].relstage = 0; - } + if(iPAN==0x8) + { + LPAN=RPAN=0.0; + } + else if(iPAN==0x0) + { + LPAN=RPAN=1.0; + } + else if(iPAN&0x8) + { + LPAN=1.0; + + iPAN=0x10-iPAN; - mpcm->stream = stream_create(0, 2, clock / MULTIPCM_CLOCKDIV, mpcm, MultiPCM_update); + SegaDB=(float) iPAN*(-12.0)/(float) 0x4; - // make pitch delta table (1 octave) - for(i=0; i<0x1001; i++) - { - mpcm->dlttbl[i] = (long)(unity * (1.0 + ((double)i / 4096.0))); - } + RPAN=pow(10.0,SegaDB/20.0); - // precalculate the PCM data for a small speedup - phdr = (UINT8 *)mpcm->romptr; - for(i = 0; i < 511; i++) - { - idx = i*12; - nowadrs = (phdr[idx + 0]<<16) + (phdr[idx + 1]<<8) + (phdr[idx + 2]); - - if((nowadrs == 0)||(nowadrs==0xffffff)) - { // invalid entry - mpcm->samples[i].st=0; - mpcm->samples[i].size=0; + if((iPAN&0x7)==7) + RPAN=0.0; } else { - mpcm->samples[i].st = nowadrs; - mpcm->samples[i].loop = (phdr[idx + 3]<<8) + (phdr[idx + 4]); - mpcm->samples[i].size = 0xffff - ((phdr[idx + 5]<<8) + (phdr[idx + 6])); - mpcm->samples[i].env[0] = phdr[idx + 8]; - mpcm->samples[i].env[1] = phdr[idx + 9]; - mpcm->samples[i].env[2] = phdr[idx + 10]; + RPAN=1.0; + + SegaDB=(float) iPAN*(-12.0)/(float) 0x4; + + LPAN=pow(10.0,SegaDB/20.0); + if((iPAN&0x7)==7) + LPAN=0.0; } + + TL/=4.0; + + LPANTABLE[i]=FIX((LPAN*TL)); + RPANTABLE[i]=FIX((RPAN*TL)); } - /* set up the save state info */ + //Pitch steps + for(i=0;i<0x400;++i) { - int v; - char mname[20]; - - sprintf(mname, "MultiPCM %d", sndindex); - - state_save_register_item(mname, sndindex, mpcm->bankL); - state_save_register_item(mname, sndindex, mpcm->bankR); - - state_save_register_item_2d_array(mname, sndindex, mpcm->registers); - - for (v = 0; v < 28; v++) - { - char mname2[32]; - - sprintf(mname2, "MultiPCM %d v %d", sndindex, v); - - state_save_register_item(mname2, sndindex, mpcm->Voices[v].active); - state_save_register_item(mname2, sndindex, mpcm->Voices[v].loop); - state_save_register_item(mname2, sndindex, mpcm->Voices[v].end); - state_save_register_item(mname2, sndindex, mpcm->Voices[v].loopst); - state_save_register_item(mname2, sndindex, mpcm->Voices[v].pan); - state_save_register_item(mname2, sndindex, mpcm->Voices[v].vol); - state_save_register_item(mname2, sndindex, mpcm->Voices[v].ptdelta); - state_save_register_item(mname2, sndindex, mpcm->Voices[v].ptoffset); - state_save_register_item(mname2, sndindex, mpcm->Voices[v].ptsum); - state_save_register_item(mname2, sndindex, mpcm->Voices[v].relamt); - state_save_register_item(mname2, sndindex, mpcm->Voices[v].relstage); - } - - state_save_register_item(mname, sndindex, mpcm->curreg); - state_save_register_item(mname, sndindex, mpcm->curvoice); + float fcent=ptChip->Rate*(1024.0+(float) i)/1024.0; + ptChip->FNS_Table[i]=(unsigned int ) ((float) (1<ARStep[i]=(float) (0x400<DRStep[i]=(float) (0x400<ARStep[0]=ptChip->ARStep[1]=ptChip->ARStep[2]=ptChip->ARStep[3]=0; + ptChip->ARStep[0x3f]=0x400<DRStep[0]=ptChip->DRStep[1]=ptChip->DRStep[2]=ptChip->DRStep[3]=0; - return mpcm; + //TL Interpolation steps + //lower + TLSteps[0]=-(float) (0x80<exponential ramps + for(i=0;i<0x400;++i) + { + float db=-(96.0-(96.0*(float) i/(float) 0x400)); + lin2expvol[i]=pow(10.0,db/20.0)*(float) (1<ROM+i*12; + ptChip->Samples[i].Start=(ptSample[0]<<16)|(ptSample[1]<<8)|(ptSample[2]<<0); + ptChip->Samples[i].Loop=(ptSample[3]<<8)|(ptSample[4]<<0); + ptChip->Samples[i].End=0xffff-((ptSample[5]<<8)|(ptSample[6]<<0)); + ptChip->Samples[i].LFOVIB=ptSample[7]; + ptChip->Samples[i].DR1=ptSample[8]&0xf; + ptChip->Samples[i].AR=(ptSample[8]>>4)&0xf; + ptChip->Samples[i].DR2=ptSample[9]&0xf; + ptChip->Samples[i].DL=(ptSample[9]>>4)&0xf; + ptChip->Samples[i].RR=ptSample[10]&0xf; + ptChip->Samples[i].KRS=(ptSample[10]>>4)&0xf; + ptChip->Samples[i].AM=ptSample[11]; + } + + sprintf(mname, "MultiPCM %d", sndindex); + state_save_register_item(mname, sndindex, ptChip->CurSlot); + state_save_register_item(mname, sndindex, ptChip->Address); + state_save_register_item(mname, sndindex, ptChip->BankL); + state_save_register_item(mname, sndindex, ptChip->BankR); + + for(i=0;i<28;++i) + { + char mname2[20]; + + ptChip->Slots[i].Num=i; + ptChip->Slots[i].Playing=0; + + sprintf(mname2, "MultiPCM %d v %d", sndindex, i); + + state_save_register_item(mname2, sndindex, ptChip->Slots[i].Num); + state_save_register_item_array(mname2, sndindex, ptChip->Slots[i].Regs); + state_save_register_item(mname2, sndindex, ptChip->Slots[i].Playing); + state_save_register_item(mname2, sndindex, ptChip->Slots[i].Base); + state_save_register_item(mname2, sndindex, ptChip->Slots[i].offset); + state_save_register_item(mname2, sndindex, ptChip->Slots[i].step); + state_save_register_item(mname2, sndindex, ptChip->Slots[i].Pan); + state_save_register_item(mname2, sndindex, ptChip->Slots[i].TL); + state_save_register_item(mname2, sndindex, ptChip->Slots[i].DstTL); + state_save_register_item(mname2, sndindex, ptChip->Slots[i].TLStep); + state_save_register_item(mname2, sndindex, ptChip->Slots[i].Prev); + state_save_register_item(mname2, sndindex, ptChip->Slots[i].EG.volume); + state_save_register_item(mname2, sndindex, ptChip->Slots[i].EG.state); + state_save_register_item(mname2, sndindex, ptChip->Slots[i].EG.step); + state_save_register_item(mname2, sndindex, ptChip->Slots[i].EG.AR); + state_save_register_item(mname2, sndindex, ptChip->Slots[i].EG.D1R); + state_save_register_item(mname2, sndindex, ptChip->Slots[i].EG.D2R); + state_save_register_item(mname2, sndindex, ptChip->Slots[i].EG.RR); + state_save_register_item(mname2, sndindex, ptChip->Slots[i].EG.DL); + state_save_register_item(mname2, sndindex, ptChip->Slots[i].PLFO.phase); + state_save_register_item(mname2, sndindex, ptChip->Slots[i].PLFO.phase_step); + state_save_register_item(mname2, sndindex, ptChip->Slots[i].ALFO.phase); + state_save_register_item(mname2, sndindex, ptChip->Slots[i].ALFO.phase_step); + } + + LFO_Init(); + + return ptChip; } -/* write register */ + static void MultiPCM_reg_w(int chip, int offset, UINT8 data) { - int ppp, inum; - signed short pitch; - long pt_abs, pt_oct, st; - int vnum; - MultiPCMT *cptr = sndti_token(SOUND_MULTIPCM, chip); - VoiceT *vptr; - - stream_update(cptr->stream); - - switch (offset) + struct _MultiPCM *ptChip = sndti_token(SOUND_MULTIPCM, chip); + switch(offset) { - case 0: // data / status - if ((cptr->curvoice > 27) || (cptr->curvoice < 0)) - { - //logerror("MPCM: unknown write to voice > 28\n"); - return; - } - - vnum = cptr->curvoice; - cptr->registers[vnum][cptr->curreg] = data; - - vptr = &cptr->Voices[vnum]; - - switch (cptr->curreg) - { - case 0: // panning - ppp = (cptr->registers[vnum][0]>>4)&0xf; - if (ppp >= 8) - { - ppp = -(16-ppp); - } - vptr->pan = ppp + 8; - break; - - case 1: // sample - break; - - case 2: // pitch LSB - // MUST fall through to update pitch also! - case 3: // pitch MSB - // compute frequency divisor - pitch = (cptr->registers[vnum][3]<<8) + cptr->registers[vnum][2]; - pt_abs = (double)abs(pitch); - pt_oct = pt_abs>>12; - if(pitch < 0) - { - vptr->ptdelta = cptr->dlttbl[0x1000 - (pt_abs&0xfff)]; - vptr->ptdelta >>= (pt_oct+1); - } - else - { - vptr->ptdelta = cptr->dlttbl[pt_abs&0xfff]; - vptr->ptdelta <<= pt_oct; - } - break; - - case 4: // key on/off - if (data & 0x80) - { - inum = cptr->registers[vnum][1]; - - // calc decay amount - vptr->relamt = decaytbl[(0x0f - cptr->samples[inum].env[2])]; - - // compute start and end pointers - st = cptr->samples[inum].st; - - // perform banking - if (st >= 0x100000) - { -/* logerror("MPCM: key on chip %d voice %d\n", chip, vnum); - logerror("regs %02x %02x %02x %02x %02x %02x %02x %02x\n", cptr->registers[vnum][0], - cptr->registers[vnum][1],cptr->registers[vnum][2],cptr->registers[vnum][3], - cptr->registers[vnum][4],cptr->registers[vnum][5], - cptr->registers[vnum][6],cptr->registers[vnum][7]);*/ - - if (vptr->pan < 8) - { - st = (st & 0xfffff) + cptr->bankL; - } - else - { - st = (st & 0xfffff) + cptr->bankR; - } - } - - vptr->pSamp = &cptr->romptr[st]; - vptr->end = cptr->samples[inum].size; - vptr->loopst = cptr->samples[inum].loop; - - vptr->ptoffset = 0; - vptr->ptsum = 0; - vptr->active = 1; - vptr->relstage = 0; - } - else - { -// logerror("MPCM: key off chip %d voice %d\n", chip, vnum); - vptr->active = 0; - vptr->relcount = 0; - if ((vptr->loop) && (vptr->pSamp)) - { - vptr->relstage = 1; - } - } - break; - - case 5: // volume/loop - vptr->vol = cptr->voltbl[(cptr->registers[vnum][5]>>1)&0x7f]; - vptr->loop = (cptr->registers[vnum][5]&0x1) || !vptr->loopst; - break; - - case 6: // ??? LFO? reverb? - case 7: -// logerror("write %x to reg %d, voice %d\n", data, cptr->curreg, vnum); - break; - - default: -// logerror("write %x to reg %d, voice %d\n", data, cptr->curreg, vnum); - break; - } + case 0: //Data write + WriteSlot(ptChip,ptChip->Slots+ptChip->CurSlot,ptChip->Address,data); + break; + case 1: + ptChip->CurSlot=val2chan[data&0x1f]; break; - case 1: // voice select - cptr->curvoice = ctbl[data&0x1f]; - break; - - case 2: // register select - cptr->curreg = data; - if (cptr->curreg > 7) - cptr->curreg = 7; + case 2: + ptChip->Address=(data>7)?7:data; break; } } -/* read register */ - -static UINT8 MultiPCM_reg_r(int chip, int offset) -{ - UINT8 retval = 0; - - switch (offset) - { - case 0: - retval = 0; // always return READY - break; - - default: - //logerror("read from unknown MPCM register %ld\n", offset); - break; - } - - return retval; -} - /* MAME/M1 access functions */ READ8_HANDLER( MultiPCM_reg_0_r ) @@ -517,9 +690,9 @@ WRITE8_HANDLER( MultiPCM_reg_1_w ) void multipcm_set_bank(int which, UINT32 leftoffs, UINT32 rightoffs) { - struct MultiPCM_t *mpcm = sndti_token(SOUND_MULTIPCM, which); - mpcm->bankL = leftoffs; - mpcm->bankR = rightoffs; + struct _MultiPCM *ptChip = sndti_token(SOUND_MULTIPCM, which); + ptChip->BankL = leftoffs; + ptChip->BankR = rightoffs; } @@ -550,11 +723,12 @@ void multipcm_get_info(void *token, UINT32 state, sndinfo *info) case SNDINFO_PTR_RESET: /* Nothing */ break; /* --- the following bits of info are returned as NULL-terminated strings --- */ - case SNDINFO_STR_NAME: info->s = "MultiPCM"; break; + case SNDINFO_STR_NAME: info->s = "Sega/Yamaha 315-5560"; break; case SNDINFO_STR_CORE_FAMILY: info->s = "Sega custom"; break; - case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break; + case SNDINFO_STR_CORE_VERSION: info->s = "2.0"; break; case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break; case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright Nicola Salmoria and the MAME Team"; break; } } +