Created
January 27, 2023 08:08
-
-
Save hatkidchan/43f752205cd4dbe3ac89494c8c3e5fb1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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