Supermodel/Src/Sound/SCSP.cpp

2353 lines
56 KiB
C++
Raw Normal View History

2011-04-24 01:14:00 +00:00
/**
** Supermodel
** A Sega Model 3 Arcade Emulator.
** Copyright 2011 Bart Trzynadlowski, Nik Henson
2011-04-24 01:14:00 +00:00
**
** This file is part of Supermodel.
**
** Supermodel 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 3 of the License, or (at your option)
** any later version.
**
** Supermodel 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 Supermodel. If not, see <http://www.gnu.org/licenses/>.
**/
/*
* SCSP.cpp
*
* WARNING: Here be dragons! Tread carefully. Enabling/disabling things may
* break save state support.
*
2011-04-24 01:14:00 +00:00
* SCSP (Sega Custom Sound Processor) emulation. This code was generously
* donated by ElSemi. Interfaces directly to the 68K processor through
* callbacks. Some minor interface changes were made (external global variables
* were removed).
*
2011-07-13 05:29:02 +00:00
* The MIDI input buffer has been increased from 8 (which I assume is the
* actual size) in order to accommodate Model 3's PowerPC/68K communication.
* There is probably tight synchronization between the CPUs, with PowerPC-side
* interrupts being generated to fill the MIDI buffer as the 68K pulls data
* out, or there may be a UART with a large FIFO buffer. This can be simulated
* by increasing the MIDI buffer (MIDI_STACK_SIZE).
*
2011-04-24 01:14:00 +00:00
* To-Do List
* ----------
* - Wrap up into an object. Remove any unused #ifdef pathways.
*/
/*
SEGA Custom Sound Processor (SCSP) Emulation
by ElSemi.
Driven by MC68000
*/
#include "Supermodel.h"
#include "Sound/SCSP.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
2011-04-24 01:14:00 +00:00
#include "Sound/SCSPDSP.h"
static const Util::Config::Node *s_config = 0;
static bool s_multiThreaded = false;
2011-04-24 01:14:00 +00:00
//#define NEWSCSP
//#define RB_VOLUME
//#define REVERB
#define USEDSP
#define MAX_SCSP 2
/*#define TIMER_LIMITSA 0x101
#define TIMER_LIMITSB 0x100
#define TIMER_LIMITSC 0xff
*/
#define TIMER_LIMITSA 0xff
#define TIMER_LIMITSB 0xff
#define TIMER_LIMITSC 0xff
// These globals control the operation of the SCSP, they are no longer extern and are set through SCSP_SetBuffers(). --Bart
float SysFPS;
//extern "C" A68KContext M68000_regs;
//extern void __cdecl ErrorLogMessage(char *,...);
signed short *bufferl;
signed short *bufferr;
int length;
int cnts;
signed int *buffertmpl,*buffertmpr; // these are allocated inside this file
unsigned int srate=44100;
#define REVERB_LEN 0x10000
#define REVERB_DIF 6000
#define REVERB_DIV 4
signed short bufferrevr[REVERB_LEN];
signed short bufferrevl[REVERB_LEN];
unsigned int RevR,RevW;
//#define _DEBUG
#ifndef _DEBUG
#define ErrorLogMessage
#endif
#ifndef BYTE
#define BYTE UINT8
#endif
#ifndef WORD
#define WORD UINT16
#endif
#ifndef DWORD
#define DWORD UINT32
#endif
static CMutex *MIDILock; // for safe access to the MIDI FIFOs
2011-04-24 01:14:00 +00:00
static int (*Run68kCB)(int cycles);
static void (*Int68kCB)(int irq);
static void (*RetIntCB)();
static DWORD IrqTimA=1;
static DWORD IrqTimBC=2;
static DWORD IrqMidi=3;
2011-07-13 05:29:02 +00:00
#define MIDI_STACK_SIZE 128
#define MIDI_STACK_SIZE_MASK (MIDI_STACK_SIZE-1)
2011-04-24 01:14:00 +00:00
static BYTE MidiOutStack[8];
static BYTE MidiOutW=0,MidiOutR=0;
2011-07-13 05:29:02 +00:00
static BYTE MidiStack[MIDI_STACK_SIZE];
2011-04-24 01:14:00 +00:00
static BYTE MidiOutFill;
static BYTE MidiInFill;
static BYTE MidiW=0,MidiR=0;
static BYTE HasSlaveSCSP=0;
static DWORD FNS_Table[0x400];
/*static int TLTABLE[256];
static int LPANTABLE[16];
static int RPANTABLE[16];
*/
#ifdef RB_VOLUME
static int volume[256*4]; // precalculated attenuation values with some marging for enveloppe and pan levels
static int pan_left[32], pan_right[32]; // pan volume offsets
#else
static float SDLT[8]={-1000000.0,-36.0,-30.0,-24.0,-18.0,-12.0,-6.0,0.0};
static int LPANTABLE[0x10000];
static int RPANTABLE[0x10000];
#endif
static int TimPris[3];
static int TimCnt[3];
#define SHIFT 12
#define FIX(v) ((DWORD) ((float) (1<<SHIFT)*(v)))
#define EG_SHIFT 8
#include "SCSPLFO.cpp"
2011-04-24 01:14:00 +00:00
/*
SCSP features 32 programmable slots
that can generate FM and PCM (from ROM/RAM) sound
*/
//SLOT PARAMETERS
#define KEYONEX(slot) ((slot->data[0x0]>>0x0)&0x1000)
#define KEYONB(slot) ((slot->data[0x0]>>0x0)&0x0800)
#define SBCTL(slot) ((slot->data[0x0]>>0x9)&0x0003)
#define SSCTL(slot) ((slot->data[0x0]>>0x7)&0x0003)
#define LPCTL(slot) ((slot->data[0x0]>>0x5)&0x0003)
#define PCM8B(slot) ((slot->data[0x0]>>0x0)&0x0010)
#define SA(slot) (((slot->data[0x0]&0xF)<<16)|(slot->data[0x1]))
#define LSA(slot) (slot->data[0x2])
#define LEA(slot) (slot->data[0x3])
#define D2R(slot) ((slot->data[0x4]>>0xB)&0x001F)
#define D1R(slot) ((slot->data[0x4]>>0x6)&0x001F)
#define EGHOLD(slot) ((slot->data[0x4]>>0x0)&0x0020)
#define AR(slot) ((slot->data[0x4]>>0x0)&0x001F)
#define LPSLNK(slot) ((slot->data[0x5]>>0x0)&0x4000)
#define KRS(slot) ((slot->data[0x5]>>0xA)&0x000F)
#define DL(slot) ((slot->data[0x5]>>0x5)&0x001F)
#define RR(slot) ((slot->data[0x5]>>0x0)&0x001F)
#define STWINH(slot) ((slot->data[0x6]>>0x0)&0x0200)
#define SDIR(slot) ((slot->data[0x6]>>0x0)&0x0100)
#define TL(slot) ((slot->data[0x6]>>0x0)&0x00FF)
#define MDL(slot) ((slot->data[0x7]>>0xB)&0x0007)
#define MDXSL(slot) ((slot->data[0x7]>>0x6)&0x003F)
#define MDYSL(slot) ((slot->data[0x7]>>0x0)&0x003F)
#define OCT(slot) ((slot->data[0x8]>>0xB)&0x000F)
#define FNS(slot) ((slot->data[0x8]>>0x0)&0x03FF)
#define LFORE(slot) ((slot->data[0x9]>>0x0)&0x8000)
#define LFOF(slot) ((slot->data[0x9]>>0xA)&0x001F)
#define PLFOWS(slot) ((slot->data[0x9]>>0x8)&0x0003)
#define PLFOS(slot) ((slot->data[0x9]>>0x5)&0x0007)
#define ALFOWS(slot) ((slot->data[0x9]>>0x3)&0x0003)
#define ALFOS(slot) ((slot->data[0x9]>>0x0)&0x0007)
#define ISEL(slot) ((slot->data[0xA]>>0x3)&0x000F)
#define IMXL(slot) ((slot->data[0xA]>>0x0)&0x0007)
#define DISDL(slot) ((slot->data[0xB]>>0xD)&0x0007)
#define DIPAN(slot) ((slot->data[0xB]>>0x8)&0x001F)
#define EFSDL(slot) ((slot->data[0xB]>>0x5)&0x0007)
#define EFPAN(slot) ((slot->data[0xB]>>0x0)&0x001F)
//Envelope step (fixed point)
int ARTABLE[64],DRTABLE[64];
//Envelope times in ms
double ARTimes[64]={100000/*infinity*/,100000/*infinity*/,8100.0,6900.0,6000.0,4800.0,4000.0,3400.0,3000.0,2400.0,2000.0,1700.0,1500.0,
1200.0,1000.0,860.0,760.0,600.0,500.0,430.0,380.0,300.0,250.0,220.0,190.0,150.0,130.0,110.0,95.0,
76.0,63.0,55.0,47.0,38.0,31.0,27.0,24.0,19.0,15.0,13.0,12.0,9.4,7.9,6.8,6.0,4.7,3.8,3.4,3.0,2.4,
2.0,1.8,1.6,1.3,1.1,0.93,0.85,0.65,0.53,0.44,0.40,0.35,0.0,0.0};
double DRTimes[64]={100000/*infinity*/,100000/*infinity*/,118200.0,101300.0,88600.0,70900.0,59100.0,50700.0,44300.0,35500.0,29600.0,25300.0,22200.0,17700.0,
14800.0,12700.0,11100.0,8900.0,7400.0,6300.0,5500.0,4400.0,3700.0,3200.0,2800.0,2200.0,1800.0,1600.0,1400.0,1100.0,
920.0,790.0,690.0,550.0,460.0,390.0,340.0,270.0,230.0,200.0,170.0,140.0,110.0,98.0,85.0,68.0,57.0,49.0,43.0,34.0,
28.0,25.0,22.0,18.0,14.0,12.0,11.0,8.5,7.1,6.1,5.4,4.3,3.6,3.1};
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
BYTE EGHOLD;
BYTE LPLINK;
};
struct _SLOT
{
union
{
WORD data[0x10]; //only 0x1a bytes used
BYTE datab[0x20];
};
BYTE active; //this slot is currently playing
BYTE *base; //samples base address
DWORD cur_addr; //current play address (24.8)
DWORD step; //pitch step (24.8)
BYTE Back;
_EG EG; //Envelope
_LFO PLFO; //Phase LFO
_LFO ALFO; //Amplitude LFO
int slot;
signed short Prev; //Previous sample (for interpolation)
};
#define MEM4B(scsp) ((scsp->data[0]>>0x0)&0x0200)
#define DAC18B(scsp) ((scsp->data[0]>>0x0)&0x0100)
#define MVOL(scsp) ((scsp->data[0]>>0x0)&0x000F)
#define RBL(scsp) ((scsp->data[1]>>0x7)&0x0003)
#define RBP(scsp) ((scsp->data[1]>>0x0)&0x007F)
#define MOFULL(scsp) ((scsp->data[2]>>0x0)&0x1000)
#define MOEMPTY(scsp) ((scsp->data[2]>>0x0)&0x0800)
#define MIOVF(scsp) ((scsp->data[2]>>0x0)&0x0400)
#define MIFULL(scsp) ((scsp->data[2]>>0x0)&0x0200)
#define MIEMPTY(scsp) ((scsp->data[2]>>0x0)&0x0100)
#define SCILV0(scsp) ((scsp->data[0x24/2]>>0x0)&0xff)
#define SCILV1(scsp) ((scsp->data[0x26/2]>>0x0)&0xff)
#define SCILV2(scsp) ((scsp->data[0x28/2]>>0x0)&0xff)
#define SCIEX0 0
#define SCIEX1 1
#define SCIEX2 2
#define SCIMID 3
#define SCIDMA 4
#define SCIIRQ 5
#define SCITMA 6
#define SCITMB 7
struct _SCSP
{
union
{
WORD data[0x30/2];
BYTE datab[0x30];
};
_SLOT Slots[32];
signed short RINGBUF[64];
unsigned char BUFPTR;
unsigned char *SCSPRAM;
char Master;
#ifdef USEDSP
_SCSPDSP DSP;
signed short *MIXBuf;
#endif
} SCSPs[MAX_SCSP],*SCSP=SCSPs;
signed short *RBUFDST; //this points to where the sample will be stored in the RingBuf
unsigned char DecodeSCI(unsigned char irq)
{
unsigned char SCI=0;
unsigned char v;
v=(SCILV0((SCSP))&(1<<irq))?1:0;
SCI|=v;
v=(SCILV1((SCSP))&(1<<irq))?1:0;
SCI|=v<<1;
v=(SCILV2((SCSP))&(1<<irq))?1:0;
SCI|=v<<2;
return SCI;
}
void CheckPendingIRQ()
{
DWORD pend=SCSP[0].data[0x20/2];
DWORD en=SCSP[0].data[0x1e/2];
/*if(pend&0x8)
if(en&0x8)
{
Int68kCB(IrqMidi);
return;
}
*/
/*
* MIDI FIFO critical section
*
* NOTE: I don't think a mutex is really needed here, so I've disabled
* this critical section.
*/
//if (g_Config.multiThreaded)
// MIDILock->Lock();
2011-04-24 01:14:00 +00:00
if(MidiW!=MidiR)
{
//if (g_Config.multiThreaded)
// MIDILock->Unlock();
2011-04-24 01:14:00 +00:00
//SCSP.data[0x20/2]|=0x8; //Hold midi line while there are commands pending
Int68kCB(IrqMidi);
2011-07-13 05:29:02 +00:00
//printf("68K: MIDI IRQ\n");
2011-04-24 01:14:00 +00:00
//ErrorLogMessage("Midi");
return;
}
//if (g_Config.multiThreaded)
// MIDILock->Unlock();
2011-04-24 01:14:00 +00:00
if(!pend)
return;
if(pend&0x40)
if(en&0x40)
{
Int68kCB(IrqTimA);
//ErrorLogMessage("TimA");
return;
}
if(pend&0x80)
if(en&0x80)
{
Int68kCB(IrqTimBC);
//ErrorLogMessage("TimB");
return;
}
if(pend&0x100)
if(en&0x100)
{
Int68kCB(IrqTimBC);
//ErrorLogMessage("TimC");
return;
}
Int68kCB(0);
}
int Get_AR(int base,int R)
{
int Rate=base+(R<<1);
// int Rate=(base+R)<<1;
if(Rate>63) Rate=63;
if(Rate<0) Rate=0;
return ARTABLE[Rate];
}
int Get_DR(int base,int R)
{
int Rate=base+(R<<1);
// int Rate=(base+R)<<1;
if(Rate>63) Rate=63;
if(Rate<0) Rate=0;
return DRTABLE[Rate];
}
int Get_RR(int base,int R)
{
int Rate=base+(R<<1);
// int Rate=(base+R)<<1;
if(Rate>63) Rate=63;
if(Rate<0) Rate=0;
return DRTABLE[Rate];
}
void Compute_EG(_SLOT *slot)
{
int octave=OCT(slot);
int rate;
if(octave&8) octave=octave-16;
if(KRS(slot)!=0xf)
rate=2*(octave+KRS(slot))+((FNS(slot)>>9)&1);
else
rate=((FNS(slot)>>9)&1);
slot->EG.volume=0;
slot->EG.AR=Get_AR(rate,AR(slot));
slot->EG.D1R=Get_DR(rate,D1R(slot));
slot->EG.D2R=Get_DR(rate,D2R(slot));
slot->EG.RR=Get_RR(rate,RR(slot));
slot->EG.DL=0x1f-DL(slot);
slot->EG.EGHOLD=EGHOLD(slot);
}
void SCSP_StopSlot(_SLOT *slot,int keyoff);
int EG_Update(_SLOT *slot)
{
switch(slot->EG.state)
{
case ATTACK:
slot->EG.volume+=slot->EG.AR;
if(slot->EG.volume>=(0x3ff<<EG_SHIFT))
{
slot->EG.state=DECAY1;
if(slot->EG.D1R>=(1024<<EG_SHIFT)) //Skip DECAY1, go directly to DECAY2
slot->EG.state=DECAY2;
slot->EG.volume=0x3ff<<EG_SHIFT;
}
if(slot->EG.EGHOLD)
return 0x3ff<<(SHIFT-10);
break;
case DECAY1:
slot->EG.volume-=slot->EG.D1R;
if((slot->EG.volume>>(EG_SHIFT+5))<=slot->EG.DL)
slot->EG.state=DECAY2;
break;
case DECAY2:
if(slot->EG.volume<=0 || slot->EG.DL==0)
{
slot->EG.volume=0;
SCSP_StopSlot(slot,0);
}
if(D2R(slot)==0)
return (slot->EG.volume>>EG_SHIFT)<<(SHIFT-10);
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)
{
SCSP_StopSlot(slot,0);
slot->EG.volume=0;
slot->EG.state=ATTACK;
}
//slot->EG.volume=0;
break;
default:
return 1<<SHIFT;
}
return (slot->EG.volume>>EG_SHIFT)<<(SHIFT-10);
}
DWORD SCSP_Step(_SLOT *slot)
{
int octave=OCT(slot);
int Fn;
/*
int Fo=44100;
if(octave&8)
Fo>>=(16-octave);
else
Fo<<=octave;
Fn=Fo*(((FNS(slot))<<(SHIFT-10))|(1<<SHIFT));
*/
Fn=(FNS_Table[FNS(slot)]); //24.8
if(octave&8)
Fn>>=(16-octave);
else
Fn<<=octave;
return Fn/srate;
}
void Compute_LFO(_SLOT *slot)
{
if(PLFOS(slot)!=0)
LFO_ComputeStep(&(slot->PLFO),LFOF(slot),PLFOWS(slot),PLFOS(slot),0);
if(ALFOS(slot)!=0)
LFO_ComputeStep(&(slot->ALFO),LFOF(slot),ALFOWS(slot),ALFOS(slot),1);
}
void SCSP_StartSlot(_SLOT *slot)
{
slot->active=1;
slot->Back=0;
slot->base=SCSP->SCSPRAM+SA(slot);
slot->cur_addr=0;
slot->step=SCSP_Step(slot);
Compute_EG(slot);
slot->EG.state=ATTACK;
slot->EG.volume=0;
slot->Prev=0;
Compute_LFO(slot);
/*{
char aux[12];
static n=0;
sprintf(aux,"smp%d.raw",n);
FILE *f=fopen(aux,"wb");
fwrite(slot->base,LEA(slot),1,f);
fclose(f);
++n;
}
*/
}
void SCSP_StopSlot(_SLOT *slot,int keyoff)
{
if(keyoff && slot->EG.state!=RELEASE)
{
slot->EG.state=RELEASE;
// return;
}
else
slot->active=0;
slot->data[0]&=~0x800;
//DebugLog("KEYOFF2 %d",slot->slot);
2011-04-24 01:14:00 +00:00
}
#define log2(n) (log((float) n)/log((float) 2))
bool SCSP_Init(const Util::Config::Node &config, int n)
2011-04-24 01:14:00 +00:00
{
s_config = &config;
s_multiThreaded = config["MultiThreaded"].ValueAs<bool>();
2011-04-24 01:14:00 +00:00
if(n==2)
{
SCSP=SCSPs+1;
memset(SCSP,0,sizeof(_SCSP));
2011-04-24 01:14:00 +00:00
SCSP->Master=0;
HasSlaveSCSP=1;
#ifdef USEDSP
SCSPDSP_Init(&SCSP->DSP);
#endif
}
SCSP=SCSPs+0;
memset(SCSP,0,sizeof(_SCSP));
2011-04-24 01:14:00 +00:00
#ifdef USEDSP
SCSPDSP_Init(&SCSP->DSP);
#endif
SCSP->Master=1;
RevR=0;
RevW=REVERB_DIF;
memset(bufferrevl,0,sizeof(bufferrevl));
memset(bufferrevr,0,sizeof(bufferrevr));
MidiR=MidiW=0;
MidiOutR=MidiOutW=0;
MidiOutFill=0;
MidiInFill=0;
for(int i=0;i<0x400;++i)
{
float fcent=(double) 1200.0*log2((double)(((double) 1024.0+(double)i)/(double)1024.0));
//float fcent=1.0+(float) i/1024.0;
fcent=(double) 44100.0*pow(2.0,fcent/1200.0);
FNS_Table[i]=(float) (1<<SHIFT) *fcent;
//FNS_Table[i]=(i>>(10-SHIFT))|(1<<SHIFT);
}
#ifdef RB_VOLUME
// Volume table, 1 = -0.375dB, 8 = -3dB, 256 = -96dB
for(i = 0; i < 256; i++)
volume[i] = 65536.0*pow(2.0, (-0.375/6.0)*i);
for(i = 256; i < 256*4; i++)
volume[i] = 0;
// Pan values, units are a linear -3dB ramp, i.e. 8 places in the volume[] table.
for(i = 0; i < 16; i++)
{
pan_left[i] = i*8;
pan_left[i+16] = 0;
pan_right[i] = 0;
pan_right[i+16] = i*8;
}
// patch in the infinity values
pan_left[15] = 256;
pan_right[31] = 256;
#else
for(int i=0;i<0x10000;++i)
{
int iTL =(i>>0x8)&0xff;
int iPAN=(i>>0x0)&0x1f;
int iSDL=(i>>0x5)&0x07;
float TL=1.0;
float SegaDB=0;
//2^(-(TL-2^4))
/*if(iTL&0x01) TL*=0.95760;
if(iTL&0x02) TL*=0.91700;
if(iTL&0x04) TL*=0.84090;
if(iTL&0x08) TL*=0.70711;
if(iTL&0x10) TL*=0.50000;
if(iTL&0x20) TL*=0.25000;
if(iTL&0x40) TL*=0.06250;
if(iTL&0x80) TL*=0.00391;*/
if(iTL&0x01) SegaDB-=0.4;
if(iTL&0x02) SegaDB-=0.8;
if(iTL&0x04) SegaDB-=1.5;
if(iTL&0x08) SegaDB-=3;
if(iTL&0x10) SegaDB-=6;
if(iTL&0x20) SegaDB-=12;
if(iTL&0x40) SegaDB-=24;
if(iTL&0x80) SegaDB-=48;
TL=pow(10.0,SegaDB/20.0);
float PAN=1.0;
//2^(-2^(PAN-2))
/*if(iPAN&0x1) PAN*=0.70711;
if(iPAN&0x2) PAN*=0.50000;
if(iPAN&0x4) PAN*=0.25000;
if(iPAN&0x8) PAN*=0.06250;
if(iPAN==0xf) PAN=0.0;*/
SegaDB=0;
if(iPAN&0x1) SegaDB-=3;
if(iPAN&0x2) SegaDB-=6;
if(iPAN&0x4) SegaDB-=12;
if(iPAN&0x8) SegaDB-=24;
if(iPAN==0xf) PAN=0.0;
else if(iPAN==0x1f) PAN=0.0;
else PAN=pow(10.0,SegaDB/20.0);
float LPAN,RPAN;
if(iPAN<0x10)
{
LPAN=PAN;
RPAN=1.0;
}
else
{
RPAN=PAN;
LPAN=1.0;
}
float SDL=1.0;
if(iSDL)
SDL=pow(10.0,(SDLT[iSDL])/20.0);
else
SDL=0.0;
if(iSDL==0x6)
int a=1;
if(iTL==0x3a)
int a=1;
LPANTABLE[i]=FIX((4.0*LPAN*TL*SDL));
RPANTABLE[i]=FIX((4.0*RPAN*TL*SDL));
}
#endif
/*for(i=0;i<4;++i)
ARTABLE[i]=DRTABLE[i]=0;
for(i=4;i<62;++i)*/
/*for(i=2;i<62;++i)
{
//double t=BaseTimes[i]; //In ms
double t=BaseTimes2[i/2]/AR2DR; //In ms
double step=(1023*1000.0)/((float) srate*t);
double scale=(double) (1<<EG_SHIFT);
ARTABLE[i]=(int) (step*scale);
step/=AR2DR;
DRTABLE[i]=(int) (step*scale);
}
*/
ARTABLE[0]=DRTABLE[0]=0; //Infinite time
ARTABLE[1]=DRTABLE[1]=0;
for(int i=2;i<64;++i)
{
double t,step,scale;
t=ARTimes[i]; //In ms
if(t!=0.0)
{
step=(1023*1000.0)/((float) srate*t);
scale=(double) (1<<EG_SHIFT);
ARTABLE[i]=(int) (step*scale);
}
else
ARTABLE[i]=1024<<EG_SHIFT;
t=DRTimes[i]; //In ms
step=(1023*1000.0)/((float) srate*t);
scale=(double) (1<<EG_SHIFT);
DRTABLE[i]=(int) (step*scale);
}
for(int i=0;i<32;++i)
SCSPs[0].Slots[i].slot=i;
#ifdef USEDSP
//allocate 0x300 (over 1 frame) * 32 slots * 16 bit
SCSP->MIXBuf=(signed short *) malloc(0x300*32*sizeof(signed short));
#endif
LFO_Init();
buffertmpl = NULL;
buffertmpr = NULL;
2011-04-24 01:14:00 +00:00
buffertmpl=(signed int*) malloc(44100*sizeof(signed int));
if (NULL == buffertmpl)
return ErrorLog("Insufficient memory for internal SCSP buffers.");
2011-04-24 01:14:00 +00:00
buffertmpr=(signed int*) malloc(44100*sizeof(signed int));
if (NULL == buffertmpl)
{
free(buffertmpl);
return ErrorLog("Insufficient memory for internal SCSP buffers.");
}
2011-04-24 01:14:00 +00:00
memset(buffertmpl,0,44100*sizeof(signed int));
memset(buffertmpr,0,44100*sizeof(signed int));
// MIDI FIFO mutex
MIDILock = CThread::CreateMutex();
if (NULL == MIDILock)
{
free(buffertmpl);
free(buffertmpr);
return ErrorLog("Unable to create MIDI mutex!");
}
return OKAY;
2011-04-24 01:14:00 +00:00
}
void SCSP_SetRAM(int n,unsigned char *r)
{
SCSPs[n].SCSPRAM=r;
#ifdef USEDSP
SCSPs[n].DSP.SCSPRAM=(unsigned short*) r;
#endif
}
void SCSP_UpdateSlotReg(int s,int r)
{
_SLOT *slot=SCSP->Slots+s;
switch(r&0x3f)
{
case 0:
case 1:
if(KEYONEX(slot))
{
for(int sl=0;sl<32;++sl)
{
_SLOT *s2=SCSP->Slots+sl;
if(!KEYONB(s2) && sl==cnts && s2->active)
int a=1;
//if(s2->EG.state!=RELEASE)
{
if(KEYONB(s2) && (!s2->active || (s2->active && s2->EG.state==RELEASE)))
{
//DebugLog("KEYON %d",sl);
//printf("68K: KEYON %d\n",sl);
2011-04-24 01:14:00 +00:00
SCSP_StartSlot(s2);
}
if(!KEYONB(s2) && s2->active)
{
//s2->active=0;
SCSP_StopSlot(s2,1);
//DebugLog("KEYOFF %d",sl);
2011-04-24 01:14:00 +00:00
}
}
}
slot->data[0]&=~0x1000;
}
break;
case 0x10:
case 0x11:
slot->step=SCSP_Step(slot);
break;
case 0xA:
case 0xB:
if(slot->active)
int a=1;
// if(RR(slot)==0x1f)
// SCSP_StopSlot(slot,0);
slot->EG.RR=Get_RR(0,RR(slot));
slot->EG.DL=0x1f-DL(slot);
break;
case 0x12:
case 0x13:
Compute_LFO(slot);
break;
}
}
void SCSP_UpdateReg(int reg)
{
switch(reg&0x3f)
{
case 0x2:
case 0x3:
{
#ifdef USEDSP
unsigned int v=RBL(SCSP);
SCSP->DSP.RBP=RBP(SCSP);
if(v==0)
SCSP->DSP.RBL=8*1024;
else if(v==1)
SCSP->DSP.RBL=16*1024;
else if(v==2)
SCSP->DSP.RBL=32*1024;
else if(v==3)
SCSP->DSP.RBL=64*1024;
#endif
}
break;
case 0x6:
case 0x7:
SCSP_MidiOutW(SCSP->data[0x6/2]&0xff);
break;
/* case 0x8:
case 0x9:
{
unsigned char slot=SCSP.data[0x8/2]>>11;
int a=1;
}
break;
*/
case 0x12:
case 0x13:
case 0x14:
case 0x15:
case 0x16:
case 0x17:
{
int a=1;
}
break;
case 0x18:
case 0x19:
if(SCSP->Master)
{
TimPris[0]=1<<((SCSP->data[0x18/2]>>8)&0x7);
TimCnt[0]=((SCSP->data[0x18/2]&0xff)<<8)|(TimCnt[0]&0xff);
}
break;
case 0x1a:
case 0x1b:
if(SCSP->Master)
{
TimPris[1]=1<<((SCSP->data[0x1A/2]>>8)&0x7);
TimCnt[1]=((SCSP->data[0x1A/2]&0xff)<<8)|(TimCnt[1]&0xff);
}
break;
case 0x1C:
case 0x1D:
if(SCSP->Master)
{
TimPris[2]=1<<((SCSP->data[0x1C/2]>>8)&0x7);
TimCnt[2]=((SCSP->data[0x1C/2]&0xff)<<8)|(TimCnt[2]&0xff);
}
break;
case 0x22: //SCIRE
case 0x23:
if(SCSP->Master)
{
SCSP->data[0x20/2]&=~SCSP->data[0x22/2];
CheckPendingIRQ();
}
break;
case 0x24:
case 0x25:
case 0x26:
case 0x27:
case 0x28:
case 0x29:
if(SCSP->Master)
{
IrqTimA=DecodeSCI(SCITMA);
IrqTimBC=DecodeSCI(SCITMB);
IrqMidi=DecodeSCI(SCIMID);
}
break;
}
}
void SCSP_UpdateSlotRegR(int slot,int reg)
{
}
void SCSP_UpdateRegR(int reg)
{
switch(reg&0x3f)
{
case 4:
case 5:
{
unsigned short v=SCSP->data[0x5/2];
v&=0xff00;
/*
* MIDI FIFO critical section!
*/
if (s_multiThreaded)
MIDILock->Lock();
2011-04-24 01:14:00 +00:00
v|=MidiStack[MidiR];
//printf("read MIDI\n");
2011-04-24 01:14:00 +00:00
if(MidiR!=MidiW)
{
++MidiR;
2011-07-13 05:29:02 +00:00
MidiR&=MIDI_STACK_SIZE_MASK;
2011-04-24 01:14:00 +00:00
//Int68kCB(IrqMidi);
}
MidiInFill--;
SCSP->data[0x5/2]=v;
if (s_multiThreaded)
MIDILock->Unlock();
2011-04-24 01:14:00 +00:00
}
break;
case 8:
case 9:
{
unsigned char slot=SCSP->data[0x8/2]>>11;
unsigned int CA=SCSP->Slots[slot&0x1f].cur_addr>>(SHIFT+12);
SCSP->data[0x8/2]&=~(0x780);
SCSP->data[0x8/2]|=CA<<7;
}
break;
}
}
void SCSP_w8(unsigned int addr,unsigned char val)
{
addr&=0xffff;
if(addr<0x400)
{
int slot=addr/0x20;
addr&=0x1f;
//DebugLog("Slot %02X Reg %02X write byte %04X\n",slot,addr^1,val);
//printf("\tSlot %02X Reg %02X write byte %04X\n",slot,addr^1,val);
*(unsigned char *) &(SCSP->Slots[slot].datab[addr^1]) = val;
2011-04-24 01:14:00 +00:00
SCSP_UpdateSlotReg(slot,(addr^1)&0x1f);
}
else if(addr<0x600)
{
*(unsigned char *) &(SCSP->datab[(addr&0xff)^1]) = val;
2011-04-24 01:14:00 +00:00
SCSP_UpdateReg((addr^1)&0xff);
}
else if(addr<0x700)
SCSP->RINGBUF[(addr-0x600)/2]=val;
else
{
#ifdef USEDSP
//DSP
if(addr<0x780) //COEF
((unsigned char *) SCSP->DSP.COEF)[(addr-0x700)^1]=val;
2011-04-24 01:14:00 +00:00
else if(addr<0x7C0)
((unsigned char *) SCSP->DSP.MADRS)[(addr-0x780)^1]=val;
2011-04-24 01:14:00 +00:00
else if(addr>=0x800 && addr<0xC00)
((unsigned char *) SCSP->DSP.MPRO)[(addr-0x800)^1]=val;
2011-04-24 01:14:00 +00:00
else
int a=1;
if(addr==0xBFE)
{
SCSPDSP_Start(&SCSP->DSP);
}
int a=1;
#endif
}
}
void SCSP_w16(unsigned int addr,unsigned short val)
{
addr&=0xffff;
if(addr<0x400)
{
int slot=addr/0x20;
addr&=0x1f;
//DebugLog("Slot %02X Reg %02X write word %04X\n",slot,addr,val);
//printf("\tSlot %02X Reg %02X write word %04X\n",slot,addr,val);
*(unsigned short *) &(SCSP->Slots[slot].datab[addr]) = val;
2011-04-24 01:14:00 +00:00
SCSP_UpdateSlotReg(slot,addr&0x1f);
}
else if(addr<0x600)
{
*(unsigned short *) &(SCSP->datab[addr&0xff]) = val;
2011-04-24 01:14:00 +00:00
SCSP_UpdateReg(addr&0xff);
}
else if(addr<0x700)
SCSP->RINGBUF[(addr-0x600)/2]=val;
else
{
#ifdef USEDSP
//DSP
if(addr<0x780) //COEF
*(unsigned short *) &(SCSP->DSP.COEF[(addr-0x700)/2])=val;
2011-04-24 01:14:00 +00:00
else if(addr<0x800)
*(unsigned short *) &(SCSP->DSP.MADRS[(addr-0x780)/2])=val;
2011-04-24 01:14:00 +00:00
else if(addr<0xC00)
*(unsigned short *) &(SCSP->DSP.MPRO[(addr-0x800)/2])=val;
2011-04-24 01:14:00 +00:00
else
int a=1;
if(addr==0xBFE)
SCSPDSP_Start(&SCSP->DSP);
int a=1;
#endif
}
}
void SCSP_w32(unsigned int addr,unsigned int val)
{
addr&=0xffff;
if(addr<0x400)
{
int slot=addr/0x20;
addr&=0x1f;
//DebugLog("Slot %02X Reg %02X write dword %08X\n",slot,addr,val);
//printf("\tSlot %02X Reg %02X write dword %08X\n",slot,addr,val);
rotl(val, 16);
*(unsigned int *) &(SCSP->Slots[slot].datab[addr]) = val;
2011-04-24 01:14:00 +00:00
SCSP_UpdateSlotReg(slot,addr&0x1f);
SCSP_UpdateSlotReg(slot,(addr&0x1f)+2);
}
else if(addr<0x600)
{
rotl(val, 16);
*(unsigned int *) &(SCSP->datab[addr&0xff]) = val;
2011-04-24 01:14:00 +00:00
SCSP_UpdateReg(addr&0xff);
SCSP_UpdateReg((addr&0xff)+2);
}
else if(addr<0x700)
int a=1;
else
{
#ifdef USEDSP
//DSP
rotl(val, 16);
2011-04-24 01:14:00 +00:00
if(addr<0x780) //COEF
*(unsigned int *) &(SCSP->DSP.COEF[(addr-0x700)/2])=val;
2011-04-24 01:14:00 +00:00
else if(addr<0x800)
*(unsigned int *) &(SCSP->DSP.MADRS[(addr-0x780)/2])=val;
2011-04-24 01:14:00 +00:00
else if(addr<0xC00)
*(unsigned int *) &(SCSP->DSP.MPRO[(addr-0x800)/2])=val;
2011-04-24 01:14:00 +00:00
else
int a=1;
if(addr==0xBFC)
SCSPDSP_Start(&SCSP->DSP);
int a=1;
#endif
}
}
unsigned char SCSP_r8(unsigned int addr)
{
unsigned char v=0;
addr&=0xffff;
if(addr<0x400)
{
int slot=addr/0x20;
addr&=0x1f;
SCSP_UpdateSlotRegR(slot,(addr^1)&0x1f);
v=*(unsigned char *) &(SCSP->Slots[slot].datab[addr^1]);
//DebugLog("Slot %02X Reg %02X Read byte %02X",slot,addr^1,v);
2011-04-24 01:14:00 +00:00
}
else if(addr<0x600)
{
SCSP_UpdateRegR(addr&0xff);
v= *(unsigned char *) &(SCSP->datab[(addr&0xff)^1]);
2011-04-24 01:14:00 +00:00
//ErrorLogMessage("SCSP Reg %02X Read byte %02X",addr&0xff,v);
}
else if(addr<0x700)
v=0;
return v;
}
unsigned short SCSP_r16(unsigned int addr)
{
unsigned short v=0;
addr&=0xffff;
if(addr<0x400)
{
int slot=addr/0x20;
addr&=0x1f;
SCSP_UpdateSlotRegR(slot,addr&0x1f);
v=*(unsigned short *) &(SCSP->Slots[slot].datab[addr]);
//DebugLog("Slot %02X Reg %02X Read word %04X",slot,addr,v);
2011-04-24 01:14:00 +00:00
}
else if(addr<0x600)
{
SCSP_UpdateRegR(addr&0xff);
v= *(unsigned short *) &(SCSP->datab[addr&0xff]);
2011-04-24 01:14:00 +00:00
//ErrorLogMessage("SCSP Reg %02X Read word %04X",addr&0xff,v);
}
else if(addr<0x700)
v=SCSP->RINGBUF[(addr-0x600)/2];
return v;
}
unsigned int SCSP_r32(unsigned int addr)
{
return 0xffffffff;
}
#define REVSIGN(v) ((~v)+1)
void SCSP_TimersAddTicks2(int ticks)
{
//Update timers
WORD cnt;
WORD step;
//Timer A
if(!TimPris[0])
{
//cnt=SCSPs[0].data[0x18/2]&0xff;
cnt=TimCnt[0];
if(cnt==0xffff)
goto noTA;
++cnt;
++TimCnt[0];
if(cnt>=TIMER_LIMITSA)
{
/*if((SCSPs[0].data[0x20/2]&SCSPs[0].data[0x1e/2])&0x40) //timer pending ack
int a=1;*/
SCSPs[0].data[0x20/2]|=0x40;
/*if(SCSP.data[0x1e/2]&0x40)
Int68kCB(IrqTimA);*/
cnt=0xff;
TimCnt[0]=0xffff;
}
step=1<<((SCSPs[0].data[0x18/2]>>8)&0x7);
TimPris[0]=step;
SCSPs[0].data[0x18/2]&=0xff00;
SCSPs[0].data[0x18/2]|=cnt;
}
// else
TimPris[0]--;
noTA:
;
//Timer B
if(!TimPris[1])
{
//cnt=SCSPs[0].data[0x1a/2]&0xff;
cnt=TimCnt[1];
if(cnt==0xffff)
goto noTB;
++cnt;
++TimCnt[1];
if(cnt>=TIMER_LIMITSB)
{
/*if((SCSP.data[0x20/2]&SCSP.data[0x1e/2])&0x80) //timer pending ack
int a=1;*/
SCSPs[0].data[0x20/2]|=0x80;
/*if(SCSP.data[0x1e/2]&0x80)
Int68kCB(IrqTimBC);*/
cnt=0xff;
TimCnt[1]=0xffff;
}
step=1<<((SCSP[0].data[0x1a/2]>>8)&0x7);
TimPris[1]=step;
SCSPs[0].data[0x1a/2]&=0xff00;
SCSPs[0].data[0x1a/2]|=cnt;
}
// else
TimPris[1]--;
noTB:
;
//Timer C
if(!TimPris[2])
{
//cnt=SCSPs[0].data[0x1c/2]&0xff;
cnt=TimCnt[2];
if(cnt==0xffff)
goto noTC;
++cnt;
++TimCnt[2];
if(cnt>=TIMER_LIMITSC)
{
/*if((SCSP.data[0x20/2]&SCSP.data[0x1e/2])&0x100) //timer pending ack
int a=1;*/
SCSP[0].data[0x20/2]|=0x100;
/*if(SCSP.data[0x1e/2]&0x100)
Int68kCB(IrqTimBC);*/
cnt=0xff;
TimCnt[2]=0xffff;
}
step=1<<((SCSPs[0].data[0x1c/2]>>8)&0x7);
TimPris[2]=step;
SCSPs[0].data[0x1c/2]&=0xff00;
SCSPs[0].data[0x1c/2]|=cnt;
}
// else
TimPris[2]--;
noTC:
;
}
void SCSP_TimersAddTicks(int ticks)
{
if(TimCnt[0]<=0xff00)
{
TimCnt[0]+=ticks << (8-((SCSPs[0].data[0x18/2]>>8)&0x7));
if (TimCnt[0] > 0xFE00)
{
TimCnt[0] = 0xFFFF;
SCSPs[0].data[0x20/2]|=0x40;
}
SCSPs[0].data[0x18/2]&=0xff00;
SCSPs[0].data[0x18/2]|=TimCnt[0]>>8;
}
if(TimCnt[1]<=0xff00)
{
TimCnt[1]+=ticks << (8-((SCSPs[0].data[0x1a/2]>>8)&0x7));
if (TimCnt[1] > 0xFE00)
{
TimCnt[1] = 0xFFFF;
SCSPs[0].data[0x20/2]|=0x80;
}
SCSPs[0].data[0x1a/2]&=0xff00;
SCSPs[0].data[0x1a/2]|=TimCnt[1]>>8;
}
if(TimCnt[2]<=0xff00)
{
TimCnt[2]+=ticks << (8-((SCSPs[0].data[0x1c/2]>>8)&0x7));
if (TimCnt[2] > 0xFE00)
{
TimCnt[2] = 0xFFFF;
SCSPs[0].data[0x20/2]|=0x100;
}
SCSPs[0].data[0x1c/2]&=0xff00;
SCSPs[0].data[0x1c/2]|=TimCnt[2]>>8;
}
}
#ifdef NEWSCSP
#ifdef USEDSP
const bool hasDSP=true;
#else
const bool hasDSP=false;
#endif
signed short *bufmix;
signed int *bufl1,*bufr1;
#define SCSPNAME(_8bit,lfo,alfo,loop) \
void SCSP_Update##_8bit##lfo##alfo##loop(_SLOT *slot,unsigned int Enc,unsigned int nsamples)
//TRUST ON THE COMPILER OPTIMIZATIONS
#define SCSPTMPL(_8bit,lfo,alfo,loop) \
SCSPNAME(_8bit,lfo,alfo,loop)\
{\
signed int sample;\
DWORD addr;\
for(unsigned int s=0;s<nsamples;++s)\
{\
int step=slot->step;\
if(!slot->active)\
return;\
if(lfo) \
{\
step=step*PLFO_Step(&(slot->PLFO));\
step>>=SHIFT; \
}\
if(_8bit)\
{\
unsigned int offs=(slot->cur_addr>>SHIFT);\
signed char *p=(signed char *) (slot->base);\
int s;\
signed int fpart=slot->cur_addr&((1<<SHIFT)-1);\
s=(int) p[offs^1]*((1<<SHIFT)-fpart)+(int) p[(offs+1)^1]*fpart;\
sample=(s>>SHIFT)<<8;\
}\
else\
{\
signed short *p=(signed short *) &(slot->base[(slot->cur_addr>>(SHIFT-1))&(~1)]);\
2011-04-24 01:14:00 +00:00
signed int fpart=slot->cur_addr&((1<<SHIFT)-1);\
sample=(p[0]);\
}\
if(loop==0)\
{\
slot->cur_addr+=step;\
addr=slot->cur_addr>>SHIFT;\
if(addr>LEA(slot))\
{\
SCSP_StopSlot(slot,0);\
}\
}\
if(loop==1)\
{\
slot->cur_addr+=step;\
addr=slot->cur_addr>>SHIFT;\
if(addr>LEA(slot))\
slot->cur_addr=(LSA(slot)+1)<<SHIFT;\
}\
if(loop==2)\
{\
if(slot->Back)\
slot->cur_addr+=REVSIGN(step);\
else\
slot->cur_addr+=step;\
addr=slot->cur_addr>>SHIFT;\
if(addr>=LEA(slot))\
{\
slot->cur_addr=LEA(slot)<<SHIFT;\
slot->Back=1;\
}\
if((addr<LSA(slot) || (addr&0x80000000)) && slot->Back)\
slot->cur_addr=LEA(slot)<<SHIFT;\
}\
if(loop==3)\
{\
if(slot->Back)\
slot->cur_addr+=REVSIGN(step);\
else\
slot->cur_addr+=step;\
addr=slot->cur_addr>>SHIFT;\
if(addr>=LEA(slot)) /*reached end, reverse till start*/ \
{\
slot->cur_addr=LEA(slot)<<SHIFT;\
slot->Back=1;\
}\
if((addr<=LSA(slot) || (addr&0x80000000)) && slot->Back) /*reached start or negative*/\
{\
slot->cur_addr=LSA(slot)<<SHIFT;\
slot->Back=0;\
}\
}\
if(alfo)\
{\
sample=sample*ALFO_Step(&(slot->ALFO));\
sample>>=SHIFT;\
}\
*RBUFDST=sample;\
\
sample=(sample*EG_Update(slot))>>SHIFT;\
if(hasDSP)\
*bufmix++=((sample*LPANTABLE[(Enc|0xE0)&0xFFE0])>>(SHIFT+3));\
\
*bufl1=*bufl1 + ((sample*LPANTABLE[Enc])>>SHIFT);\
*bufr1=*bufr1 + ((sample*RPANTABLE[Enc])>>SHIFT);\
++bufl1;\
++bufr1;\
}\
}
SCSPTMPL(0,0,0,0) SCSPTMPL(0,0,0,1) SCSPTMPL(0,0,0,2) SCSPTMPL(0,0,0,3)
SCSPTMPL(0,0,1,0) SCSPTMPL(0,0,1,1) SCSPTMPL(0,0,1,2) SCSPTMPL(0,0,1,3)
SCSPTMPL(0,1,0,0) SCSPTMPL(0,1,0,1) SCSPTMPL(0,1,0,2) SCSPTMPL(0,1,0,3)
SCSPTMPL(0,1,1,0) SCSPTMPL(0,1,1,1) SCSPTMPL(0,1,1,2) SCSPTMPL(0,1,1,3)
SCSPTMPL(1,0,0,0) SCSPTMPL(1,0,0,1) SCSPTMPL(1,0,0,2) SCSPTMPL(1,0,0,3)
SCSPTMPL(1,0,1,0) SCSPTMPL(1,0,1,1) SCSPTMPL(1,0,1,2) SCSPTMPL(1,0,1,3)
SCSPTMPL(1,1,0,0) SCSPTMPL(1,1,0,1) SCSPTMPL(1,1,0,2) SCSPTMPL(1,1,0,3)
SCSPTMPL(1,1,1,0) SCSPTMPL(1,1,1,1) SCSPTMPL(1,1,1,2) SCSPTMPL(1,1,1,3)
#undef SCSPTMPL
#define SCSPTMPL(_8bit,lfo,alfo,loop) \
SCSP_Update##_8bit##lfo##alfo##loop ,
typedef void (*_SCSPUpdateModes)(_SLOT *,unsigned int,unsigned int);
_SCSPUpdateModes SCSPUpdateModes[]=
{
SCSPTMPL(0,0,0,0) SCSPTMPL(0,0,0,1) SCSPTMPL(0,0,0,2) SCSPTMPL(0,0,0,3)
SCSPTMPL(0,0,1,0) SCSPTMPL(0,0,1,1) SCSPTMPL(0,0,1,2) SCSPTMPL(0,0,1,3)
SCSPTMPL(0,1,0,0) SCSPTMPL(0,1,0,1) SCSPTMPL(0,1,0,2) SCSPTMPL(0,1,0,3)
SCSPTMPL(0,1,1,0) SCSPTMPL(0,1,1,1) SCSPTMPL(0,1,1,2) SCSPTMPL(0,1,1,3)
SCSPTMPL(1,0,0,0) SCSPTMPL(1,0,0,1) SCSPTMPL(1,0,0,2) SCSPTMPL(1,0,0,3)
SCSPTMPL(1,0,1,0) SCSPTMPL(1,0,1,1) SCSPTMPL(1,0,1,2) SCSPTMPL(1,0,1,3)
SCSPTMPL(1,1,0,0) SCSPTMPL(1,1,0,1) SCSPTMPL(1,1,0,2) SCSPTMPL(1,1,0,3)
SCSPTMPL(1,1,1,0) SCSPTMPL(1,1,1,1) SCSPTMPL(1,1,1,2) SCSPTMPL(1,1,1,3)
};
#define SCANLINES 210
void SCSP_CpuRunScanline()
{
int slice=12000000/(44100);
static unsigned int smp=0;
smp+=(unsigned int) ((256.0*44100.0)/((float) SCANLINES*SysFPS));
int lastdiff=0;
for(;smp&0xffffff00;)
{
lastdiff=Run68kCB(slice+lastdiff);
/*while(slice>0)
{
lastdiff=Run68kCB(1);
slice+=lastdiff;
if(M68000_regs.pc==0x0602620)
int a=1;
}*/
SCSP_TimersAddTicks(1);
CheckPendingIRQ();
smp-=0x100;
}
}
void SCSP_DoMasterSamples(int nsamples)
{
static int lastdiff=0;
signed short *bufr,*bufl;
for(int sl=0;sl<32;++sl)
{
bufr1=buffertmpr;
bufl1=buffertmpl;
// if(sl!=0x3)
// continue;
if(SCSPs[0].Slots[sl].active)
{
_SLOT *slot=SCSPs[0].Slots+sl;
unsigned int disdl=DISDL(slot);
unsigned int efsdl=EFSDL(slot);
unsigned int tl=TL(slot);
unsigned short Enc=((TL(slot))<<0x8)|((DIPAN(slot))<<0x0)|((DISDL(slot))<<0x5);
//unsigned short Enc=(0x00)|((DIPAN(slot))<<0x8)|((0x7)<<0xd);
unsigned int mode=LPCTL(slot);
/* if(SSCTL(slot)!=0) //no FM or noise yet
int a=1;
int MDX=MDXSL(slot);
int MDY=MDYSL(slot);
int LEV=MDL(slot);
if(LEV!=0 || MDX!=0 || MDY!=0)
goto norender;
if(SBCTL(slot))
int a=1;
*/
RBUFDST=SCSPs[0].RINGBUF+SCSPs[0].BUFPTR;
if(sl==0x15)
int a=1;
if(PLFOS(slot))
mode|=8;
if(ALFOS(slot))
mode|=4;
if(PCM8B(slot))
mode|=0x10;
#ifdef USEDSP
bufmix=SCSPs[0].MIXBuf+0x300*slot->slot;
#endif
SCSPUpdateModes[mode](slot,Enc,nsamples);
//norender:
//;
}
++SCSPs[0].BUFPTR;
SCSPs[0].BUFPTR&=63;
}
if(HasSlaveSCSP)
{
for(int sl=0;sl<32;++sl)
{
bufr1=buffertmpr;
bufl1=buffertmpl;
if(SCSPs[1].Slots[sl].active)
{
_SLOT *slot=SCSPs[1].Slots+sl;
//unsigned short Enc=((TL(slot))<<0x0)|((DIPAN(slot))<<0x8)|((0x7)<<0xd);
unsigned short Enc=((TL(slot))<<0x8)|((DIPAN(slot))<<0x0)|((DISDL(slot))<<0x5);
unsigned int mode=LPCTL(slot);
if(PLFOS(slot))
mode|=8;
if(ALFOS(slot))
mode|=4;
if(PCM8B(slot))
mode|=0x10;
RBUFDST=SCSPs[1].RINGBUF+SCSPs[1].BUFPTR;
#ifdef USEDSP
bufmix=SCSPs[1].MIXBuf+0x300*slot->slot;
#endif
SCSPUpdateModes[mode](slot,Enc,nsamples);
}
++SCSPs[1].BUFPTR;
SCSPs[1].BUFPTR&=63;
}
}
bufr=bufferr;
bufl=bufferl;
bufr1=buffertmpr;
bufl1=buffertmpl;
for(int s=0;s<nsamples;++s)
{
#define ICLIP16(x) (x<-32768)?-32768:((x>32767)?32767:x)
signed int smpl=*bufl1;
signed int smpr=*bufr1;
#ifdef USEDSP
signed short *pt=SCSPs[0].MIXBuf+s;
for(int sl=0;sl<32;++sl)
{
_SLOT *slot=SCSPs[0].Slots+sl;
if(slot->active)
{
SCSPDSP_SetSample(&SCSP[0].DSP,pt[0],ISEL(slot),IMXL(slot));
}
pt+=0x300;
}
SCSPDSP_Step(&SCSP[0].DSP);
if(HasSlaveSCSP)
{
pt=SCSPs[1].MIXBuf+s;
for(int sl=0;sl<32;++sl)
{
_SLOT *slot=SCSPs[1].Slots+sl;
if(slot->active)
{
SCSPDSP_SetSample(&SCSP[1].DSP,pt[0],ISEL(slot),IMXL(slot));
}
pt+=0x300;
}
SCSPDSP_Step(&SCSP[1].DSP);
}
// smpl=0;
// smpr=0;
for(int i=0;i<16;++i)
{
_SLOT *slot=SCSPs[0].Slots+i;
int ef=EFSDL(slot);
if(ef)
{
unsigned short Enc=0|((EFPAN(slot))<<0x0)|((EFSDL(slot))<<0x5);
smpl+=(SCSPs[0].DSP.EFREG[i]*LPANTABLE[Enc])>>SHIFT;
smpr+=(SCSPs[0].DSP.EFREG[i]*RPANTABLE[Enc])>>SHIFT;
}
if(HasSlaveSCSP)
{
_SLOT *slot=SCSPs[1].Slots+i;
ef=EFSDL(slot);
if(ef)
{
unsigned short Enc=0|((EFPAN(slot))<<0x0)|((EFSDL(slot))<<0x5);
smpl+=(SCSPs[1].DSP.EFREG[i]*LPANTABLE[Enc])>>SHIFT;
smpr+=(SCSPs[1].DSP.EFREG[i]*RPANTABLE[Enc])>>SHIFT;
}
}
}
#endif
#ifdef REVERB
smpl+=bufferrevl[RevR];
smpr+=bufferrevr[RevR];
bufferrevl[RevW]=((smpl<<0)/REVERB_DIV)>>0;
bufferrevr[RevW]=((smpr<<0)/REVERB_DIV)>>0;
++RevW;
if(RevW==REVERB_LEN)
RevW=0;
++RevR;
if(RevR==REVERB_LEN)
RevR=0;
#endif
*bufl=ICLIP16(smpl);
*bufr=ICLIP16(smpr);
*bufl1=0;
*bufr1=0;
++bufl;
++bufr;
++bufl1;
++bufr1;
}
}
#else
signed int inline SCSP_UpdateSlot(_SLOT *slot)
{
signed int sample;
int step=slot->step;
DWORD addr;
if(SSCTL(slot)!=0) //no FM or noise yet
return 0;
if(PLFOS(slot)!=0)
{
step=step*PLFO_Step(&(slot->PLFO));
step>>=SHIFT;
}
if(PCM8B(slot))
addr=slot->cur_addr>>SHIFT;
else
addr=(slot->cur_addr>>(SHIFT-1))&(~1);
if(MDL(slot)!=0 || MDXSL(slot)!=0 || MDYSL(slot)!=0)
{
2011-09-05 20:07:14 +00:00
//TODO: is this correct? SCSP is not necessarily set to the slave SCSP. ElSemi may not have noticed this.
2011-04-24 01:14:00 +00:00
unsigned char v;
signed int smp=(SCSP->RINGBUF[(SCSP->BUFPTR+MDXSL(slot))&63]+SCSP->RINGBUF[(SCSP->BUFPTR+MDYSL(slot))&63])/2;
smp>>=11;
// Check for underflow before adding to addr
if (smp >= 0 || (DWORD)(-smp) < addr)
addr+=smp;
else
addr = 0;
2011-04-24 01:14:00 +00:00
if(!PCM8B(slot))
addr&=~1;
}
if(PCM8B(slot)) //8 bit signed
{
signed char *p=(signed char *) &(slot->base[addr^1]);
2011-04-24 01:14:00 +00:00
int s;
signed int fpart=slot->cur_addr&((1<<SHIFT)-1);
sample=(p[0])<<8;
2011-09-05 20:07:14 +00:00
//if (p>=(signed char *) &SCSP->SCSPRAM[0x200000])
// printf("%X %X %X %p %p %p\n", addr, SA(slot), LEA(slot), p, slot->base, SCSP->SCSPRAM);
2011-04-24 01:14:00 +00:00
/*s=(int) p[0]*((1<<SHIFT)-fpart)+(int) p[1]*fpart;
sample=(s>>SHIFT)<<8;
*/
/* if(SBCTL(slot)&1) //reverse data
sample^=0x7f;
if(SBCTL(slot)&2) //reverse sign
sample^=0x80;
*/
}
else //16 bit signed (endianness?)
{
signed short *p=(signed short *) &(slot->base[addr]);
2011-04-24 01:14:00 +00:00
int s;
signed int fpart=slot->cur_addr&((1<<SHIFT)-1);
sample=(p[0]);
//sample=((p[0]>>8)&0xFF)|(p[0]<<8);
//s=(int) p[0]*((1<<SHIFT)-fpart)+(int) p[1]*fpart;
//sample=s>>SHIFT;
/* if(SBCTL(slot)&1) //reverse data
sample^=0x7fff;
if(SBCTL(slot)&2) //reverse sign
sample^=0x8000;
*/
}
switch(LPCTL(slot))
{
case 0: //no loop
slot->cur_addr+=step;
addr=slot->cur_addr>>SHIFT;
if(addr>LEA(slot))
{
//slot->active=0;
SCSP_StopSlot(slot,0);
}
break;
case 1: //normal loop
slot->cur_addr+=step;
addr=slot->cur_addr>>SHIFT;
if(addr>LEA(slot))
slot->cur_addr=LSA(slot)<<SHIFT;
break;
case 2: //reverse loop
if(slot->Back)
slot->cur_addr+=REVSIGN(step);
else
slot->cur_addr+=step;
addr=slot->cur_addr>>SHIFT;
if(addr>LEA(slot))
{
slot->cur_addr=LEA(slot)<<SHIFT;
slot->Back=1;
}
if((addr<LSA(slot) || (addr&0x80000000)) && slot->Back)
slot->cur_addr=LEA(slot)<<SHIFT;
break;
case 3: //ping-pong
if(slot->Back)
slot->cur_addr+=REVSIGN(step);
else
slot->cur_addr+=step;
addr=slot->cur_addr>>SHIFT;
if(addr>LEA(slot)) //reached end, reverse till start
{
slot->cur_addr=LEA(slot)<<SHIFT;
//slot->step=REVSIGN(slot->step);
slot->Back=1;
}
if((addr<LSA(slot) || (addr&0x80000000)) && (slot->Back)) //reached start or negative
{
slot->cur_addr=LSA(slot)<<SHIFT;
//slot->step=REVSIGN(slot->step);
slot->Back=0;
}
break;
}
if(ALFOS(slot)!=0)
{
sample=sample*ALFO_Step(&(slot->ALFO));
sample>>=SHIFT;
}
if(!STWINH(slot))
*RBUFDST=sample;
else
int a=1;
sample=(sample*EG_Update(slot))>>SHIFT;
return sample;
}
void SCSP_CpuRunScanline()
{
}
void SCSP_DoMasterSamples(int nsamples)
{
int slice=12000000/(SysFPS*nsamples); // 68K cycles/sample
static int lastdiff=0;
/*
* Compute relative master/slave SCSP balance (note: master is often used
* for the front speakers). Equal balance is a 1.0 scale factor for both.
* When one SCSP is fully attenuated, the other's samples will be multiplied
* by 2.
*/
float balance = (float) s_config->Get("Balance").ValueAs<float>();
if (balance < -100.0f)
balance = -100.0f;
else if (balance > 100.0f)
balance = 100.0f;
balance /= 100.0f;
float masterBalance = 1.0f+balance;
float slaveBalance = 1.0f-balance;
/*
* Generate samples
*/
2011-04-24 01:14:00 +00:00
for(int s=0;s<nsamples;++s)
{
signed int smpl=0;
signed int smpr=0;
for(int sl=0;sl<32;++sl)
{
if(SCSPs[0].Slots[sl].active)
{
_SLOT *slot=SCSPs[0].Slots+sl;
unsigned short Enc=((TL(slot))<<0x8)|((DIPAN(slot))<<0x0)|((DISDL(slot))<<0x5);
RBUFDST=SCSPs[0].RINGBUF+SCSPs[0].BUFPTR;
signed int sample;
//signed int sample=(int) (masterBalance*(float)SCSP_UpdateSlot(slot));
2011-04-24 01:14:00 +00:00
//if(SA(slot)!=0x2ccf4)
/*if(SA(slot)!=0x1c77e)
sample=0;
else*/
sample= (int) (masterBalance*(float)SCSP_UpdateSlot(slot));
2011-04-24 01:14:00 +00:00
/*unsigned char ef=EFSDL(slot);
ef+=DISDL(slot);
if(ef>0xf) ef=0xf;
unsigned short Enc=((TL(slot))<<0x0)|((DIPAN(slot))<<0x8)|((ef)<<0xd);
*/
#ifdef USEDSP
SCSPDSP_SetSample(&SCSPs[0].DSP,/*sample>>5*/(sample*LPANTABLE[(Enc|0xE0)&0xFFE0])>>(SHIFT+3)/*>>SHIFT*/,ISEL(slot),IMXL(slot));
#endif
#ifdef RB_VOLUME
smpl += (sample * volume[TL(slot)+pan_left [DIPAN(slot)]])>>17;
smpr += (sample * volume[TL(slot)+pan_right[DIPAN(slot)]])>>17;
#else
//if(sl==cnts)
{
smpl+=(sample*LPANTABLE[Enc])>>SHIFT;
smpr+=(sample*RPANTABLE[Enc])>>SHIFT;
}
#endif
}
++SCSPs[0].BUFPTR;
SCSPs[0].BUFPTR&=63;
if(HasSlaveSCSP)
{
if(SCSPs[1].Slots[sl].active)
{
_SLOT *slot=SCSPs[1].Slots+sl;
unsigned short Enc=((TL(slot))<<0x8)|((DIPAN(slot))<<0x0)|((DISDL(slot))<<0x5);
RBUFDST=SCSPs[1].RINGBUF+SCSPs[1].BUFPTR;
signed int sample=(int) (slaveBalance*(float)SCSP_UpdateSlot(slot));
2011-04-24 01:14:00 +00:00
#ifdef USEDSP
SCSPDSP_SetSample(&SCSPs[1].DSP,(sample*LPANTABLE[(Enc|0xE0)&0xFFE0])>>(SHIFT+3),ISEL(slot),IMXL(slot));
#endif
#ifdef RB_VOLUME
smpl += (sample * volume[TL(slot)+pan_left [DIPAN(slot)]])>>17;
smpr += (sample * volume[TL(slot)+pan_right[DIPAN(slot)]])>>17;
#else
smpl+=(sample*LPANTABLE[Enc])>>SHIFT;
smpr+=(sample*RPANTABLE[Enc])>>SHIFT;
#endif
}
++SCSPs[1].BUFPTR;
SCSPs[1].BUFPTR&=63;
}
}
#define ICLIP16(x) (x<-32768)?-32768:((x>32767)?32767:x)
#ifdef USEDSP
SCSPDSP_Step(&SCSPs[0].DSP);
if(HasSlaveSCSP)
SCSPDSP_Step(&SCSPs[1].DSP);
// smpl=0;
// smpr=0;
for(int i=0;i<16;++i)
{
_SLOT *slot=SCSPs[0].Slots+i;
int ef=EFSDL(slot);
if(ef)
{
unsigned short Enc=0|((EFPAN(slot))<<0x0)|((EFSDL(slot))<<0x5);
signed int leftSample = (int) (masterBalance*(float)((SCSPs[0].DSP.EFREG[i]*LPANTABLE[Enc])>>SHIFT));
signed int rightSample = (int) (masterBalance*(float)((SCSPs[0].DSP.EFREG[i]*RPANTABLE[Enc])>>SHIFT));
smpl+=leftSample;
smpr+=rightSample;
2011-04-24 01:14:00 +00:00
}
if(HasSlaveSCSP)
{
_SLOT *slot=SCSPs[1].Slots+i;
ef=EFSDL(slot);
if(ef)
{
unsigned short Enc=0|((EFPAN(slot))<<0x0)|((EFSDL(slot))<<0x5);
signed int leftSample = (int) (slaveBalance*(float)((SCSPs[1].DSP.EFREG[i]*LPANTABLE[Enc])>>SHIFT));
signed int rightSample = (int) (slaveBalance*(float)((SCSPs[1].DSP.EFREG[i]*RPANTABLE[Enc])>>SHIFT));
smpl+=leftSample;
smpr+=rightSample;
2011-04-24 01:14:00 +00:00
}
}
}
#endif
#ifdef REVERB
smpl+=bufferrevl[RevR];
smpr+=bufferrevr[RevR];
bufferrevl[RevW]=((smpl<<0)/REVERB_DIV)>>0;
bufferrevr[RevW]=((smpr<<0)/REVERB_DIV)>>0;
++RevW;
if(RevW==REVERB_LEN)
RevW=0;
++RevR;
if(RevR==REVERB_LEN)
RevR=0;
#endif
if(smpl<-32768)
smpl=-32768;
else if(smpl>32767)
smpl=32767;
bufferl[s]=smpl;
//bufferl[s]=ICLIP16(smpl);
bufferr[s]=ICLIP16(smpr);
SCSP_TimersAddTicks(1);
CheckPendingIRQ();
/*for(int nc=slice;nc;nc--)
{
Run68kCB(1);
if(M68000_regs.pc==0x6035A6)
{
int a=1;
}
}
*/
lastdiff=Run68kCB(slice-lastdiff);
}
}
#endif
void SCSP_Update()
{
SCSP_DoMasterSamples(length);
}
void SCSP_SetCB(int (*Run68k)(int cycles),void (*Int68k)(int irq))
2011-04-24 01:14:00 +00:00
{
Int68kCB=Int68k;
Run68kCB=Run68k;
}
void SCSP_MidiIn(BYTE val)
{
/*
* MIDI FIFO critical section
*/
if (s_multiThreaded)
MIDILock->Lock();
//DebugLog("Midi Buffer push %02X",val);
2011-04-24 01:14:00 +00:00
MidiStack[MidiW++]=val;
2011-07-13 05:29:02 +00:00
MidiW&=MIDI_STACK_SIZE_MASK;
2011-04-24 01:14:00 +00:00
MidiInFill++;
//Int68kCB(IrqMidi);
// SCSP.data[0x20/2]|=0x8;
if (s_multiThreaded)
MIDILock->Unlock();
2011-04-24 01:14:00 +00:00
}
void SCSP_MidiOutW(BYTE val)
{
/*
* MIDI FIFO critical section
*/
if (s_multiThreaded)
MIDILock->Lock();
//printf("68K: MIDI out\n");
//DebugLog("Midi Out Buffer push %02X",val);
2011-04-24 01:14:00 +00:00
MidiStack[MidiOutW++]=val;
MidiOutW&=7;
++MidiOutFill;
if (s_multiThreaded)
MIDILock->Unlock();
2011-04-24 01:14:00 +00:00
}
unsigned char SCSP_MidiOutR()
{
unsigned char val;
if(MidiOutR==MidiOutW) // I don't think this needs to be a critical section...
2011-04-24 01:14:00 +00:00
return 0xff;
/*
* MIDI FIFO critical section
*/
if (s_multiThreaded)
MIDILock->Lock();
2011-04-24 01:14:00 +00:00
val=MidiStack[MidiOutR++];
//DebugLog("Midi Out Buffer pop %02X",val);
2011-04-24 01:14:00 +00:00
MidiOutR&=7;
--MidiOutFill;
if (s_multiThreaded)
MIDILock->Unlock();
2011-04-24 01:14:00 +00:00
return val;
}
unsigned char SCSP_MidiOutFill()
{
unsigned char v;
/*
* MIDI FIFO critical section
*/
if (s_multiThreaded)
MIDILock->Lock();
v = MidiOutFill;
if (s_multiThreaded)
MIDILock->Unlock();
return v;
2011-04-24 01:14:00 +00:00
}
unsigned char SCSP_MidiInFill()
{
unsigned char v;
/*
* MIDI FIFO critical section
*/
if (s_multiThreaded)
MIDILock->Lock();
v = MidiInFill;
if (s_multiThreaded)
MIDILock->Unlock();
return v;
2011-04-24 01:14:00 +00:00
}
void SCSP_RTECheck()
{
/* unsigned short pend=SCSP.data[0x20/2]&0xfff;
if(pend)
{
if(pend&0x40)
{
Int68kCB(IrqTimA);
return;
}
if(pend&(0x80|0x100))
{
Int68kCB(IrqTimBC);
return;
}
if(pend&0x8)
Int68kCB(IrqMidi);
}
*/
}
int SCSP_IRQCB(int)
{
CheckPendingIRQ();
return -1;
}
void SCSP_Master_w8(unsigned int addr,unsigned char val)
{
SCSP=SCSPs+0;
SCSP_w8(addr,val);
}
void SCSP_Master_w16(unsigned int addr,unsigned short val)
{
SCSP=SCSPs+0;
SCSP_w16(addr,val);
}
void SCSP_Master_w32(unsigned int addr,unsigned int val)
{
SCSP=SCSPs+0;
SCSP_w32(addr,val);
}
void SCSP_Slave_w8(unsigned int addr,unsigned char val)
{
SCSP=SCSPs+1;
SCSP_w8(addr,val);
}
void SCSP_Slave_w16(unsigned int addr,unsigned short val)
{
SCSP=SCSPs+1;
SCSP_w16(addr,val);
}
void SCSP_Slave_w32(unsigned int addr,unsigned int val)
{
SCSP=SCSPs+1;
SCSP_w32(addr,val);
}
unsigned char SCSP_Master_r8(unsigned int addr)
{
SCSP=SCSPs+0;
return SCSP_r8(addr);
}
unsigned short SCSP_Master_r16(unsigned int addr)
{
SCSP=SCSPs+0;
return SCSP_r16(addr);
}
unsigned int SCSP_Master_r32(unsigned int addr)
{
SCSP=SCSPs+0;
return SCSP_r32(addr);
}
unsigned char SCSP_Slave_r8(unsigned int addr)
{
SCSP=SCSPs+1;
return SCSP_r8(addr);
}
unsigned short SCSP_Slave_r16(unsigned int addr)
{
SCSP=SCSPs+1;
return SCSP_r16(addr);
}
unsigned int SCSP_Slave_r32(unsigned int addr)
{
SCSP=SCSPs+1;
return SCSP_r32(addr);
}
/******************************************************************************
Supermodel Interface Functions
2011-04-24 01:14:00 +00:00
******************************************************************************/
void SCSP_SaveState(CBlockFile *StateFile)
{
StateFile->NewBlock("SCSP x 2", __FILE__);
/*
* Save global variables.
*
* Difficult to say exactly what is necessary given that many things are
* commented out and should not be enabled but I try to save as much as
* possible.
*
* Things not saved:
*
* - Reverb buffers and pointers
* - FNS table (populated by SCSP_Init() and only read)
* - RB_VOLUME stuff
* - ARTABLE, DRTABLE
* - RBUFDST
*/
StateFile->Write(&IrqTimA, sizeof(IrqTimA));
StateFile->Write(&IrqTimBC, sizeof(IrqTimBC));
StateFile->Write(&IrqMidi, sizeof(IrqMidi));
StateFile->Write(MidiOutStack, sizeof(MidiOutStack));
StateFile->Write(&MidiOutW, sizeof(MidiOutW));
StateFile->Write(&MidiOutR, sizeof(MidiOutR));
StateFile->Write(MidiStack, sizeof(MidiStack));
StateFile->Write(&MidiOutFill, sizeof(MidiOutFill));
StateFile->Write(&MidiInFill, sizeof(MidiInFill));
StateFile->Write(&MidiW, sizeof(MidiW));
StateFile->Write(&MidiR, sizeof(MidiR));
StateFile->Write(TimPris, sizeof(TimPris));
StateFile->Write(TimCnt, sizeof(TimCnt));
// Save both SCSP states
for (int i = 0; i < 2; i++)
{
StateFile->Write(SCSPs[i].datab, sizeof(SCSPs[i].datab));
StateFile->Write(&(SCSPs[i].BUFPTR), sizeof(SCSPs[i].BUFPTR));
StateFile->Write(&(SCSPs[i].Master), sizeof(SCSPs[i].Master));
// Save each slot
for (int j = 0; j < 32; j++)
{
2011-09-05 20:07:14 +00:00
UINT64 baseOffset;
UINT8 egState;
StateFile->Write(SCSPs[i].Slots[j].datab, sizeof(SCSPs[i].Slots[j].datab));
StateFile->Write(&(SCSPs[i].Slots[j].active), sizeof(SCSPs[i].Slots[j].active));
2011-09-05 20:07:14 +00:00
baseOffset = (UINT64) (SCSPs[i].Slots[j].base - SCSPs[i].SCSPRAM);
StateFile->Write(&baseOffset, sizeof(baseOffset));
StateFile->Write(&(SCSPs[i].Slots[j].cur_addr), sizeof(SCSPs[i].Slots[j].cur_addr));
StateFile->Write(&(SCSPs[i].Slots[j].step), sizeof(SCSPs[i].Slots[j].step));
StateFile->Write(&(SCSPs[i].Slots[j].Back), sizeof(SCSPs[i].Slots[j].Back));
StateFile->Write(&(SCSPs[i].Slots[j].slot), sizeof(SCSPs[i].Slots[j].slot));
StateFile->Write(&(SCSPs[i].Slots[j].Prev), sizeof(SCSPs[i].Slots[j].Prev));
// EG
StateFile->Write(&(SCSPs[i].Slots[j].EG.volume), sizeof(SCSPs[i].Slots[j].EG.volume));
egState = SCSPs[i].Slots[j].EG.state;
StateFile->Write(&egState, sizeof(egState));
StateFile->Write(&(SCSPs[i].Slots[j].EG.step), sizeof(SCSPs[i].Slots[j].EG.step));
StateFile->Write(&(SCSPs[i].Slots[j].EG.AR), sizeof(SCSPs[i].Slots[j].EG.AR));
StateFile->Write(&(SCSPs[i].Slots[j].EG.D1R), sizeof(SCSPs[i].Slots[j].EG.D1R));
StateFile->Write(&(SCSPs[i].Slots[j].EG.D2R), sizeof(SCSPs[i].Slots[j].EG.D2R));
StateFile->Write(&(SCSPs[i].Slots[j].EG.RR), sizeof(SCSPs[i].Slots[j].EG.RR));
StateFile->Write(&(SCSPs[i].Slots[j].EG.DL), sizeof(SCSPs[i].Slots[j].EG.DL));
StateFile->Write(&(SCSPs[i].Slots[j].EG.EGHOLD), sizeof(SCSPs[i].Slots[j].EG.EGHOLD));
StateFile->Write(&(SCSPs[i].Slots[j].EG.LPLINK), sizeof(SCSPs[i].Slots[j].EG.LPLINK));
// PLFO
StateFile->Write(&(SCSPs[i].Slots[j].PLFO.phase), sizeof(SCSPs[i].Slots[j].PLFO.phase));
StateFile->Write(&(SCSPs[i].Slots[j].PLFO.phase_step), sizeof(SCSPs[i].Slots[j].PLFO.phase_step));
// ALFO
StateFile->Write(&(SCSPs[i].Slots[j].ALFO.phase), sizeof(SCSPs[i].Slots[j].ALFO.phase));
StateFile->Write(&(SCSPs[i].Slots[j].ALFO.phase_step), sizeof(SCSPs[i].Slots[j].ALFO.phase_step));
//when loading, make sure to compute lfo
}
// DSP
StateFile->Write(&(SCSPs[i].DSP.RBP), sizeof(SCSPs[i].DSP.RBP));
StateFile->Write(&(SCSPs[i].DSP.RBL), sizeof(SCSPs[i].DSP.RBL));
StateFile->Write(SCSPs[i].DSP.COEF, sizeof(SCSPs[i].DSP.COEF));
StateFile->Write(SCSPs[i].DSP.MADRS, sizeof(SCSPs[i].DSP.MADRS));
StateFile->Write(SCSPs[i].DSP.MPRO, sizeof(SCSPs[i].DSP.MPRO));
StateFile->Write(SCSPs[i].DSP.TEMP, sizeof(SCSPs[i].DSP.TEMP));
StateFile->Write(SCSPs[i].DSP.MEMS, sizeof(SCSPs[i].DSP.MEMS));
StateFile->Write(&(SCSPs[i].DSP.DEC), sizeof(SCSPs[i].DSP.DEC));
StateFile->Write(SCSPs[i].DSP.MIXS, sizeof(SCSPs[i].DSP.MIXS));
StateFile->Write(SCSPs[i].DSP.EXTS, sizeof(SCSPs[i].DSP.EXTS));
StateFile->Write(SCSPs[i].DSP.EFREG, sizeof(SCSPs[i].DSP.EFREG));
StateFile->Write(&(SCSPs[i].DSP.Stopped), sizeof(SCSPs[i].DSP.Stopped));
StateFile->Write(&(SCSPs[i].DSP.LastStep), sizeof(SCSPs[i].DSP.LastStep));
}
}
void SCSP_LoadState(CBlockFile *StateFile)
{
if (OKAY != StateFile->FindBlock("SCSP x 2"))
{
ErrorLog("Unable to load SCSP state. Save state file is corrupt.");
return;
}
// Load global variables
StateFile->Read(&IrqTimA, sizeof(IrqTimA));
StateFile->Read(&IrqTimBC, sizeof(IrqTimBC));
StateFile->Read(&IrqMidi, sizeof(IrqMidi));
StateFile->Read(MidiOutStack, sizeof(MidiOutStack));
StateFile->Read(&MidiOutW, sizeof(MidiOutW));
StateFile->Read(&MidiOutR, sizeof(MidiOutR));
StateFile->Read(MidiStack, sizeof(MidiStack));
StateFile->Read(&MidiOutFill, sizeof(MidiOutFill));
StateFile->Read(&MidiInFill, sizeof(MidiInFill));
StateFile->Read(&MidiW, sizeof(MidiW));
StateFile->Read(&MidiR, sizeof(MidiR));
StateFile->Read(TimPris, sizeof(TimPris));
StateFile->Read(TimCnt, sizeof(TimCnt));
// Load both SCSP states
for (int i = 0; i < 2; i++)
{
StateFile->Read(SCSPs[i].datab, sizeof(SCSPs[i].datab));
StateFile->Read(&(SCSPs[i].BUFPTR), sizeof(SCSPs[i].BUFPTR));
StateFile->Read(&(SCSPs[i].Master), sizeof(SCSPs[i].Master));
// Load each slot
for (int j = 0; j < 32; j++)
{
2011-09-05 20:07:14 +00:00
UINT64 baseOffset;
UINT8 egState;
StateFile->Read(SCSPs[i].Slots[j].datab, sizeof(SCSPs[i].Slots[j].datab));
StateFile->Read(&(SCSPs[i].Slots[j].active), sizeof(SCSPs[i].Slots[j].active));
StateFile->Read(&baseOffset, sizeof(baseOffset));
SCSPs[i].Slots[j].base = &(SCSPs[i].SCSPRAM[baseOffset&0xFFFFF]); // clamp to 1 MB
StateFile->Read(&(SCSPs[i].Slots[j].cur_addr), sizeof(SCSPs[i].Slots[j].cur_addr));
StateFile->Read(&(SCSPs[i].Slots[j].step), sizeof(SCSPs[i].Slots[j].step));
StateFile->Read(&(SCSPs[i].Slots[j].Back), sizeof(SCSPs[i].Slots[j].Back));
StateFile->Read(&(SCSPs[i].Slots[j].slot), sizeof(SCSPs[i].Slots[j].slot));
StateFile->Read(&(SCSPs[i].Slots[j].Prev), sizeof(SCSPs[i].Slots[j].Prev));
// EG
StateFile->Read(&(SCSPs[i].Slots[j].EG.volume), sizeof(SCSPs[i].Slots[j].EG.volume));
StateFile->Read(&egState, sizeof(egState));
SCSPs[i].Slots[j].EG.state = (_STATE) egState;
StateFile->Read(&(SCSPs[i].Slots[j].EG.step), sizeof(SCSPs[i].Slots[j].EG.step));
StateFile->Read(&(SCSPs[i].Slots[j].EG.AR), sizeof(SCSPs[i].Slots[j].EG.AR));
StateFile->Read(&(SCSPs[i].Slots[j].EG.D1R), sizeof(SCSPs[i].Slots[j].EG.D1R));
StateFile->Read(&(SCSPs[i].Slots[j].EG.D2R), sizeof(SCSPs[i].Slots[j].EG.D2R));
StateFile->Read(&(SCSPs[i].Slots[j].EG.RR), sizeof(SCSPs[i].Slots[j].EG.RR));
StateFile->Read(&(SCSPs[i].Slots[j].EG.DL), sizeof(SCSPs[i].Slots[j].EG.DL));
StateFile->Read(&(SCSPs[i].Slots[j].EG.EGHOLD), sizeof(SCSPs[i].Slots[j].EG.EGHOLD));
StateFile->Read(&(SCSPs[i].Slots[j].EG.LPLINK), sizeof(SCSPs[i].Slots[j].EG.LPLINK));
// PLFO
StateFile->Read(&(SCSPs[i].Slots[j].PLFO.phase), sizeof(SCSPs[i].Slots[j].PLFO.phase));
StateFile->Read(&(SCSPs[i].Slots[j].PLFO.phase_step), sizeof(SCSPs[i].Slots[j].PLFO.phase_step));
// ALFO
StateFile->Read(&(SCSPs[i].Slots[j].ALFO.phase), sizeof(SCSPs[i].Slots[j].ALFO.phase));
StateFile->Read(&(SCSPs[i].Slots[j].ALFO.phase_step), sizeof(SCSPs[i].Slots[j].ALFO.phase_step));
// Recompute LFOs
Compute_LFO(&(SCSPs[i].Slots[j]));
}
// DSP
StateFile->Read(&(SCSPs[i].DSP.RBP), sizeof(SCSPs[i].DSP.RBP));
StateFile->Read(&(SCSPs[i].DSP.RBL), sizeof(SCSPs[i].DSP.RBL));
StateFile->Read(SCSPs[i].DSP.COEF, sizeof(SCSPs[i].DSP.COEF));
StateFile->Read(SCSPs[i].DSP.MADRS, sizeof(SCSPs[i].DSP.MADRS));
StateFile->Read(SCSPs[i].DSP.MPRO, sizeof(SCSPs[i].DSP.MPRO));
StateFile->Read(SCSPs[i].DSP.TEMP, sizeof(SCSPs[i].DSP.TEMP));
StateFile->Read(SCSPs[i].DSP.MEMS, sizeof(SCSPs[i].DSP.MEMS));
StateFile->Read(&(SCSPs[i].DSP.DEC), sizeof(SCSPs[i].DSP.DEC));
StateFile->Read(SCSPs[i].DSP.MIXS, sizeof(SCSPs[i].DSP.MIXS));
StateFile->Read(SCSPs[i].DSP.EXTS, sizeof(SCSPs[i].DSP.EXTS));
StateFile->Read(SCSPs[i].DSP.EFREG, sizeof(SCSPs[i].DSP.EFREG));
StateFile->Read(&(SCSPs[i].DSP.Stopped), sizeof(SCSPs[i].DSP.Stopped));
StateFile->Read(&(SCSPs[i].DSP.LastStep), sizeof(SCSPs[i].DSP.LastStep));
}
}
2011-04-24 01:14:00 +00:00
void SCSP_SetBuffers(INT16 *leftBufferPtr, INT16 *rightBufferPtr, int bufferLength)
{
SysFPS = 60.0; // should this be updated to reflect actual FPS?
bufferl = leftBufferPtr;
bufferr = rightBufferPtr;
length = bufferLength;
cnts = 0; // what is this for? seems unimportant but need to find out
}
void SCSP_Deinit(void)
{
#ifdef USEDSP
free(SCSP->MIXBuf);
#endif
free(buffertmpl);
free(buffertmpr);
delete MIDILock;
buffertmpl = NULL;
buffertmpr = NULL;
MIDILock = NULL;
2011-04-24 01:14:00 +00:00
}