Commits

Anonymous committed af041ef

initial import

Comments (0)

Files changed (5)

+\.o
+\.cmxa
+\.cmi
+\.cmx
+\.swo
+\.swp
+.DS_Store
+_build
+module Sample = struct
+  type t
+  external load : string -> t = "sdl_load_wav"
+  external set_volume : t -> int -> unit = "sdl_set_wav_volume"
+end
+
+external init : unit -> unit = "sdl_init"
+external allocate_channels : int -> unit = "sdl_allocate_channels"
+external set_volume : int -> int -> unit = "sdl_set_channel_volume"
+external play_channel_raw : int -> Sample.t -> int -> unit = "sdl_play_channel"
+external play_channel_fade_in_raw : int -> Sample.t -> int -> int -> unit =
+  "sdl_play_channel_fade_in"
+
+let play channel ?(repeat=0) sample = play_channel_raw channel sample repeat
+
+let play_fade_in channel ?(repeat=0) sample fade_ms =
+  play_channel_fade_in_raw channel sample repeat fade_ms
+;;
+
+let () =
+  init ();
+  allocate_channels 16;
+  let sample1 = Sample.load "foo.wav" in
+  let sample2 = Sample.load "foo.wav" in
+  let sample3 = Sample.load "foo.wav" in
+  let sample4 = Sample.load "foo.wav" in
+  play 1 ~repeat:5 sample1;
+  play 2 ~repeat:5 sample2;
+  play 3 ~repeat:5 sample3;
+  play 4 ~repeat:5 sample4;
+module Sample : sig
+  type t
+
+  val load : string -> t
+  val set_volume : t -> int -> unit
+end
+
+val init : unit -> unit
+
+(* [allocate_channels num] allocates num channels for mixing *)
+val allocate_channels : int -> unit
+
+(* [set_volume channnel volume] sets the volume of the given channel.
+ * Valid volumes range from 0 to 128 inclusive. *)
+val set_volume : int -> int -> unit
+
+val play : int -> ?repeat:int -> Sample.t -> unit
+val play_fade_in : int -> ?repeat:int -> Sample.t -> int -> unit
+
+#!/bin/sh
+
+ocamlopt -c -I /opt/local/include/SDL sdl_stubs.c 
+ocamlopt -o chirp -cclib "$(sdl-config --libs)" -cclib -lSDL_mixer chirp.mli chirp.ml sdl_stubs.o 
+#include <string.h>
+#include <caml/mlvalues.h>
+#include <caml/memory.h>
+#include <caml/alloc.h>
+#include <caml/custom.h>
+#include <caml/fail.h>
+
+#include <SDL.h>
+#include <SDL_mixer.h>
+
+// raise an OCaml exception with the current SDL_mixer error
+void sdl_failwith_current_error(char *caller)
+{
+  char *mix_err = Mix_GetError();
+  char final_str[strlen(mix_err) + strlen(caller) + 4];
+
+  sprintf(final_str, "%s - %s", caller, Mix_GetError());
+  caml_failwith(final_str);
+}
+
+// initialize SDL for audio and the SDL_mixer library
+value sdl_init(value unit)
+{
+  CAMLparam1(unit);
+
+  // start SDL with audio support
+  if(SDL_Init(SDL_INIT_AUDIO) < 0) {
+    char *sdl_err = SDL_GetError();
+    char err_str[19 + strlen(sdl_err)];
+    sprintf(err_str, "SDL_Init failed - %s", sdl_err);
+    caml_failwith(err_str);
+  }
+  
+  // open 44.1KHz, signed 16bit, system byte order,
+  // stereo audio, using 1024 byte chunks
+  if(Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024) < 0) {
+    sdl_failwith_current_error("sdl_init");
+  }
+  CAMLreturn(Val_unit);
+}
+
+// free a sample allocated with sdl_load_wav. 
+// This function does not use CAMLparam or CAMLreturn because it 
+// does not allocate (allocation is forbidden in finalizers called
+// from C Custom_blocks)
+void sdl_free_wav(value caml_wav)
+{
+  Mix_Chunk *sample;
+
+  sample = (Mix_Chunk *)Field(caml_wav, 0);
+  Mix_FreeChunk(sample);
+  sample = NULL;
+}
+
+static struct custom_operations wav_custom_ops = {
+  "sdl_sound",
+  sdl_free_wav,
+  custom_compare_default,
+  custom_hash_default,
+  custom_serialize_default,
+  custom_deserialize_default
+};
+
+// CR: really don't understand this nest of pointers...
+#define Val_wav(v) (*(Mix_Chunk **) Data_custom_val(v))
+
+value sdl_load_wav(value caml_filename)
+{
+  CAMLparam1(caml_filename);
+  char *filename = String_val(caml_filename);
+  Mix_Chunk *sample = Mix_LoadWAV(filename);
+
+  if(!sample) sdl_failwith_current_error("sdl_load_wav");
+
+  CAMLlocal1(v);
+  v = caml_alloc_custom(&wav_custom_ops, sizeof(sample), 0, 1);
+  Val_wav(v) = sample;
+
+  CAMLreturn(v);
+}
+
+value sdl_set_wav_volume(value wav, value caml_volume)
+{
+  CAMLparam2(wav, caml_volume);
+  Mix_Chunk *sample = Val_wav(wav);
+  int volume = Val_int(caml_volume);
+
+  Mix_VolumeChunk(sample, volume);
+
+  CAMLreturn(Val_unit);
+}
+
+value sdl_allocate_channels(value caml_num_channels)
+{
+  CAMLparam1(caml_num_channels);
+  Mix_AllocateChannels(Val_int(caml_num_channels));
+  CAMLreturn(Val_unit);
+}
+
+value sdl_set_channel_volume(value caml_channel, value caml_volume)
+{
+  CAMLparam2(caml_channel, caml_volume);
+  // documentation doesn't say that this will ever return < 0, but since
+  // it returns the current volume of the channel, it should never be < 0
+  if(Mix_Volume(Val_int(caml_channel), Val_int(caml_volume)) < 0)
+    sdl_failwith_current_error("sdl_set_channel_volume");
+  CAMLreturn(Val_unit);
+}
+
+value sdl_play_channel(value caml_channel, value wav, value caml_repeat)
+{
+  CAMLparam3(caml_channel, wav, caml_repeat);
+  int channel = Val_int(caml_channel);
+  Mix_Chunk *sample = Val_wav(wav);
+  int repeat = Val_int(caml_repeat);
+
+  if(Mix_PlayChannel(channel, sample, repeat) < 0)
+    sdl_failwith_current_error("sdl_play_channel");
+
+  CAMLreturn(Val_unit);
+}
+
+value sdl_play_channel_fade_in(
+    value caml_channel, 
+    value wav, 
+    value caml_repeat,
+    value caml_fade_in)
+{
+  CAMLparam4(caml_channel, wav, caml_repeat, caml_fade_in);
+  int channel = Val_int(caml_channel);
+  Mix_Chunk *sample = Val_wav(wav);
+  int repeat = Val_int(caml_repeat);
+  int fade_in = Val_int(caml_fade_in);
+
+  if(Mix_FadeInChannel(channel, sample, repeat, fade_in) < 0)
+    sdl_failwith_current_error("sdl_play_channel_fade_in");
+
+  CAMLreturn(Val_unit);
+}
+
+