summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/SDL2/Xcode-iOS/Demos/src/mixer.c
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/SDL2/Xcode-iOS/Demos/src/mixer.c')
-rw-r--r--3rdparty/SDL2/Xcode-iOS/Demos/src/mixer.c353
1 files changed, 353 insertions, 0 deletions
diff --git a/3rdparty/SDL2/Xcode-iOS/Demos/src/mixer.c b/3rdparty/SDL2/Xcode-iOS/Demos/src/mixer.c
new file mode 100644
index 00000000000..bd0cfb1dffc
--- /dev/null
+++ b/3rdparty/SDL2/Xcode-iOS/Demos/src/mixer.c
@@ -0,0 +1,353 @@
+/*
+ * mixer.c
+ * written by Holmes Futrell
+ * use however you want
+ */
+
+#import "SDL.h"
+#import "common.h"
+
+#define NUM_CHANNELS 8 /* max number of sounds we can play at once */
+#define NUM_DRUMS 4 /* number of drums in our set */
+#define MILLESECONDS_PER_FRAME 16 /* about 60 frames per second */
+
+static struct
+{
+ SDL_Rect rect; /* where the button is drawn */
+ SDL_Color upColor; /* color when button is not active */
+ SDL_Color downColor; /* color when button is active */
+ int isPressed; /* is the button being pressed ? */
+ int touchIndex; /* what mouse (touch) index pressed the button ? */
+} buttons[NUM_DRUMS];
+
+struct sound
+{
+ Uint8 *buffer; /* audio buffer for sound file */
+ Uint32 length; /* length of the buffer (in bytes) */
+};
+
+/* this array holds the audio for the drum noises */
+static struct sound drums[NUM_DRUMS];
+
+/* function declarations */
+void handleMouseButtonDown(SDL_Event * event);
+void handleMouseButtonUp(SDL_Event * event);
+int playSound(struct sound *);
+void initializeButtons();
+void audioCallback(void *userdata, Uint8 * stream, int len);
+void loadSound(const char *file, struct sound *s);
+
+struct
+{
+ /* channel array holds information about currently playing sounds */
+ struct
+ {
+ Uint8 *position; /* what is the current position in the buffer of this sound ? */
+ Uint32 remaining; /* how many bytes remaining before we're done playing the sound ? */
+ Uint32 timestamp; /* when did this sound start playing ? */
+ } channels[NUM_CHANNELS];
+ SDL_AudioSpec outputSpec; /* what audio format are we using for output? */
+ int numSoundsPlaying; /* how many sounds are currently playing */
+} mixer;
+
+/* sets up the buttons (color, position, state) */
+void
+initializeButtons()
+{
+
+ int i;
+ int spacing = 10; /* gap between drum buttons */
+ SDL_Rect buttonRect; /* keeps track of where to position drum */
+ SDL_Color upColor = { 86, 86, 140, 255 }; /* color of drum when not pressed */
+ SDL_Color downColor = { 191, 191, 221, 255 }; /* color of drum when pressed */
+
+ buttonRect.x = spacing;
+ buttonRect.y = spacing;
+ buttonRect.w = SCREEN_WIDTH - 2 * spacing;
+ buttonRect.h = (SCREEN_HEIGHT - (NUM_DRUMS + 1) * spacing) / NUM_DRUMS;
+
+ /* setup each button */
+ for (i = 0; i < NUM_DRUMS; i++) {
+
+ buttons[i].rect = buttonRect;
+ buttons[i].isPressed = 0;
+ buttons[i].upColor = upColor;
+ buttons[i].downColor = downColor;
+
+ buttonRect.y += spacing + buttonRect.h; /* setup y coordinate for next drum */
+
+ }
+}
+
+/*
+ loads a wav file (stored in 'file'), converts it to the mixer's output format,
+ and stores the resulting buffer and length in the sound structure
+ */
+void
+loadSound(const char *file, struct sound *s)
+{
+ SDL_AudioSpec spec; /* the audio format of the .wav file */
+ SDL_AudioCVT cvt; /* used to convert .wav to output format when formats differ */
+ int result;
+ if (SDL_LoadWAV(file, &spec, &s->buffer, &s->length) == NULL) {
+ fatalError("could not load .wav");
+ }
+ /* build the audio converter */
+ result = SDL_BuildAudioCVT(&cvt, spec.format, spec.channels, spec.freq,
+ mixer.outputSpec.format,
+ mixer.outputSpec.channels,
+ mixer.outputSpec.freq);
+ if (result == -1) {
+ fatalError("could not build audio CVT");
+ } else if (result != 0) {
+ /*
+ this happens when the .wav format differs from the output format.
+ we convert the .wav buffer here
+ */
+ cvt.buf = (Uint8 *) SDL_malloc(s->length * cvt.len_mult); /* allocate conversion buffer */
+ cvt.len = s->length; /* set conversion buffer length */
+ SDL_memcpy(cvt.buf, s->buffer, s->length); /* copy sound to conversion buffer */
+ if (SDL_ConvertAudio(&cvt) == -1) { /* convert the sound */
+ fatalError("could not convert .wav");
+ }
+ SDL_free(s->buffer); /* free the original (unconverted) buffer */
+ s->buffer = cvt.buf; /* point sound buffer to converted buffer */
+ s->length = cvt.len_cvt; /* set sound buffer's new length */
+ }
+}
+
+/* called from main event loop */
+void
+handleMouseButtonDown(SDL_Event * event)
+{
+
+ int x, y, mouseIndex, i, drumIndex;
+
+ mouseIndex = 0;
+ drumIndex = -1;
+
+ SDL_GetMouseState(&x, &y);
+ /* check if we hit any of the drum buttons */
+ for (i = 0; i < NUM_DRUMS; i++) {
+ if (x >= buttons[i].rect.x
+ && x < buttons[i].rect.x + buttons[i].rect.w
+ && y >= buttons[i].rect.y
+ && y < buttons[i].rect.y + buttons[i].rect.h) {
+ drumIndex = i;
+ break;
+ }
+ }
+ if (drumIndex != -1) {
+ /* if we hit a button */
+ buttons[drumIndex].touchIndex = mouseIndex;
+ buttons[drumIndex].isPressed = 1;
+ playSound(&drums[drumIndex]);
+ }
+
+}
+
+/* called from main event loop */
+void
+handleMouseButtonUp(SDL_Event * event)
+{
+ int i;
+ int mouseIndex = 0;
+ /* check if this should cause any of the buttons to become unpressed */
+ for (i = 0; i < NUM_DRUMS; i++) {
+ if (buttons[i].touchIndex == mouseIndex) {
+ buttons[i].isPressed = 0;
+ }
+ }
+}
+
+/* draws buttons to screen */
+void
+render(SDL_Renderer *renderer)
+{
+ int i;
+ SDL_SetRenderDrawColor(renderer, 50, 50, 50, 255);
+ SDL_RenderClear(renderer); /* draw background (gray) */
+ /* draw the drum buttons */
+ for (i = 0; i < NUM_DRUMS; i++) {
+ SDL_Color color =
+ buttons[i].isPressed ? buttons[i].downColor : buttons[i].upColor;
+ SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
+ SDL_RenderFillRect(renderer, &buttons[i].rect);
+ }
+ /* update the screen */
+ SDL_RenderPresent(renderer);
+}
+
+/*
+ finds a sound channel in the mixer for a sound
+ and sets it up to start playing
+*/
+int
+playSound(struct sound *s)
+{
+ /*
+ find an empty channel to play on.
+ if no channel is available, use oldest channel
+ */
+ int i;
+ int selected_channel = -1;
+ int oldest_channel = 0;
+
+ if (mixer.numSoundsPlaying == 0) {
+ /* we're playing a sound now, so start audio callback back up */
+ SDL_PauseAudio(0);
+ }
+
+ /* find a sound channel to play the sound on */
+ for (i = 0; i < NUM_CHANNELS; i++) {
+ if (mixer.channels[i].position == NULL) {
+ /* if no sound on this channel, select it */
+ selected_channel = i;
+ break;
+ }
+ /* if this channel's sound is older than the oldest so far, set it to oldest */
+ if (mixer.channels[i].timestamp <
+ mixer.channels[oldest_channel].timestamp)
+ oldest_channel = i;
+ }
+
+ /* no empty channels, take the oldest one */
+ if (selected_channel == -1)
+ selected_channel = oldest_channel;
+ else
+ mixer.numSoundsPlaying++;
+
+ /* point channel data to wav data */
+ mixer.channels[selected_channel].position = s->buffer;
+ mixer.channels[selected_channel].remaining = s->length;
+ mixer.channels[selected_channel].timestamp = SDL_GetTicks();
+
+ return selected_channel;
+}
+
+/*
+ Called from SDL's audio system. Supplies sound input with data by mixing together all
+ currently playing sound effects.
+*/
+void
+audioCallback(void *userdata, Uint8 * stream, int len)
+{
+ int i;
+ int copy_amt;
+ SDL_memset(stream, mixer.outputSpec.silence, len); /* initialize buffer to silence */
+ /* for each channel, mix in whatever is playing on that channel */
+ for (i = 0; i < NUM_CHANNELS; i++) {
+ if (mixer.channels[i].position == NULL) {
+ /* if no sound is playing on this channel */
+ continue; /* nothing to do for this channel */
+ }
+
+ /* copy len bytes to the buffer, unless we have fewer than len bytes remaining */
+ copy_amt =
+ mixer.channels[i].remaining <
+ len ? mixer.channels[i].remaining : len;
+
+ /* mix this sound effect with the output */
+ SDL_MixAudioFormat(stream, mixer.channels[i].position,
+ mixer.outputSpec.format, copy_amt, 150);
+
+ /* update buffer position in sound effect and the number of bytes left */
+ mixer.channels[i].position += copy_amt;
+ mixer.channels[i].remaining -= copy_amt;
+
+ /* did we finish playing the sound effect ? */
+ if (mixer.channels[i].remaining == 0) {
+ mixer.channels[i].position = NULL; /* indicates no sound playing on channel anymore */
+ mixer.numSoundsPlaying--;
+ if (mixer.numSoundsPlaying == 0) {
+ /* if no sounds left playing, pause audio callback */
+ SDL_PauseAudio(1);
+ }
+ }
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+
+ int done; /* has user tried to quit ? */
+ SDL_Window *window; /* main window */
+ SDL_Renderer *renderer;
+ SDL_Event event;
+ Uint32 startFrame; /* holds when frame started processing */
+ Uint32 endFrame; /* holds when frame ended processing */
+ Uint32 delay; /* calculated delay, how long should we wait before next frame? */
+
+ if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) {
+ fatalError("could not initialize SDL");
+ }
+ window =
+ SDL_CreateWindow(NULL, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,
+ SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS);
+ renderer = SDL_CreateRenderer(window, 0, 0);
+
+ /* initialize the mixer */
+ SDL_memset(&mixer, 0, sizeof(mixer));
+ /* setup output format */
+ mixer.outputSpec.freq = 44100;
+ mixer.outputSpec.format = AUDIO_S16LSB;
+ mixer.outputSpec.channels = 2;
+ mixer.outputSpec.samples = 256;
+ mixer.outputSpec.callback = audioCallback;
+ mixer.outputSpec.userdata = NULL;
+
+ /* open audio for output */
+ if (SDL_OpenAudio(&mixer.outputSpec, NULL) != 0) {
+ fatalError("Opening audio failed");
+ }
+
+ /* load our drum noises */
+ loadSound("ds_kick_big_amb.wav", &drums[3]);
+ loadSound("ds_brush_snare.wav", &drums[2]);
+ loadSound("ds_loose_skin_mute.wav", &drums[1]);
+ loadSound("ds_china.wav", &drums[0]);
+
+ /* setup positions, colors, and state of buttons */
+ initializeButtons();
+
+ /* enter main loop */
+ done = 0;
+ while (!done) {
+ startFrame = SDL_GetTicks();
+ while (SDL_PollEvent(&event)) {
+ switch (event.type) {
+ case SDL_MOUSEBUTTONDOWN:
+ handleMouseButtonDown(&event);
+ break;
+ case SDL_MOUSEBUTTONUP:
+ handleMouseButtonUp(&event);
+ break;
+ case SDL_QUIT:
+ done = 1;
+ break;
+ }
+ }
+ render(renderer); /* draw buttons */
+ endFrame = SDL_GetTicks();
+
+ /* figure out how much time we have left, and then sleep */
+ delay = MILLESECONDS_PER_FRAME - (endFrame - startFrame);
+ if (delay < 0) {
+ delay = 0;
+ } else if (delay > MILLESECONDS_PER_FRAME) {
+ delay = MILLESECONDS_PER_FRAME;
+ }
+ SDL_Delay(delay);
+ }
+
+ /* cleanup code, let's free up those sound buffers */
+ int i;
+ for (i = 0; i < NUM_DRUMS; i++) {
+ SDL_free(drums[i].buffer);
+ }
+ /* let SDL do its exit code */
+ SDL_Quit();
+
+ return 0;
+}