summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Makefile13
-rw-r--r--README.md18
-rw-r--r--alsa.cpp114
-rw-r--r--media/click.s16lebin0 -> 3692 bytes
-rw-r--r--media/click.wavbin0 -> 3736 bytes
5 files changed, 145 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..eb05671
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,13 @@
+default: alsa
+
+CXXLIBS=$(shell pkg-config --libs alsa) -lreichwein -lfmt
+CXX=clang++
+
+alsa: alsa.cpp
+ $(CXX) $(CXXFLAGS) -std=c++20 -O2 -g -Wall -o $@ $^ $(CXXLIBS)
+
+clean:
+ rm -f alsa
+
+sound:
+ ffmpeg -i media/click.wav -f s16le media/click.s16le
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..fbf72d6
--- /dev/null
+++ b/README.md
@@ -0,0 +1,18 @@
+Click
+=====
+
+Hardware:
+- PC/Linux
+- Raspberry Pi 3 B
+- Microcontroller
+
+Features:
+- Input: MIDI
+- Output: Audio output
+ Options:
+ * Self generated click, self chosen tempo
+ * Click based on MIDI clock (24 clocks per quarter note during song)
+ * Click based on configurable MIDI note
+
+ch4
+c#1 drum map : stick
diff --git a/alsa.cpp b/alsa.cpp
new file mode 100644
index 0000000..7df0805
--- /dev/null
+++ b/alsa.cpp
@@ -0,0 +1,114 @@
+#include <libreichwein/file.h>
+
+#include <alsa/asoundlib.h>
+
+#include <cstdint>
+#include <cmath>
+#include <iostream>
+#include <limits>
+
+static const char *device = "default"; /* playback device */
+const snd_pcm_sframes_t nframes = 1024; // ~1/44th sec buffer size
+int16_t buffer[nframes]; /* some random data */
+const unsigned int f_sample = 44100;
+const double pi = std::acos(-1);
+
+class ClickStream
+{
+private:
+ std::vector<uint16_t> m_data;
+public:
+ ClickStream()
+ {
+ std::string data_s = Reichwein::File::getFile("media/click.s16le");
+ m_data.resize(data_s.size() / 2);
+ memcpy(m_data.data(), data_s.data(), data_s.size());
+ }
+
+double generate(double phase)
+{
+ int i;
+ size_t j = phase;
+
+ for (i = 0; i < nframes; i++) {
+ if (j >= m_data.size())
+ j = 0;
+ buffer[i] = m_data[j];
+ j++;
+ }
+
+ return j;
+}
+
+};
+
+class PCM
+{
+public:
+ PCM()
+ {
+ // non-blocking
+ if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
+ printf("Playback open error: %s\n", snd_strerror(err));
+ exit(EXIT_FAILURE);
+ }
+ if ((err = snd_pcm_set_params(handle,
+ SND_PCM_FORMAT_S16_LE,
+ SND_PCM_ACCESS_RW_INTERLEAVED,
+ 1,
+ f_sample,
+ 1,
+ 20000)) < 0) { /* 0.5sec */
+ printf("Playback open error: %s\n", snd_strerror(err));
+ exit(EXIT_FAILURE);
+ }
+
+ }
+
+ ~PCM()
+ {
+ /* pass the remaining samples, otherwise they're dropped in close */
+ err = snd_pcm_drain(handle);
+ if (err < 0)
+ printf("snd_pcm_drain failed: %s\n", snd_strerror(err));
+ snd_pcm_close(handle);
+ }
+
+ // write from buffer to ALSA PCM
+ bool write()
+ {
+ frames = snd_pcm_writei(handle, buffer, nframes);
+ if (frames < 0) {
+ std::cout << "Recovering." << std::endl;
+ frames = snd_pcm_recover(handle, frames, 0);
+ }
+ if (frames < 0) {
+ printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
+ return false;
+ }
+ if (frames > 0 && frames < nframes)
+ printf("Short write (expected %li, wrote %li)\n", nframes, frames);
+
+ return frames == 0;
+ }
+
+private:
+ int err;
+ snd_pcm_t *handle;
+ snd_pcm_sframes_t frames;
+};
+
+int main(void)
+{
+ PCM pcm;
+
+ double phase = 0;
+ ClickStream stream;
+ for (unsigned int i = 0; i < 50; i++) {
+ phase = stream.generate(phase);
+ pcm.write();
+ }
+
+ return 0;
+}
+
diff --git a/media/click.s16le b/media/click.s16le
new file mode 100644
index 0000000..409f077
--- /dev/null
+++ b/media/click.s16le
Binary files differ
diff --git a/media/click.wav b/media/click.wav
new file mode 100644
index 0000000..6e756b6
--- /dev/null
+++ b/media/click.wav
Binary files differ