Skip to content

Instantly share code, notes, and snippets.

@hatkidchan
Created January 27, 2023 08:08
Show Gist options
  • Save hatkidchan/43f752205cd4dbe3ac89494c8c3e5fb1 to your computer and use it in GitHub Desktop.
Save hatkidchan/43f752205cd4dbe3ac89494c8c3e5fb1 to your computer and use it in GitHub Desktop.
// x-run: tcc -lasound -lm -run % -r 600 988 1 1319 4
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <alsa/asoundlib.h>
#include <sys/types.h>
#include <math.h>
enum {
FORM_SINE, FORM_TRIANGLE, FORM_SAW, FORM_SQUARE
};
snd_pcm_t *alsa_handle;
u_int8_t buffer[4096];
int sample_offset = 0;
bool open_alsa(const char *device);
void write_partial(u_int8_t *buffer, int n);
u_int8_t mksound(double phase, int waveform);
int main(int argc, char **argv) {
int ticks_per_minute = 0;
int waveform = FORM_SINE;
if (!open_alsa("default")) {
return 1;
}
printf("alsa: %p\n", alsa_handle);
char **arg = &argv[1];
u_int8_t buffer_tmp[4096];
double phase = 0.0;
while (*arg) {
if (!strcmp(*arg, "-s")) waveform = FORM_SINE;
else if (!strcmp(*arg, "-t")) waveform = FORM_TRIANGLE;
else if (!strcmp(*arg, "-w")) waveform = FORM_SAW;
else if (!strcmp(*arg, "-r")) waveform = FORM_SQUARE;
else {
int v = atoi(*arg);
if (ticks_per_minute == 0) {
ticks_per_minute = v;
} else {
int frequency = v;
int ticks = atoi(*++arg);
int samples = ticks * 44100 * 60 / ticks_per_minute;
for (int t = 0; t < samples; t++) {
buffer_tmp[t % 4096] = mksound(phase, waveform);
phase += M_PI * 2. * frequency / 44100.0;
if ((t % 4096) == 4095) {
write_partial(buffer_tmp, 4096);
}
}
write_partial(buffer_tmp, samples % 4096);
}
}
arg++;
}
memset(buffer_tmp, 0x80, 4096);
write_partial(buffer_tmp, 4096);
write_partial(buffer_tmp, 4096);
return 0;
}
bool open_alsa(const char *device) {
int err;
if ((err = snd_pcm_open(&alsa_handle,
device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
printf("snd_pcm_open() failed: %s\n", snd_strerror(err));
return false;
}
/*snd_pcm_hw_params_t *hwparams;*/
/*snd_pcm_hw_params_malloc(&hwparams);*/
/*snd_pcm_hw_params_any(alsa_handle, hwparams);*/
/*snd_pcm_hw_params_set_access(*/
if ((err = snd_pcm_set_params(alsa_handle, SND_PCM_FORMAT_U8,
SND_PCM_ACCESS_RW_INTERLEAVED, 1, 44100, 1, 100000)) < 0) {
printf("snd_pcm_set_params() failed: %s\n", snd_strerror(err));
return false;
}
return true;
}
u_int8_t mksound(double phase, int waveform) {
switch (waveform) {
case FORM_SINE: return sin(phase) * 64 + 128;
case FORM_SQUARE: return sin(phase) > 0 ? 192 : 64;
case FORM_TRIANGLE: return asin(sin(phase)) * 64 + 128;
case FORM_SAW: return (phase - floor(phase) - 0.5) * 256 + 128;
}
return rand() & 0xff;
}
void write_partial(u_int8_t *in_buf, int n) {
for (int i = 0; i < n; i++, sample_offset++) {
buffer[sample_offset % 4096] = in_buf[i];
if ((sample_offset % 4096) == 4095) {
printf("submit at %d\n", sample_offset);
snd_pcm_sframes_t f = snd_pcm_writei(alsa_handle, buffer, 4096);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment