2

I am trying to embed Chicken Scheme into a C program, to generate sounds to be played with SDL2's audio system. I would have liked to use the sdl2 egg, but it does not seem to support Audio yet (despite the documentation mentioning the 'audio flag for the init! function).

At first, I was using SDL_QueueAudio from C, passing it a buffer that I had allocated in C and then filled in Scheme. This worked fine, passing a Sint16 * and size_t into Scheme, then using pointer-s16-set! from Scheme to fill it and returning a size_t to note how many cells were filled.

Then, when I realised that using the callback api for generating the audio was much better suited to this, I tried switching to it (having already used it before in C), only for the Scheme function to never be entered. Logging something in the callback function before the Scheme call worked, but logging directly within the Scheme function, or after the Scheme call, never happened.

I can only imagine that this is due to SDL2's audio callback running on a separate thread, and that messing with calling through to Scheme somehow. With this in mind, I tried calling CHICKEN_run(C_toplevel); from within the callback function, the first time that it was called, but that only resulted in a bus error.

So my question is: is there a way of calling embedded Chicken Scheme from SDL2's audio callback?

I am on macOs 10.13.6 High Sierra, with SDL2 and chicken both installed and up-to-date through Homebrew.

I compile with (as I said, this works fine when using the queue audio api):

csc code.c codescm.scm -embedded -o code -L -lSDL2

My simplified code is below:

#include <chicken.h>
#include "SDL2/SDL.h"

extern size_t fill_sound_buffer(Sint16 *buffer, size_t buffer_length);

void fill_sound_callback(void *user_data, Uint8 *stream, int stream_length)
{
    // Logging here prints to the console
    fill_sound_buffer((Sint16 *)stream, stream_length / 2);
    // Logging here does not print to the console
}

void play(void)
{
    SDL_AudioSpec audio_want;
    SDL_zero(audio_want);
    audio_want.freq = 44100;
    audio_want.format = AUDIO_S16SYS;
    audio_want.channels = 1;
    audio_want.samples = 2048;
    audio_want.callback = fill_sound_callback;

    SDL_AudioSpec audio_have;
    SDL_AudioDeviceID audio_device = SDL_OpenAudioDevice(NULL, 0, &audio_want, &audio_have, 0);

    SDL_PauseAudioDevice(audio_device, 0);
    SDL_Delay(5000);
    // Logging here shows up after 5 seconds, but the program then continues to wait
    SDL_CloseAudioDevice(audio_device);
}

int main(int argc, char *argv[])
{
    SDL_Init(SDL_INIT_AUDIO);
    CHICKEN_run(C_toplevel);
    play();
    SDL_Quit();
    return 0;
}
(import (chicken format)
        (chicken foreign)
        (chicken memory)
        (chicken platform))

(define-external (fill_sound_buffer ((c-pointer short) buffer) (size_t buffer_length)) size_t
 ; This never prints when using the callback api
 (printf "In Scheme~%")
 ; Removed the code that calculates a sine wave and fills the buffer with it, which works
 0)

(return-to-host)
Billy Brown
  • 2,272
  • 23
  • 25
  • 1
    Unlikely. You can e.g. make event loop and launch custom event from callback, then wait for your main loop to process event, issue script call, and signal you back via semaphore, but that would probably result in sound stuttering. Queueing seems much easier way. – keltar Jul 04 '20 at 13:26
  • 2
    Here's a blog post showing how the doodle egg solved this for SDL1: http://pestilenz.org/~ckeen/blog/posts/callbacks.html – wasamasa Jul 05 '20 at 06:02
  • Both solutions look quite similar: in the C callback, send some form of event (SDL or message on a pipe) to notify that Scheme can fill the buffer, and then somehow notify the C callback that the buffer has been filled. Two pipes (for C -> Scheme and Scheme -> C) might work best, but I might just go with queuing the audio as long as that works. – Billy Brown Jul 06 '20 at 07:29
  • Slightly related - I've been fiddling with the SDL audio stuff and have a trivial egg I've been putting together. Just the scheme->C stuff I'm afraid though, no callbacks – Richard Huxton Jul 06 '20 at 08:15

0 Answers0