From 4c49c5b6a3c18db8d9062feb86286b3578a35bd0 Mon Sep 17 00:00:00 2001
From: Stephen Crane <jscrane@gmail.com>
Date: Thu, 6 Sep 2018 09:18:23 +0100
Subject: [PATCH] initial sound infrastructure

---
 r65emu.h  |  1 +
 sound.cpp | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 sound.h   | 10 +++++++++
 3 files changed, 78 insertions(+)
 create mode 100644 sound.cpp
 create mode 100644 sound.h

diff --git a/r65emu.h b/r65emu.h
index 7f53c3c..83c98a7 100644
--- a/r65emu.h
+++ b/r65emu.h
@@ -13,5 +13,6 @@
 #include "timed.h"
 #include "hardware.h"
 #include "checkpoint.h"
+#include "sound.h"
 
 #endif
diff --git a/sound.cpp b/sound.cpp
new file mode 100644
index 0000000..36c0a80
--- /dev/null
+++ b/sound.cpp
@@ -0,0 +1,67 @@
+#include <Arduino.h>
+#include <hardware.h>
+#include "timed.h"
+#include "sound.h"
+
+#if defined(DAC_SOUND) && defined(ESP_PLATFORM)
+#include <driver/dac.h>
+
+static portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
+
+static dac_channel_t channel;
+
+static volatile const uint8_t *_bytes;
+static volatile unsigned _size, _off;
+static hw_timer_t *timer;
+
+void IRAM_ATTR timer_callback() {
+	portENTER_CRITICAL_ISR(&mux);
+
+	if (_off < _size)
+		dac_output_voltage(channel, _bytes[_off++]);
+	else {
+		_bytes = 0;
+		dac_output_disable(channel);
+		timerAlarmDisable(timer);
+	}
+
+	portEXIT_CRITICAL_ISR(&mux);
+}
+
+void Sound::begin(unsigned pin, unsigned freq) {
+	if (pin == 25)
+		channel = DAC_CHANNEL_1;
+	else if (pin == 26)
+		channel = DAC_CHANNEL_2;
+
+	timer = timerBegin(1, 80, true);
+	timerAttachInterrupt(timer, &timer_callback, true);
+	timerAlarmWrite(timer, 1000000 / freq, true);
+}
+
+const uint8_t *Sound::play(const uint8_t *bytes, unsigned size) {
+	portENTER_CRITICAL_ISR(&mux);
+
+	const uint8_t *play = (const uint8_t *)_bytes;
+	if (_off == _size) {
+		_bytes = bytes;
+		_size = size;
+		_off = 0;
+		dac_output_enable(channel);
+		timerAlarmEnable(timer);
+		play = bytes;
+	}
+
+	portEXIT_CRITICAL_ISR(&mux);
+	return play;
+}
+
+#else
+// does nothing by default
+void Sound::begin(unsigned channel, unsigned freq) {
+}
+
+const uint8_t *Sound::play(const uint8_t *bytes, unsigned size) {
+	return 0;
+}
+#endif
diff --git a/sound.h b/sound.h
new file mode 100644
index 0000000..a3a6ed5
--- /dev/null
+++ b/sound.h
@@ -0,0 +1,10 @@
+#ifndef __SOUND_H__
+#define __SOUND_H__
+
+class Sound {
+public:
+	void begin(unsigned pin, unsigned freq);
+	const uint8_t *play(const uint8_t *bytes, unsigned size);
+};
+
+#endif