kopia lustrzana https://github.com/Jean-MarcHarvengt/MCUME
297 wiersze
8.3 KiB
C++
297 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"
|
|
static const i2s_port_t 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 SND_Process(void *sndbuffer, int sndn);
|
|
//}
|
|
#endif
|
|
|
|
|
|
static void snd_Mixer16(uint16_t * stream, int len )
|
|
{
|
|
if (playing)
|
|
{
|
|
#ifdef CUSTOM_SND
|
|
SND_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 cfg={
|
|
.mode=(i2s_mode_t)(I2S_MODE_DAC_BUILT_IN|I2S_MODE_TX|I2S_MODE_MASTER),
|
|
.sample_rate=DEFAULT_SAMPLERATE,
|
|
.bits_per_sample=I2S_BITS_PER_SAMPLE_16BIT,
|
|
.channel_format=I2S_CHANNEL_FMT_RIGHT_LEFT,
|
|
.communication_format=I2S_COMM_FORMAT_I2S_MSB,
|
|
.intr_alloc_flags=0,
|
|
.dma_buf_count=4,
|
|
.dma_buf_len=DEFAULT_SAMPLESIZE*4
|
|
};
|
|
i2s_driver_install(i2s_num, &cfg, 4, &queue);
|
|
//i2s_driver_install(i2s_num, &cfg, 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];
|
|
Buffer[i*2]=Buffer[i];
|
|
}
|
|
printf("%d\n",n);
|
|
i2s_write_bytes(i2s_num, (const void*)Buffer, n*4, portMAX_DELAY);
|
|
left-=n;
|
|
}
|
|
//i2s_write(i2s_num, i2s_write_buff, i2s_wr_len, &bytes_written, portMAX_DELAY);
|
|
#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
|
|
|
|
|