diff options
author | Roland Reichwein <mail@reichwein.it> | 2025-01-02 13:14:08 +0100 |
---|---|---|
committer | Roland Reichwein <mail@reichwein.it> | 2025-01-02 13:14:08 +0100 |
commit | 083e46d5d23d2105e2df1adc769700fb579c9597 (patch) | |
tree | 27fb7fd49b4eb91f40eec561c566717f72cedd12 |
Initial commit
-rw-r--r-- | Makefile | 13 | ||||
-rw-r--r-- | README.md | 18 | ||||
-rw-r--r-- | alsa.cpp | 114 | ||||
-rw-r--r-- | media/click.s16le | bin | 0 -> 3692 bytes | |||
-rw-r--r-- | media/click.wav | bin | 0 -> 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 Binary files differnew file mode 100644 index 0000000..409f077 --- /dev/null +++ b/media/click.s16le diff --git a/media/click.wav b/media/click.wav Binary files differnew file mode 100644 index 0000000..6e756b6 --- /dev/null +++ b/media/click.wav |