160 lines
4.4 KiB
C++
160 lines
4.4 KiB
C++
#ifndef YAZE_APP_EMU_AUDIO_S_DSP_H
|
|
#define YAZE_APP_EMU_AUDIO_S_DSP_H
|
|
|
|
#include <cstdint>
|
|
#include <functional>
|
|
#include <vector>
|
|
|
|
#include "app/emu/audio/spc700.h"
|
|
#include "app/emu/memory/memory.h"
|
|
|
|
namespace yaze {
|
|
namespace emu {
|
|
|
|
typedef struct DspChannel {
|
|
// pitch
|
|
uint16_t pitch;
|
|
uint16_t pitchCounter;
|
|
bool pitchModulation;
|
|
// brr decoding
|
|
int16_t decodeBuffer[12];
|
|
uint8_t bufferOffset;
|
|
uint8_t srcn;
|
|
uint16_t decodeOffset;
|
|
uint8_t blockOffset; // offset within brr block
|
|
uint8_t brrHeader;
|
|
bool useNoise;
|
|
uint8_t startDelay;
|
|
// adsr, envelope, gain
|
|
uint8_t adsrRates[4]; // attack, decay, sustain, gain
|
|
uint8_t adsrState; // 0: attack, 1: decay, 2: sustain, 3: release
|
|
uint8_t sustainLevel;
|
|
uint8_t gainSustainLevel;
|
|
bool useGain;
|
|
uint8_t gainMode;
|
|
bool directGain;
|
|
uint16_t gainValue; // for direct gain
|
|
uint16_t preclampGain; // for bent increase
|
|
uint16_t gain;
|
|
// keyon/off
|
|
bool keyOn;
|
|
bool keyOff;
|
|
// output
|
|
int16_t sampleOut; // final sample, to be multiplied by channel volume
|
|
int8_t volumeL;
|
|
int8_t volumeR;
|
|
bool echoEnable;
|
|
} DspChannel;
|
|
|
|
/**
|
|
* The S-DSP is a digital signal processor generating the sound data.
|
|
*
|
|
* A DSP register can be selected with $F2, after which it can be read or
|
|
* written at $F3. Often it is useful to load the register address into A, and
|
|
* the value to send in Y, so that MOV $F2, YA can be used to do both in one
|
|
* 16-bit instruction.
|
|
*
|
|
* The DSP register address space only has 7 bits. The high bit of $F2, if set,
|
|
* will make the selected register read-only via $F3.
|
|
*
|
|
* When initializing the DSP registers for the first time, take care not to
|
|
* accidentally enable echo writeback via FLG, because it will immediately begin
|
|
* overwriting values in RAM.
|
|
*
|
|
* Voices
|
|
* There are 8 voices, numbered 0 to 7.
|
|
* Each voice X has 10 registers in the range $X0-$X9.
|
|
*
|
|
* | Name | Address | Bits | Notes |
|
|
* |---------|---------|-----------|--------------------------------------------------------|
|
|
* | VOL (L) | $X0 | SVVV VVVV | Left channel volume, signed. | | VOL (R) |
|
|
* $X1 | SVVV VVVV | Right channel volume, signed. | | P (L) | $X2 |
|
|
* LLLL LLLL | Low 8 bits of sample pitch. | | P (H)
|
|
* | $X3 | --HH HHHH | High 6 bits of sample pitch. | | SCRN | $X4 |
|
|
* SSSS SSSS | Selects a sample source entry from the directory. | | ADSR
|
|
* (1)| $X5 | EDDD AAAA | ADSR enable (E), decay rate (D), attack rate (A).
|
|
* | | ADSR (2)| $X6 | SSSR RRRR | Sustain level (S), release rate (R). | |
|
|
* GAIN | $X7 | 0VVV VVVV 1MMV VVVV | Mode (M), value (V). | | ENVX |
|
|
* $X8 | 0VVV VVVV | Reads current 7-bit value of ADSR/GAIN envelope. | |
|
|
* OUTX | $X9 | SVVV VVVV | Reads signed 8-bit value of current sample
|
|
* wave | | | | | multiplied by ENVX, before
|
|
* applying VOL. |
|
|
*/
|
|
|
|
class Dsp {
|
|
public:
|
|
Dsp(std::vector<uint8_t>& aram) : aram_(aram) {}
|
|
|
|
void NewFrame();
|
|
|
|
void Reset();
|
|
|
|
void Cycle();
|
|
|
|
void HandleEcho();
|
|
void CycleChannel(int ch);
|
|
|
|
void HandleNoise();
|
|
void HandleGain(int ch);
|
|
|
|
bool CheckCounter(int rate);
|
|
|
|
void DecodeBrr(int ch);
|
|
|
|
uint8_t Read(uint8_t adr);
|
|
void Write(uint8_t adr, uint8_t val);
|
|
|
|
int16_t GetSample(int ch);
|
|
|
|
void GetSamples(int16_t* sample_data, int samples_per_frame, bool pal_timing);
|
|
|
|
private:
|
|
int16_t sample_buffer_[0x400 * 2]; // (1024 samples, *2 for stereo)
|
|
int16_t sample_offset_; // current offset in samplebuffer
|
|
|
|
std::vector<uint8_t>& aram_;
|
|
|
|
// mirror ram
|
|
uint8_t ram[0x80];
|
|
// 8 channels
|
|
DspChannel channel[8];
|
|
// overarching
|
|
uint16_t counter;
|
|
uint16_t dirPage;
|
|
bool evenCycle;
|
|
bool mute;
|
|
bool reset;
|
|
int8_t masterVolumeL;
|
|
int8_t masterVolumeR;
|
|
// accumulation
|
|
int16_t sampleOutL;
|
|
int16_t sampleOutR;
|
|
int16_t echoOutL;
|
|
int16_t echoOutR;
|
|
// noise
|
|
int16_t noiseSample;
|
|
uint8_t noiseRate;
|
|
// echo
|
|
bool echoWrites;
|
|
int8_t echoVolumeL;
|
|
int8_t echoVolumeR;
|
|
int8_t feedbackVolume;
|
|
uint16_t echoBufferAdr;
|
|
uint16_t echoDelay;
|
|
uint16_t echoLength;
|
|
uint16_t echoBufferIndex;
|
|
uint8_t firBufferIndex;
|
|
int8_t firValues[8];
|
|
int16_t firBufferL[8];
|
|
int16_t firBufferR[8];
|
|
// sample ring buffer (1024 samples, *2 for stereo)
|
|
int16_t sampleBuffer[0x400 * 2];
|
|
uint16_t sampleOffset; // current offset in samplebuffer
|
|
uint32_t lastFrameBoundary;
|
|
};
|
|
|
|
} // namespace emu
|
|
} // namespace yaze
|
|
|
|
#endif // YAZE_APP_EMU_AUDIO_S_DSP_H
|