@@ -4,6 +4,12 @@
#include <SDL2/SDL.h> // SDL2 standard functions
#include <SDL2/SDL2_gfxPrimitives.h> // SDL2 shapes and other handy abstractions.
// Include SDL's audio mixing components
#include <SDL2/SDL_mixer.h>
// Include a .h file containing the math for generating a frequency.
#include "tone.h"
#define SCREEN_W 1920/2
#define SCREEN_H 1080/2
@@ -16,6 +22,13 @@ SDL_Texture* sdlTexture;
uint32_t* pixels;
int running = 1;
// music, a pointer for all our SDL audio objects. My original idea
// was to set this pointer to NULL every time we need to load an audio
// file, but it may be cleaner to have a (make-audio name1 "file.wav")
// function from Scheme, which is callable with (play-audio name1) and
// (ause-audio name1).
Mix_Music *music = NULL;
typedef struct scheme_input {
uint32_t mouse_buttons;
int32_t mouse_x;
@@ -118,6 +131,51 @@ sexp get_key(sexp ctx, sexp self, sexp n) {
return sexp_make_integer(ctx, scheme_input.keycode);
}
////////////////////// BEGIN MAIN AUDIO CODE
// generate_tone, allows us to make a beep sound from Scheme, with:
// (generate-tone 440.0 0.5) ;;440Hz is the key of A, 0.5 seconds.
// Requires much more testing.
static sexp generate_tone(sexp ctx, sexp self, sexp n,
sexp sx_tone, sexp sx_duration) {
float tone = (float)sexp_flonum_value(sx_tone);
float duration = (float)sexp_flonum_value(sx_duration);
sdl_generate_tone(tone, duration);
return SEXP_TRUE;
}
// Load a WAV file. 'filename' is the wav file,
// loopp is a number specifying whether the audio
// should loop forever.
int sdl_play_wav_file(char* filename, int loopp) {
//INIT AUDIO
if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0) {
printf("Can't start SDL_mixer! %s\n", Mix_GetError());
return 1;
}
music = Mix_LoadMUS(filename);
Mix_PlayMusic(music, loopp);
if (music == NULL) {
printf("Can't start music! %s\n", Mix_GetError());
return 1;
}
return 0;
}
// The S-Expression version of sdl_play_wav_file,
// that we provide to Scheme.
sexp play_wav_file(sexp ctx, sexp self, sexp n,
sexp filename, sexp sx_loopp) {
uint32_t loopp = sexp_unbox_fixnum(sx_loopp);
char* filen = sexp_string_data(filename);
sdl_play_wav_file(filen, loopp);
return n;
}
////////////////////// END OF AUDIO SECTION
// 'provide', a shortcut for sexp_define_foreign.
void provide(sexp ctx, sexp env, char* name, int num_args, int return_type, void* func) {
sexp op = sexp_define_foreign(ctx, env, name, num_args, func);
@@ -144,21 +202,24 @@ void scheme_define_ops(sexp ctx, sexp env) {
provide(ctx, env, "mouse-y", 0, 1, (sexp_proc1)get_mouse_y);
provide(ctx, env, "mouse-buttons", 0, 1, (sexp_proc1)get_mouse_buttons);
provide(ctx, env, "keyboard", 0, 1, (sexp_proc1)get_key);
provide(ctx, env, "play-wav-file", 2, 0, (sexp_proc1)play_wav_file);
provide(ctx, env, "generate-tone", 2, 0, (sexp_proc1)generate_tone);
}
void scheme_loop(sexp ctx) {
// TODO: error handling
// TODO: record elapsed time and input events and pass to main function for animation stuff?
//sdl_pixel_put(20,20,0xffffff);
SDL_UpdateTexture(sdlTexture, NULL, pixels, SCREEN_W * sizeof(uint32_t));
SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);
// filledEllipseRGBA(sdlRenderer, 400, 400, 50, 80, 255, 50, 80, 255);
sexp_eval_string(ctx, "(main)", -1, NULL);
// evaluate the (main) function and print any errors
sexp res;
res = sexp_eval_string(ctx, "(main)", -1, NULL);
if (sexp_exceptionp(res)) {
sexp_print_exception(ctx, res, sexp_current_error_port(ctx));
}
SDL_RenderPresent(sdlRenderer);
// Simple framerate limiter, so Interscheme doesn't eat CPU power during tests.
// FIXME: this makes the actual processing too slow for me.
// FIXME: this makes the actual processing too slow for me (mntmn) .
// SDL_Delay(1000 / FPS);
}
@@ -166,7 +227,8 @@ int main(int argc, char** argv) {
sexp ctx;
SDL_Event event;
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
// Initialize the SDL video/audio components.
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) {
printf("Couldn't initialize SDL! %s\n", SDL_GetError());
return 1;
}
@@ -226,7 +288,7 @@ int main(int argc, char** argv) {
sexp_gc_var1(obj1);
sexp_gc_preserve1(ctx, obj1);
if (argc == 2) { // If the user specified a file
obj1 = sexp_c_string(ctx, argv[1], -1);
obj1 = sexp_c_string(ctx, argv[1], -1);
} else if (argc > 2) {
printf("Too many arguments!\n");
} else { // If 0 arguments, use the default file.
@@ -285,7 +347,7 @@ int main(int argc, char** argv) {
}
}
scheme_loop(ctx);
scheme_loop(ctx);
}
sexp_destroy_context(ctx);