acid-drop

- Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.acid.vegas/-c.git
Log | Files | Refs | Archive | README | LICENSE

commit 86b4488d92e1e031de73ea8bff4e933224e3be26
parent e991577a77633676ee456088df86d694e111e051
Author: acidvegas <acid.vegas@acid.vegas>
Date: Wed, 5 Jun 2024 15:06:51 -0400

Added support for the T-Deck internal speaker! Boot sounds added, notification sounds incomming.

Diffstat:
MREADME.md | 2+-
Mplatformio.ini | 6++----
Asrc/Speaker.h | 151++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rsrc/boot_screen.h -> src/bootScreen.h | 0
Msrc/main.ino | 10++++++++--
Msrc/pins.h | 9+++++----

6 files changed, 167 insertions(+), 11 deletions(-)

diff --git a/README.md b/README.md
@@ -51,7 +51,7 @@ The device will scan for WiFi networks on boot. Once the list is displayed, you 
 - [X] Screen timeout on inactivity *(default 30 seconds)*
   - [ ] Keyboard backlight timeout with screen timeout
 - [ ] Trackball support
-- [ ] Speaker support
+- [X] Speaker support
 - [ ] GPS support
 - [ ] Lora support
 - [ ] BLE support
diff --git a/platformio.ini b/platformio.ini
@@ -24,6 +24,4 @@ build_flags =
 	-DARDUINO_USB_CDC_ON_BOOT=1
 	-DDISABLE_ALL_LIBRARY_WARNINGS
 lib_deps =
-    ;mikalhart/TinyGPSPlus@^1.0.2
-	marian-craciunescu/ESP32Ping@^1.7.0
-	;sandeepmistry/LoRa
-\ No newline at end of file
+lib_extra_dirs = lib
+\ No newline at end of file
diff --git a/src/Speaker.h b/src/Speaker.h
@@ -0,0 +1,151 @@
+#pragma once
+
+#include <Arduino.h>
+#include <driver/i2s.h>
+
+#include "pins.h"
+
+#define BOARD_I2S_PORT I2S_NUM_0
+#define SAMPLE_RATE 44100
+
+
+const float NOTE_FREQS[] = {
+    261.63, 277.18, 293.66, 311.13, 329.63, 349.23, 369.99, 392.00, 415.30, 440.00, 466.16, 493.88, // C4 to B4
+    523.25, 554.37, 587.33, 622.25, 659.25, 698.46, 739.99, 783.99, 830.61, 880.00, 932.33, 987.77, // C5 to B5
+    1046.50, 1108.73, 1174.66, 1244.51, 1318.51, 1396.91, 1480.00, 1568.00, 1661.22, 1760.00, 1864.66, 1975.53, // C6 to B6
+    2093.00, 2217.46, 2349.32, 2489.02, 2637.02, 2793.83, 2960.00, 3136.00, 3322.44, 3520.00, 3729.31, 3951.07  // C7 to B7
+};
+
+
+float getNoteFrequency(char note, int octave) {
+    if (note == 'p') return 0;  // Pause
+    int noteIndex = 0;
+    switch (note) {
+        case 'c': noteIndex = 0; break;
+        case 'd': noteIndex = 2; break;
+        case 'e': noteIndex = 4; break;
+        case 'f': noteIndex = 5; break;
+        case 'g': noteIndex = 7; break;
+        case 'a': noteIndex = 9; break;
+        case 'b': noteIndex = 11; break;
+        default: return 0;
+    }
+    return NOTE_FREQS[noteIndex + ((octave - 4) * 12)];
+}
+
+
+void setupI2S() {
+    i2s_config_t i2s_config = {
+        .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
+        .sample_rate = SAMPLE_RATE,
+        .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
+        .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
+        .communication_format = I2S_COMM_FORMAT_STAND_I2S,
+        .intr_alloc_flags = 0,  // Default interrupt priority
+        .dma_buf_count = 8,
+        .dma_buf_len = 64,
+        .use_apll = false,
+        .tx_desc_auto_clear = true,
+        .fixed_mclk = 0
+    };
+
+    i2s_pin_config_t pin_config = {
+        .bck_io_num = BOARD_I2S_BCK,
+        .ws_io_num = BOARD_I2S_WS,
+        .data_out_num = BOARD_I2S_DOUT,
+        .data_in_num = I2S_PIN_NO_CHANGE
+    };
+
+    i2s_driver_install(BOARD_I2S_PORT, &i2s_config, 0, NULL);
+    i2s_set_pin(BOARD_I2S_PORT, &pin_config);
+    i2s_set_clk(BOARD_I2S_PORT, SAMPLE_RATE, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO);
+}
+
+
+void playTone(float frequency, int duration, int volume = 16383) {
+    volume = constrain(volume, 0, 32767); // Max volume is 32767, we default to half volume if not specified
+    const int wave_period = SAMPLE_RATE / frequency;
+    int16_t sample_buffer[wave_period];
+
+    for (int i = 0; i < wave_period; ++i)
+        sample_buffer[i] = (i < wave_period / 2) ? volume : -volume;
+
+    int total_samples = SAMPLE_RATE * duration / 1000;
+    int samples_written = 0;
+
+    while (samples_written < total_samples) {
+        int to_write = min(wave_period, total_samples - samples_written);
+        i2s_write(BOARD_I2S_PORT, sample_buffer, to_write * sizeof(int16_t), (size_t *)&to_write, portMAX_DELAY);
+        samples_written += to_write;
+    }
+}
+
+
+void playRTTTL(const char* rtttl, int volume = 16383, int bpm = -1) {
+    int default_duration = 4;
+    int default_octave = 6;
+    int internal_bpm = 63;
+
+    const char* p = rtttl;
+
+    // Skip name
+    while (*p && *p != ':') p++;
+    if (*p == ':') p++;
+
+    while (*p && *p != ':') {
+        char param = *p++;
+        if (*p == '=') p++;
+        int value = atoi(p);
+        while (*p && isdigit(*p)) p++;
+        if (*p == ',') p++;
+        switch (param) {
+            case 'd': default_duration = value; break;
+            case 'o': default_octave = value; break;
+            case 'b': internal_bpm = value; break;
+        }
+    }
+
+    if (*p == ':') p++;
+
+    if (bpm != -1)
+        internal_bpm = bpm;
+
+    int beat_duration = 60000 / internal_bpm;
+
+    while (*p) {
+        int duration = 0;
+        if (isdigit(*p)) {
+            duration = atoi(p);
+            while (isdigit(*p)) p++;
+        } else {
+            duration = default_duration;
+        }
+
+        char note = *p++;
+        int frequency = getNoteFrequency(note, default_octave);
+
+        if (*p == '#') {
+            frequency = getNoteFrequency(note + 1, default_octave);
+            p++;
+        }
+
+        int octave = default_octave;
+
+        if (isdigit(*p))
+            octave = *p++ - '0';
+
+        if (*p == '.') {
+            duration = duration * 1.5;
+            p++;
+        }
+
+        int note_duration = (beat_duration * 4) / duration;
+
+        if (frequency > 0)
+            playTone(frequency, note_duration, volume);
+        else
+            delay(note_duration);
+
+        if (*p == ',') p++;
+    }
+}
diff --git a/src/boot_screen.h b/src/bootScreen.h
diff --git a/src/main.ino b/src/main.ino
@@ -14,8 +14,9 @@
 #include <Wire.h>
 
 // Local includes
-#include "boot_screen.h"
+#include "bootScreen.h"
 #include "pins.h"
+#include "Speaker.h"
 
 
 // Constants
@@ -81,7 +82,6 @@ bool screenOn = true;
 int selectedNetworkIndex = 0;
 
 
-
 // Main functions ---------------------------------------------------------------------------------
 void displayXBM() {
     tft.fillScreen(TFT_BLACK);
@@ -113,6 +113,7 @@ void displayXBM() {
 void setup() {
     // Initialize serial communication
     Serial.begin(115200);
+    while (!Serial);
     Serial.println("Booting device...");
 
     // Turn on the power to the board
@@ -132,6 +133,11 @@ void setup() {
     tft.invertDisplay(1);
     Serial.println("TFT initialized");
 
+    // Initialize the speaker
+    setupI2S(); // Do we want to keep this open or uninstall after each use to keep resources free?
+    const char* rtttl_boot = "ff6_victory:d=4,o=5,b=100:32d6,32p,32d6,32p,32d6,32p,d6,a#,c6,16d6,8p,16c6,2d6"; // This will go in preferences soon
+    playRTTTL(rtttl_boot);
+
     // Display the boot screen
     displayXBM();
 
diff --git a/src/pins.h b/src/pins.h
@@ -4,9 +4,10 @@
 // Board pin definitions ------------------------
 #define BOARD_POWERON       10
 
+// Speaker
 #define BOARD_I2S_WS        5
-#define BOARD_I2S_BCK       7
 #define BOARD_I2S_DOUT      6
+#define BOARD_I2S_BCK       7
 
 #define BOARD_I2C_SDA       18
 #define BOARD_I2C_SCL       8
@@ -55,7 +56,6 @@
 
 // Battery definitions
 #define CONV_FACTOR 1.8 // Conversion factor for the ADC to voltage conversion
-#define READS 20        // Number of readings for averaging
-
-#define LILYGO_KB_SLAVE_ADDRESS 0x55
+#define READS       20  // Number of readings for averaging
 
+#define LILYGO_KB_SLAVE_ADDRESS 0x55
+\ No newline at end of file