diff --git a/include/pinmap/esp32s3-wroom-1.h b/include/pinmap/esp32s3-wroom-1.h index 1435df0aa..0cb2a021b 100644 --- a/include/pinmap/esp32s3-wroom-1.h +++ b/include/pinmap/esp32s3-wroom-1.h @@ -37,6 +37,17 @@ #define PIN_LED_BT GPIO_NUM_NC #endif +/* C64 IEC Pins */ +// Reset line is available +// #define IEC_HAS_RESET +// #define PIN_IEC_RESET GPIO_NUM_14 +#define PIN_IEC_ATN GPIO_NUM_38 +#define PIN_IEC_CLK_IN GPIO_NUM_39 +#define PIN_IEC_CLK_OUT GPIO_NUM_40 +#define PIN_IEC_DATA_IN GPIO_NUM_41 +#define PIN_IEC_DATA_OUT GPIO_NUM_42 +#define PIN_IEC_SRQ GPIO_NUM_2 // FujiLoaf + /* Atari SIO Pins */ #define PIN_INT GPIO_NUM_38 // sio.h #define PIN_PROC GPIO_NUM_39 @@ -45,8 +56,16 @@ #define PIN_MTR GPIO_NUM_42 #define PIN_CMD GPIO_NUM_2 + /* Audio Output */ -#define PIN_DAC1 GPIO_NUM_NC +#define PIN_DAC1 GPIO_NUM_21 //GPIO_NUM_NC + +/* I2S Audio Output */ +#ifdef ESP32S3_I2S_OUT + #define PIN_I2S_SCK GPIO_NUM_6 + #define PIN_I2S_WS GPIO_NUM_5 + #define PIN_I2S_SDO GPIO_NUM_4 +#endif #endif /* PINMAP_ESP32S3_WROOM_1 */ diff --git a/lib/device/sio/voice.cpp b/lib/device/sio/voice.cpp index 01ac722e8..0b2bba7af 100755 --- a/lib/device/sio/voice.cpp +++ b/lib/device/sio/voice.cpp @@ -10,17 +10,87 @@ using namespace std; #define EOL 0x9B + +void sioVoice::sio_sam_presets(int pr) +{ +// DESCRIPTION SPEED PITCH THROAT MOUTH +// SAM 72 64 128 128 +// Elf 72 64 110 160 +// Little Robot 92 60 190 190 +// Stuffy Guy 82 72 110 105 +// Little Old Lady 82 32 145 145 +// Extra-Terrestrial 100 64 150 200 + + switch (pr) + { + case 0: //SAM + speed = "72"; + pitch = "64"; + throat = "128"; + mouth = "128"; + break; + case 1: //Elf + speed = "72"; + pitch = "64"; + throat = "110"; + mouth = "160"; + break; + case 2: //Little Robot + speed = "92"; + pitch = "60"; + throat = "190"; + mouth = "190"; + break; + case 3: //Stuffy Guy + speed = "82"; + pitch = "72"; + throat = "110"; + mouth = "105"; + break; + case 4: //Little Old Lady + speed = "82"; + pitch = "32"; + throat = "145"; + mouth = "145"; + break; + case 5: //Extra-Terrestrial + speed = "100"; + pitch = "64"; + throat = "150"; + mouth = "200"; + break; + default: + break; + } + + +} + void sioVoice::sio_sam_parameters() { string s = string((char *)lineBuffer); // change to lineBuffer vector tokens = util_tokenize(s, ' '); + + for (vector::iterator it = tokens.begin(); it != tokens.end(); ++it) { string t = *it; + switch (t[0]) { +#ifdef ESP32S3_I2S_OUT + case 0x01: // ^A i2sOut + i2sOut = *(++it); + break; +#endif +// case 0x02: // ^B SampleRate +// samplerate = *(++it); +// break; + case 0x03: // ^C Preset + sio_sam_presets(atoi((*(++it)).c_str())); + break; case 0x07: // ^G SING sing = true; break; @@ -35,11 +105,8 @@ void sioVoice::sio_sam_parameters() break; case 0x12: // ^R RESET sing = false; - pitch.clear(); - mouth.clear(); phonetic = false; - speed.clear(); - throat.clear(); + sio_sam_presets(0); break; case 0x13: // ^S Speed speed = *(++it); @@ -71,8 +138,25 @@ void sioVoice::sio_sam() sio_sam_parameters(); + +// if (!samplerate.empty()) +// { +// a[n++] = (char *)("-samplerate"); +// a[n++] = (char *)(samplerate.c_str()); +// } + +#ifdef ESP32S3_I2S_OUT + if (!i2sOut.empty()) + { + a[n++] = (char *)("-i2sOut"); + a[n++] = (char *)(i2sOut.c_str()); + } +#endif + if (sing == true) a[n++] = (char *)("-sing"); + else + a[n++] = (char *)("-no-sing"); if (!pitch.empty()) { @@ -88,12 +172,9 @@ void sioVoice::sio_sam() if (phonetic == true) a[n++] = (char *)("-phonetic"); +// else +// a[n++] = (char *)("-no-phonetic"); - if (!pitch.empty()) - { - a[n++] = (char *)("-pitch"); - a[n++] = (char *)(pitch.c_str()); - } if (!speed.empty()) { diff --git a/lib/device/sio/voice.h b/lib/device/sio/voice.h index 488bf8d7b..da0511439 100755 --- a/lib/device/sio/voice.h +++ b/lib/device/sio/voice.h @@ -27,9 +27,14 @@ class sioVoice : public virtualDevice bool phonetic = false; std::string speed; std::string throat; +// std::string samplerate; +#ifdef ESP32S3_I2S_OUT + std::string i2sOut; +#endif void sio_sam(); void sio_sam_parameters(); + void sio_sam_presets(int pr); public: }; diff --git a/lib/sam/sam.c b/lib/sam/sam.c index ddcadd662..229a930e8 100644 --- a/lib/sam/sam.c +++ b/lib/sam/sam.c @@ -63,6 +63,7 @@ void SetPitch(unsigned char _pitch) { pitch = _pitch; } void SetMouth(unsigned char _mouth) { mouth = _mouth; } void SetThroat(unsigned char _throat) { throat = _throat; } void EnableSingmode() { singmode = 1; } +void DisableSingmode() { singmode = 0; } char *GetBuffer() { return buffer; } int GetBufferLength() { return bufferpos; } void FreeBuffer() { free(buffer); } diff --git a/lib/sam/sam.h b/lib/sam/sam.h index ed6df0ca0..6d43bf16b 100644 --- a/lib/sam/sam.h +++ b/lib/sam/sam.h @@ -12,6 +12,7 @@ extern "C" void SetMouth(unsigned char _mouth); void SetThroat(unsigned char _throat); void EnableSingmode(); + void DisableSingmode(); void EnableDebug(); int SAMMain(); diff --git a/lib/sam/samlib.cpp b/lib/sam/samlib.cpp index 234010aa8..b2c62f00a 100644 --- a/lib/sam/samlib.cpp +++ b/lib/sam/samlib.cpp @@ -17,6 +17,61 @@ extern char *buffer; #endif int debug = 0; +const uint32_t sample_rate = 22050;//110000l; + + +#ifdef CONFIG_IDF_TARGET_ESP32S3 + + //PDM NEW API +#include + +// ESP32S3_I2S_OUT +#ifdef ESP32S3_I2S_OUT + //i2s Output + #include + bool i2sOut = true; +#endif + + +void SendI2S (i2s_chan_handle_t tx_handle, char *s, size_t n) +{ +// number of frames to try and send at once (a frame is a left and right sample) + const size_t NUM_FRAMES_TO_SEND=1023;//1024; + int16_t * m_tmp_frames = (int16_t *)malloc(sizeof(int16_t) * NUM_FRAMES_TO_SEND); + int16_t iTmp; + esp_err_t res; + size_t bytes_written; + int samples_to_send; + int sample_index = 0; + + while (sample_index < n) + { + samples_to_send = 0; + + for (int i = 0; i < NUM_FRAMES_TO_SEND && sample_index < n; i++) + { + // shift up to 16 bit samples + iTmp = ((int16_t) (s[sample_index])) << 8; + m_tmp_frames[i] = iTmp; + samples_to_send++; + sample_index++; + } + // write data to the i2s peripheral + bytes_written = 0; + res = i2s_channel_write(tx_handle, m_tmp_frames, samples_to_send * sizeof(int16_t), &bytes_written, 1000 / portTICK_PERIOD_MS); + if (res != ESP_OK) + { + printf ("Error sending audio data: %d", res); + } + printf ("i2s write : Send %d Bytes of %d/%d Samples \n", bytes_written, samples_to_send, n); + } + + free(m_tmp_frames); + +} + + +#endif #ifndef ESP_PLATFORM @@ -153,7 +208,7 @@ void OutputSound() SDL_CloseAudio(); } -#else +#else //Not def USESDL void OutputSound() { @@ -180,11 +235,143 @@ void OutputSound() dac_output_disable(DAC_CHANNEL_1); FreeBuffer(); -#endif -#endif +#else //Defined CONFIG_IDF_TARGET_ESP32S3 +//SampleRate = 22050 +//8 Bits + int n = GetBufferLength() / 50; + char *s = GetBuffer(); + //PDMOutput *audioOutput = NULL; + + + +//#ifdef ESP32S3_I2S_OUT +// if (!i2sOut) { +//#endif + +//PDM always but I2D only if defined ESP32S3_I2S_OUT and i2sOut is true (can change with print #1;"CTRL-A X") X : 0 Disable, 1 Enable. + +//New API +//Init/Config + i2s_chan_handle_t tx_handle; + /* Allocate an I2S tx channel */ + i2s_chan_config_t chan_cfg = //I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER); + { + .id = I2S_NUM_0, + .role = I2S_ROLE_MASTER, + .dma_desc_num = 4,//6, + .dma_frame_num = 1024,//240, + .auto_clear = false, + }; + i2s_new_channel(&chan_cfg, &tx_handle, NULL); + + /* Init the channel into PDM TX mode */ + i2s_pdm_tx_config_t pdm_tx_cfg = { + .clk_cfg = //I2S_PDM_TX_CLK_DEFAULT_CONFIG(sample_rate), + { + .sample_rate_hz = sample_rate, + .clk_src = I2S_CLK_SRC_DEFAULT, + .mclk_multiple = I2S_MCLK_MULTIPLE_256, + .up_sample_fp = 960, + .up_sample_fs = 480 + }, + + .slot_cfg = //I2S_PDM_TX_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO), + { + .data_bit_width = I2S_DATA_BIT_WIDTH_16BIT, + .slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, + .slot_mode = I2S_SLOT_MODE_MONO, //I2S_SLOT_MODE_STEREO, + .sd_prescale = 0, + .sd_scale = I2S_PDM_SIG_SCALING_MUL_1, + .hp_scale = I2S_PDM_SIG_SCALING_MUL_1, //I2S_PDM_SIG_SCALING_DIV_2, + .lp_scale = I2S_PDM_SIG_SCALING_MUL_1, + .sinc_scale = I2S_PDM_SIG_SCALING_MUL_1, + .line_mode = I2S_PDM_TX_ONE_LINE_DAC, //I2S_PDM_TX_ONE_LINE_CODEC + .hp_en = true, + .hp_cut_off_freq_hz = 49, // 35.5, + .sd_dither = 0, + .sd_dither2 = 1, + }, + .gpio_cfg = { + .clk = GPIO_NUM_NC,//(gpio_num_t) I2S_PIN_NO_CHANGE, //GPIO_NUM_5, + .dout = PIN_DAC1,//GPIO_NUM_18, + .invert_flags = { + .clk_inv = false, + }, + }, + }; + + i2s_channel_init_pdm_tx_mode(tx_handle, &pdm_tx_cfg); + i2s_channel_enable(tx_handle); + + SendI2S (tx_handle, s, n); + + /* Have to stop the channel before deleting it */ + i2s_channel_disable(tx_handle); + /* If the handle is not needed any more, delete it to release the channel resources */ + i2s_del_channel(tx_handle); + +//#ifdef ESP32S3_I2S_OUT +// } +// else //i2sOut : It need 3 Pins + +#ifdef ESP32S3_I2S_OUT + if (i2sOut) + { + i2s_chan_handle_t tx_handle; + /* Get the default channel configuration by helper macro. + * This helper macro is defined in 'i2s_common.h' and shared by all the i2s communication mode. + * It can help to specify the I2S role, and port id */ + i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER); + /* Allocate a new tx channel and get the handle of this channel */ + i2s_new_channel(&chan_cfg, &tx_handle, NULL); + + /* Setting the configurations, the slot configuration and clock configuration can be generated by the macros + * These two helper macros is defined in 'i2s_std.h' which can only be used in STD mode. + * They can help to specify the slot and clock configurations for initialization or updating */ + i2s_std_config_t std_cfg = { + .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(sample_rate), + .slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO), + .gpio_cfg = { + .mclk = I2S_GPIO_UNUSED, + .bclk = PIN_I2S_SCK,//sCLK + .ws = PIN_I2S_WS, //L/R + .dout = PIN_I2S_SDO,//Data + .din = I2S_GPIO_UNUSED, + .invert_flags = { + .mclk_inv = false, + .bclk_inv = false, + .ws_inv = false, + }, + }, + }; + /* Initialize the channel */ + i2s_channel_init_std_mode(tx_handle, &std_cfg); + + /* Before write data, start the tx channel first */ + i2s_channel_enable(tx_handle); + + //i2s_channel_write(tx_handle, src_buf, bytes_to_write, bytes_written, ticks_to_wait); + //i2s_channel_write(tx_handle, s, n, &bytes_written, 1000 / portTICK_PERIOD_MS); + SendI2S (tx_handle, s, n); + + /* Have to stop the channel before deleting it */ + i2s_channel_disable(tx_handle); + /* If the handle is not needed any more, delete it to release the channel resources */ + i2s_del_channel(tx_handle); + +// /I2S_STD + + } +#endif //ESP32S3_I2S_OUT + + FreeBuffer(); + + +#endif //CONFIG_IDF_TARGET_ESP32S3 +#endif //ESP_PLATFORM } -#endif +#endif //USESDL int sam(int argc, char **argv) { @@ -214,7 +401,7 @@ int sam(int argc, char **argv) } else { - + if (strcmp(&argv[i][1], "wav") == 0) { #ifndef ESP_PLATFORM @@ -224,14 +411,26 @@ int sam(int argc, char **argv) } else - if (strcmp(&argv[i][1], "sing") == 0) + if (strcmp(&argv[i][1], "sing") == 0) { EnableSingmode(); } + else if (strcmp(&argv[i][1], "no-sing") == 0) + { + DisableSingmode(); + } +// else if (strcmp(&argv[i][1], "samplerate") == 0) +// { +// sample_rate = (uint32_t) atol(argv[++i]); +// } else if (strcmp(&argv[i][1], "phonetic") == 0) { phonetic = 1; } +// else if (strcmp(&argv[i][1], "no-phonetic") == 0) +// { +// phonetic = 0; +// } else if (strcmp(&argv[i][1], "debug") == 0) { debug = 1; @@ -256,6 +455,12 @@ int sam(int argc, char **argv) SetThroat(atoi(argv[i + 1])); i++; } +#ifdef ESP32S3_I2S_OUT + else if (strcmp(&argv[i][1], "i2sOut") == 0) + { + i2sOut = (atoi(argv[++i])!=0); + } +#endif else { PrintUsage();