Skip to content

Commit 19b642d

Browse files
committed
New test ALSA impl w/poll. Add goto key + conffile
Goto track key is return/enter. Config file currently only used to persist the volume. It's located at $XDG_CONFIG_HOME/minigbsrc (or ~/.config/minigbsrc if XDG_CONFIG_HOME is unset).
1 parent 6a5019f commit 19b642d

File tree

6 files changed

+254
-10066
lines changed

6 files changed

+254
-10066
lines changed

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
SRC := minigbs.c debug.c audio.c ui.c
22
CFLAGS := -g -O0 -D_GNU_SOURCE -std=gnu99
3-
LDFLAGS := -lncursesw -ltinfo -lm -ldl -lpthread
3+
LDFLAGS := -lncursesw -ltinfo -lm -lasound
44

5-
minigbs: $(SRC) minigbs.h mini_al.h
5+
minigbs: $(SRC) minigbs.h
66
$(CC) $(CFLAGS) $(SRC) -o $@ $(LDFLAGS)
77

88
clean:

audio.c

Lines changed: 79 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#include "minigbs.h"
2-
#define MAL_IMPLEMENTATION
3-
#include "mini_al.h"
2+
#include <alsa/asoundlib.h>
43
#include <math.h>
54

65
struct chan_len_ctr {
@@ -66,17 +65,19 @@ static struct chan {
6665
static size_t nsamples;
6766
static float* samples;
6867
static float* sample_ptr;
69-
70-
static mal_context audio_ctx;
71-
static mal_device audio;
72-
static mal_mutex audio_lock;
68+
static float* sample_end;
7369

7470
static const int duty_lookup[] = { 0x10, 0x30, 0x3C, 0xCF };
7571
static float logbase;
7672
static float charge_factor;
7773
static float vol_l, vol_r;
7874
static float audio_rate;
79-
static bool muted[4]; // not in chan struct to avoid memset(0) across tacks
75+
static bool muted[4]; // not in chan struct to avoid memset(0) across tracks
76+
static bool paused;
77+
78+
static snd_pcm_t* pcm;
79+
static snd_pcm_uframes_t pcm_buffer_size;
80+
static snd_pcm_uframes_t pcm_period_size;
8081

8182
float hipass(struct chan* c, float sample){
8283
float out = sample - c->capacitor;
@@ -300,105 +301,91 @@ bool audio_mute(int chan, int val){
300301
return muted[chan-1];
301302
}
302303

303-
void audio_update(void){
304-
memset(samples, 0, nsamples * sizeof(float));
305-
306-
update_square(0);
307-
update_square(1);
308-
update_wave();
309-
update_noise();
310-
311-
for(size_t i = 0; i < nsamples; ++i){
312-
samples[i] *= cfg.volume;
313-
}
314-
315-
sample_ptr = samples + nsamples;
316-
}
317-
318-
volatile int audio_active;
319-
320-
void audio_pause(bool p){
321-
audio_active = !p;
322-
eventfd_write(evfd_audio_ready, 1);
323-
}
324-
325304
void audio_reset(void){
326-
audio_pause(true);
327-
mal_mutex_lock(&audio_ctx, &audio_lock);
328-
329305
memset(chans, 0, sizeof(chans));
330306
memset(samples, 0, nsamples * sizeof(float));
331307
sample_ptr = samples;
308+
sample_end = samples + nsamples;
332309
chans[0].val = chans[1].val = -1;
333-
334-
mal_mutex_unlock(&audio_ctx, &audio_lock);
335-
audio_pause(false);
336310
}
337311

338-
static uint32_t audio_callback(mal_device* ptr, uint32_t len, void* data){
339-
uint32_t orig_len = len;
340-
uint32_t ret = 0;
341-
len *= 2;
312+
void audio_pause(bool p){
313+
paused = p;
314+
}
342315

343-
mal_mutex_lock(&audio_ctx, &audio_lock);
316+
int audio_init(struct pollfd** fds, int nfds){
317+
snd_pcm_open(&pcm, "default", SND_PCM_STREAM_PLAYBACK, 0);
318+
snd_pcm_set_params(pcm, SND_PCM_FORMAT_FLOAT, SND_PCM_ACCESS_RW_INTERLEAVED, 2, FREQ, 1, 16667);
319+
snd_pcm_get_params(pcm, &pcm_buffer_size, &pcm_period_size);
344320

345-
if(!audio_active)
346-
goto out;
321+
logbase = log(1.059463094f);
322+
charge_factor = pow(0.999958, 4194304.0 / FREQ);
347323

348-
do {
349-
if(sample_ptr - samples == 0){
350-
uint64_t val = 1;
324+
audio_update_rate();
351325

352-
eventfd_write(evfd_audio_request, val);
353-
TEMP_FAILURE_RETRY(eventfd_read(evfd_audio_ready, &val));
326+
int count = snd_pcm_poll_descriptors_count(pcm);
327+
*fds = realloc(*fds, (nfds + count) * sizeof(struct pollfd));
328+
snd_pcm_poll_descriptors(pcm, (*fds) + nfds, count);
354329

355-
if(!audio_active)
356-
goto out;
357-
}
330+
return nfds + count;
331+
}
358332

359-
int n = MIN(len, sample_ptr - samples);
360-
memcpy(data, samples, n * sizeof(float));
361-
memmove(samples, samples + n, (nsamples - n) * sizeof(float));
333+
void audio_quit(){
334+
snd_pcm_close(pcm);
335+
}
362336

363-
data += (n*4);
364-
sample_ptr -= n;
365-
len -= n;
366-
} while(len);
337+
void audio_update(struct pollfd* fds, int nfds){
338+
static float* buf = NULL;
339+
const size_t bufsz = (pcm_period_size*2) * sizeof(float);
367340

368-
ret = orig_len;
341+
if(!buf){
342+
buf = malloc(bufsz);
343+
}
369344

370-
out:
371-
mal_mutex_unlock(&audio_ctx, &audio_lock);
372-
return ret;
373-
}
345+
float* p = buf;
346+
float* end = buf + (bufsz/sizeof(float));
374347

375-
void audio_init(void){
348+
uint16_t ev;
349+
snd_pcm_poll_descriptors_revents(pcm, fds, nfds, &ev);
376350

377-
if(mal_context_init(NULL, 0, NULL, &audio_ctx) != MAL_SUCCESS){
378-
fprintf(stderr, "mal_context_init failed.\n");
379-
exit(1);
351+
if(!(ev & POLLOUT)){
352+
return;
380353
}
381354

382-
mal_device_config cfg = mal_device_config_init_playback(mal_format_f32, 2, FREQ, &audio_callback);
383-
if(mal_device_init(&audio_ctx, mal_device_type_playback, NULL, &cfg, NULL, &audio) != MAL_SUCCESS){
384-
fprintf(stderr, "mal_device_init failed.\n");
385-
exit(1);
355+
if(paused){
356+
memset(buf, 0, bufsz);
357+
goto out;
386358
}
387359

388-
if(mal_mutex_create(&audio_ctx, &audio_lock) == MAL_FALSE){
389-
fprintf(stderr, "mal_mutex_create failed.\n");
390-
exit(1);
391-
}
360+
while(end - p){
361+
if(sample_ptr == sample_end){
362+
cpu_frame();
392363

393-
logbase = log(1.059463094f);
394-
charge_factor = pow(0.999958, 4194304.0 / FREQ);
364+
memset(samples, 0, nsamples * sizeof(float));
395365

396-
mal_device_start(&audio);
397-
audio_update_rate();
398-
audio_pause(false);
399-
}
366+
update_square(0);
367+
update_square(1);
368+
update_wave();
369+
update_noise();
400370

401-
void audio_quit(void){
371+
for(size_t i = 0; i < nsamples; ++i){
372+
samples[i] *= cfg.volume;
373+
}
374+
375+
sample_ptr = samples;
376+
}
377+
378+
int n = MIN(end - p, sample_end - sample_ptr);
379+
memcpy(p, sample_ptr, n * sizeof(float));
380+
sample_ptr += n;
381+
p += n;
382+
}
383+
384+
out:;
385+
int err = snd_pcm_writei(pcm, buf, pcm_period_size);
386+
if(err < 0){
387+
snd_pcm_recover(pcm, err, 1);
388+
}
402389
}
403390

404391
void audio_get_notes(uint16_t notes[static 4]){
@@ -448,16 +435,20 @@ void audio_update_rate(void){
448435
printf("Audio rate changed: %.4f\n", audio_rate);
449436
}
450437

451-
audio_pause(true);
452-
mal_mutex_lock(&audio_ctx, &audio_lock);
438+
size_t new_nsamples = (int)(FREQ / audio_rate) * 2;
439+
float* new_samples = calloc(new_nsamples, sizeof(float));
440+
441+
if(samples){
442+
memcpy(new_samples, samples, MIN(nsamples, new_nsamples));
443+
}
453444

454445
free(samples);
455-
nsamples = (int)(FREQ / audio_rate) * 2;
456-
samples = calloc(nsamples, sizeof(float));
457-
sample_ptr = samples;
446+
samples = new_samples;
447+
nsamples = new_nsamples;
458448

459-
mal_mutex_unlock(&audio_ctx, &audio_lock);
460-
audio_pause(false);
449+
// TODO: these should really be adjusted more accurately to not lose samples on speed change
450+
sample_ptr = samples;
451+
sample_end = samples + nsamples;
461452
}
462453

463454
void chan_trigger(int i){

0 commit comments

Comments
 (0)