MCUME/MCUME_esp32/esp5200/main/AudioPlaySystem.cpp

291 wiersze
8.3 KiB
C++

extern "C" {
#include "emuapi.h"
}
#ifdef HAS_SND
#include "AudioPlaySystem.h"
#include "esp_system.h"
//#define USE_I2S 1
#ifdef USE_I2S
#include "esp_event.h"
#include "driver/i2s.h"
#include "freertos/queue.h"
#include "string.h"
#define I2S_NUM ((i2s_port_t)0)
//static QueueHandle_t queue;
#else
#include "esp32-hal-timer.h"
#include "esp32-hal-dac.h"
static int32_t LastPlayPos=0;
volatile int32_t NextPlayPos=0;
volatile uint8_t DacPin;
uint16_t LastDacValue;
hw_timer_t * timer = NULL;
#endif
volatile uint16_t *Buffer;
volatile uint16_t BufferSize;
static const short square[]={
32767,32767,32767,32767,
32767,32767,32767,32767,
32767,32767,32767,32767,
32767,32767,32767,32767,
32767,32767,32767,32767,
32767,32767,32767,32767,
32767,32767,32767,32767,
32767,32767,32767,32767,
-32767,-32767,-32767,-32767,
-32767,-32767,-32767,-32767,
-32767,-32767,-32767,-32767,
-32767,-32767,-32767,-32767,
-32767,-32767,-32767,-32767,
-32767,-32767,-32767,-32767,
-32767,-32767,-32767,-32767,
-32767,-32767,-32767,-32767,
};
const short noise[] {
-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,
-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,32767,-32767,
-32767,-32767,32767,-32767,-32767,-32767,32767,-32767,-32767,-32767,32767,-32767,-32767,-32767,32767,-32767,
-32767,-32767,32767,-32767,-32767,-32767,32767,-32767,-32767,-32767,32767,-32767,-32767,32767,32767,-32767,
-32767,-32767,32767,-32767,-32767,32767,32767,-32767,-32767,-32767,32767,-32767,-32767,32767,32767,-32767,
-32767,-32767,32767,-32767,-32767,32767,32767,-32767,-32767,-32767,32767,-32767,32767,32767,32767,-32767,
32767,-32767,32767,-32767,-32767,32767,32767,-32767,-32767,-32767,32767,-32767,32767,32767,32767,-32767,
32767,-32767,32767,-32767,-32767,32767,32767,-32767,-32767,-32767,32767,32767,32767,32767,32767,-32767,
32767,-32767,32767,-32767,-32767,32767,32767,-32767,-32767,-32767,32767,32767,32767,32767,32767,-32767,
32767,-32767,32767,-32767,-32767,32767,32767,-32767,-32767,-32767,-32767,32767,32767,32767,-32767,-32767,
32767,-32767,-32767,-32767,-32767,32767,-32767,-32767,-32767,-32767,32767,32767,32767,32767,32767,-32767,
32767,-32767,32767,-32767,-32767,32767,32767,-32767,-32767,32767,-32767,32767,32767,32767,-32767,-32767,
32767,32767,-32767,-32767,-32767,32767,-32767,-32767,-32767,-32767,32767,32767,32767,32767,32767,-32767,
32767,-32767,32767,-32767,-32767,32767,32767,-32767,32767,32767,-32767,32767,-32767,32767,-32767,-32767,
32767,32767,-32767,-32767,-32767,32767,-32767,-32767,-32767,-32767,32767,32767,32767,32767,32767,-32767,
32767,-32767,32767,-32767,-32767,32767,32767,32767,32767,32767,-32767,32767,-32767,32767,-32767,-32767,
};
#define NOISEBSIZE 0x100
typedef struct
{
unsigned int spos;
unsigned int sinc;
unsigned int vol;
} Channel;
volatile bool playing = false;
static Channel chan[6] = {
{0,0,0},
{0,0,0},
{0,0,0},
{0,0,0},
{0,0,0},
{0,0,0} };
static void snd_Reset(void)
{
chan[0].vol = 0;
chan[1].vol = 0;
chan[2].vol = 0;
chan[3].vol = 0;
chan[4].vol = 0;
chan[5].vol = 0;
chan[0].sinc = 0;
chan[1].sinc = 0;
chan[2].sinc = 0;
chan[3].sinc = 0;
chan[4].sinc = 0;
chan[5].sinc = 0;
}
#ifdef CUSTOM_SND
extern "C" {
void POKEYSND_Process(void *sndbuffer, int sndn);
}
#endif
static void snd_Mixer16(uint16_t * stream, int len )
{
if (playing)
{
#ifdef CUSTOM_SND
POKEYSND_Process((void*)stream, len);
#else
int i;
long s;
//len = len >> 1;
short v0=chan[0].vol;
short v1=chan[1].vol;
short v2=chan[2].vol;
short v3=chan[3].vol;
short v4=chan[4].vol;
short v5=chan[5].vol;
for (i=0;i<len;i++)
{
s = ( v0*(square[(chan[0].spos>>8)&0x3f]) );
s+= ( v1*(square[(chan[1].spos>>8)&0x3f]) );
s+= ( v2*(square[(chan[2].spos>>8)&0x3f]) );
s+= ( v3*(noise[(chan[3].spos>>8)&(NOISEBSIZE-1)]) );
s+= ( v4*(noise[(chan[4].spos>>8)&(NOISEBSIZE-1)]) );
s+= ( v5*(noise[(chan[5].spos>>8)&(NOISEBSIZE-1)]) );
*stream++ = int16_t((s>>11));
chan[0].spos += chan[0].sinc;
chan[1].spos += chan[1].sinc;
chan[2].spos += chan[2].sinc;
chan[3].spos += chan[3].sinc;
chan[4].spos += chan[4].sinc;
chan[5].spos += chan[5].sinc;
}
#endif
}
}
#ifdef USE_I2S
#else
void IRAM_ATTR onTimer()
{
// Sound playing code, plays whatever's in the buffer continuously. Big change from previous versions
if(LastDacValue!=Buffer[NextPlayPos]) // Send value to DAC only of changed since last value else no need
{
// value to DAC has changed, send to actual hardware, else we just leave setting as is as it's not changed
LastDacValue=Buffer[NextPlayPos];
dacWrite(DacPin,uint8_t((LastDacValue>>8)+127)); // write out the data
}
Buffer[NextPlayPos]=0; // Reset this buffer byte back to silence
NextPlayPos++; // Move play pos to next byte in buffer
if(NextPlayPos==BufferSize) // If gone past end of buffer,
NextPlayPos=0; // set back to beginning
}
#endif
void AudioPlaySystem::begin(void)
{
#ifdef USE_I2S
Buffer = (uint16_t *)malloc(DEFAULT_SAMPLESIZE*4); //16bits, L+R
uint16_t * dst=(uint16_t *)Buffer;
for (int i=0; i<DEFAULT_SAMPLESIZE; i++) {
*dst++=32767;
*dst++=32767;
};
i2s_config_t i2s_config;
i2s_config.mode = (i2s_mode_t)(I2S_MODE_DAC_BUILT_IN|I2S_MODE_TX|I2S_MODE_MASTER);
i2s_config.sample_rate=DEFAULT_SAMPLERATE;
i2s_config.bits_per_sample=I2S_BITS_PER_SAMPLE_16BIT;
i2s_config.communication_format=I2S_COMM_FORMAT_I2S_MSB;
i2s_config.dma_buf_count = 2;
i2s_config.dma_buf_len = DEFAULT_SAMPLESIZE;
i2s_config.use_apll = false;
i2s_config.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1;
//i2s_driver_install(I2S_NUM, &i2s_config, 4, &queue);
i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
i2s_set_pin(I2S_NUM, NULL);
i2s_set_dac_mode(I2S_DAC_CHANNEL_LEFT_EN);
//I2S enables *both* DAC channels; we only need DAC1.
//ToDo: still needed now I2S supports set_dac_mode?
//CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_DAC_XPD_FORCE_M);
//CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_XPD_DAC_M);
#else
BufferSize = DEFAULT_SAMPLESIZE;
Buffer=(volatile uint16_t *)malloc(BufferSize*2);
volatile uint16_t * dst=Buffer;
for (int i=0; i<BufferSize; i++) {
*dst++=0;
};
DacPin=25; // set dac pin to use
LastDacValue=0; // set to mid point
dacWrite(DacPin,LastDacValue); // Set speaker to mid point, stops click at start of first sound
// Set up interrupt routine
timer = timerBegin(0, 80, true); // use timer 0, pre-scaler is 80 (divide by 8000), count up
timerAttachInterrupt(timer, &onTimer, true); // P3= edge triggered
timerAlarmWrite(timer, 45, true); // will trigger 22050 times per sec (443 per 20 ms=22050/50)
timerAlarmEnable(timer);
#endif
}
void AudioPlaySystem::start(void)
{
playing = true;
}
void AudioPlaySystem::setSampleParameters(float clockfreq, float samplerate) {
}
void AudioPlaySystem::reset(void)
{
snd_Reset();
}
void AudioPlaySystem::stop(void)
{
playing = false;
#ifdef USE_I2S
i2s_driver_uninstall(I2S_NUM); //stop & destroy i2s driver
#else
#endif
}
bool AudioPlaySystem::isPlaying(void)
{
return playing;
}
void AudioPlaySystem::sound(int C, int F, int V) {
if (C < 6) {
//printf("play %d %d %d\n",C,F,V);
chan[C].vol = V;
chan[C].sinc = F>>1;
}
}
void AudioPlaySystem::step(void)
{
#ifdef USE_I2S
int left=DEFAULT_SAMPLERATE/50;
while(left) {
int n=DEFAULT_SAMPLESIZE;
if (n>left) n=left;
snd_Mixer16((uint16_t*)Buffer, n);
//16 bit mono -> 16 bit r+l
for (int i=n-1; i>=0; i--) {
Buffer[i*2+1]=Buffer[i]+32767;
Buffer[i*2]=Buffer[i]+32767;
}
i2s_write_bytes(I2S_NUM, (const void*)Buffer, n*4, portMAX_DELAY);
left-=n;
}
#else
int32_t CurPos=NextPlayPos;
int32_t samples;
if (CurPos > LastPlayPos) {
snd_Mixer16((uint16_t *)&Buffer[LastPlayPos], CurPos-LastPlayPos);
samples = CurPos-LastPlayPos;
}
else {
snd_Mixer16((uint16_t *)&Buffer[LastPlayPos], BufferSize-LastPlayPos);
snd_Mixer16((uint16_t *)&Buffer[0], CurPos);
samples = BufferSize-LastPlayPos;
samples += CurPos;
}
LastPlayPos = CurPos;
//printf("sam %d\n",bytes);
#endif
}
#endif