SDL  2.0
mixer.c File Reference
#include "SDL.h"
#include "common.h"
+ Include dependency graph for mixer.c:

Go to the source code of this file.

Data Structures

struct  sound
 

Macros

#define NUM_CHANNELS   8 /* max number of sounds we can play at once */
 
#define NUM_DRUMS   4 /* number of drums in our set */
 

Functions

void handleMouseButtonDown (SDL_Event *event)
 
void handleMouseButtonUp (SDL_Event *event)
 
int playSound (struct sound *)
 
void initializeButtons (SDL_Renderer *)
 
void audioCallback (void *userdata, Uint8 *stream, int len)
 
void loadSound (const char *file, struct sound *s)
 
void render (SDL_Renderer *renderer)
 
int main (int argc, char *argv[])
 

Variables

struct {
   SDL_Rect   rect
 
   SDL_Color   upColor
 
   SDL_Color   downColor
 
   int   isPressed
 
   int   touchIndex
 
buttons [NUM_DRUMS]
 
static struct sound drums [NUM_DRUMS]
 
struct {
   struct {
      Uint8 *   position
 
      Uint32   remaining
 
      Uint32   timestamp
 
   }   channels [NUM_CHANNELS]
 
   SDL_AudioSpec   outputSpec
 
   int   numSoundsPlaying
 
mixer
 

Macro Definition Documentation

◆ NUM_CHANNELS

#define NUM_CHANNELS   8 /* max number of sounds we can play at once */

Definition at line 10 of file mixer.c.

Referenced by audioCallback(), and playSound().

◆ NUM_DRUMS

#define NUM_DRUMS   4 /* number of drums in our set */

Definition at line 11 of file mixer.c.

Referenced by handleMouseButtonDown(), handleMouseButtonUp(), initializeButtons(), main(), and render().

Function Documentation

◆ audioCallback()

void audioCallback ( void userdata,
Uint8 stream,
int  len 
)

Definition at line 234 of file mixer.c.

References i, mixer, NULL, NUM_CHANNELS, SDL_memset, SDL_MIX_MAXVOLUME, SDL_MixAudioFormat, and SDL_PauseAudio.

Referenced by main().

235 {
236  int i;
237  int copy_amt;
238  SDL_memset(stream, mixer.outputSpec.silence, len); /* initialize buffer to silence */
239  /* for each channel, mix in whatever is playing on that channel */
240  for (i = 0; i < NUM_CHANNELS; i++) {
241  if (mixer.channels[i].position == NULL) {
242  /* if no sound is playing on this channel */
243  continue; /* nothing to do for this channel */
244  }
245 
246  /* copy len bytes to the buffer, unless we have fewer than len bytes remaining */
247  copy_amt =
248  mixer.channels[i].remaining <
249  len ? mixer.channels[i].remaining : len;
250 
251  /* mix this sound effect with the output */
252  SDL_MixAudioFormat(stream, mixer.channels[i].position,
253  mixer.outputSpec.format, copy_amt, SDL_MIX_MAXVOLUME);
254 
255  /* update buffer position in sound effect and the number of bytes left */
256  mixer.channels[i].position += copy_amt;
257  mixer.channels[i].remaining -= copy_amt;
258 
259  /* did we finish playing the sound effect ? */
260  if (mixer.channels[i].remaining == 0) {
261  mixer.channels[i].position = NULL; /* indicates no sound playing on channel anymore */
262  mixer.numSoundsPlaying--;
263  if (mixer.numSoundsPlaying == 0) {
264  /* if no sounds left playing, pause audio callback */
265  SDL_PauseAudio(1);
266  }
267  }
268  }
269 }
#define SDL_MIX_MAXVOLUME
Definition: SDL_audio.h:616
#define SDL_MixAudioFormat
struct @64 mixer
GLenum GLsizei len
#define SDL_PauseAudio
GLuint GLuint stream
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:164
#define NUM_CHANNELS
Definition: mixer.c:10
#define SDL_memset

◆ handleMouseButtonDown()

void handleMouseButtonDown ( SDL_Event event)

Definition at line 122 of file mixer.c.

References buttons, drums, i, NUM_DRUMS, playSound(), rect, SDL_GetMouseState, and SDL_Rect::x.

Referenced by main().

123 {
124 
125  int x, y, mouseIndex, i, drumIndex;
126 
127  mouseIndex = 0;
128  drumIndex = -1;
129 
130  SDL_GetMouseState(&x, &y);
131  /* check if we hit any of the drum buttons */
132  for (i = 0; i < NUM_DRUMS; i++) {
133  if (x >= buttons[i].rect.x
134  && x < buttons[i].rect.x + buttons[i].rect.w
135  && y >= buttons[i].rect.y
136  && y < buttons[i].rect.y + buttons[i].rect.h) {
137  drumIndex = i;
138  break;
139  }
140  }
141  if (drumIndex != -1) {
142  /* if we hit a button */
143  buttons[drumIndex].touchIndex = mouseIndex;
144  buttons[drumIndex].isPressed = 1;
145  playSound(&drums[drumIndex]);
146  }
147 
148 }
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
#define NUM_DRUMS
Definition: mixer.c:11
int playSound(struct sound *)
Definition: mixer.c:187
static struct sound drums[NUM_DRUMS]
Definition: mixer.c:29
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1574
int x
Definition: SDL_rect.h:66
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
SDL_Rect rect
Definition: mixer.c:15
static struct @63 buttons[NUM_DRUMS]
#define SDL_GetMouseState

◆ handleMouseButtonUp()

void handleMouseButtonUp ( SDL_Event event)

Definition at line 152 of file mixer.c.

References buttons, i, NUM_DRUMS, and touchIndex.

Referenced by main().

153 {
154  int i;
155  int mouseIndex = 0;
156  /* check if this should cause any of the buttons to become unpressed */
157  for (i = 0; i < NUM_DRUMS; i++) {
158  if (buttons[i].touchIndex == mouseIndex) {
159  buttons[i].isPressed = 0;
160  }
161  }
162 }
#define NUM_DRUMS
Definition: mixer.c:11
int touchIndex
Definition: mixer.c:19
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
static struct @63 buttons[NUM_DRUMS]

◆ initializeButtons()

void initializeButtons ( SDL_Renderer renderer)

Definition at line 54 of file mixer.c.

References buttons, downColor, SDL_Rect::h, i, NUM_DRUMS, SDL_RenderGetLogicalSize, upColor, SDL_Rect::w, SDL_Rect::x, and SDL_Rect::y.

Referenced by main().

55 {
56  int i;
57  int spacing = 10; /* gap between drum buttons */
58  SDL_Rect buttonRect; /* keeps track of where to position drum */
59  SDL_Color upColor = { 86, 86, 140, 255 }; /* color of drum when not pressed */
60  SDL_Color downColor = { 191, 191, 221, 255 }; /* color of drum when pressed */
61  int renderW, renderH;
62 
63  SDL_RenderGetLogicalSize(renderer, &renderW, &renderH);
64 
65  buttonRect.x = spacing;
66  buttonRect.y = spacing;
67  buttonRect.w = renderW - 2 * spacing;
68  buttonRect.h = (renderH - (NUM_DRUMS + 1) * spacing) / NUM_DRUMS;
69 
70  /* setup each button */
71  for (i = 0; i < NUM_DRUMS; i++) {
72 
73  buttons[i].rect = buttonRect;
74  buttons[i].isPressed = 0;
75  buttons[i].upColor = upColor;
76  buttons[i].downColor = downColor;
77 
78  buttonRect.y += spacing + buttonRect.h; /* setup y coordinate for next drum */
79 
80  }
81 }
#define NUM_DRUMS
Definition: mixer.c:11
int x
Definition: SDL_rect.h:66
int w
Definition: SDL_rect.h:67
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
int h
Definition: SDL_rect.h:67
SDL_Color upColor
Definition: mixer.c:16
SDL_Color downColor
Definition: mixer.c:17
static struct @63 buttons[NUM_DRUMS]
#define SDL_RenderGetLogicalSize
int y
Definition: SDL_rect.h:66
A rectangle, with the origin at the upper left.
Definition: SDL_rect.h:64

◆ loadSound()

void loadSound ( const char *  file,
struct sound s 
)

Definition at line 88 of file mixer.c.

References SDL_AudioCVT::buf, sound::buffer, SDL_AudioSpec::channels, fatalError(), SDL_AudioSpec::format, SDL_AudioSpec::freq, SDL_AudioCVT::len, SDL_AudioCVT::len_cvt, SDL_AudioCVT::len_mult, sound::length, mixer, NULL, SDL_BuildAudioCVT, SDL_ConvertAudio, SDL_free, SDL_LoadWAV, SDL_malloc, SDL_memcpy, and spec.

Referenced by main().

89 {
90  SDL_AudioSpec spec; /* the audio format of the .wav file */
91  SDL_AudioCVT cvt; /* used to convert .wav to output format when formats differ */
92  int result;
93  if (SDL_LoadWAV(file, &spec, &s->buffer, &s->length) == NULL) {
94  fatalError("could not load .wav");
95  }
96  /* build the audio converter */
97  result = SDL_BuildAudioCVT(&cvt, spec.format, spec.channels, spec.freq,
98  mixer.outputSpec.format,
99  mixer.outputSpec.channels,
100  mixer.outputSpec.freq);
101  if (result == -1) {
102  fatalError("could not build audio CVT");
103  } else if (result != 0) {
104  /*
105  this happens when the .wav format differs from the output format.
106  we convert the .wav buffer here
107  */
108  cvt.buf = (Uint8 *) SDL_malloc(s->length * cvt.len_mult); /* allocate conversion buffer */
109  cvt.len = s->length; /* set conversion buffer length */
110  SDL_memcpy(cvt.buf, s->buffer, s->length); /* copy sound to conversion buffer */
111  if (SDL_ConvertAudio(&cvt) == -1) { /* convert the sound */
112  fatalError("could not convert .wav");
113  }
114  SDL_free(s->buffer); /* free the original (unconverted) buffer */
115  s->buffer = cvt.buf; /* point sound buffer to converted buffer */
116  s->length = cvt.len_cvt; /* set sound buffer's new length */
117  }
118 }
Uint8 * buffer
Definition: mixer.c:24
GLuint64EXT * result
void fatalError(const char *string)
Definition: common.c:32
Uint8 * buf
Definition: SDL_audio.h:232
#define SDL_BuildAudioCVT
struct @64 mixer
A structure to hold a set of audio conversion filters and buffers.
Definition: SDL_audio.h:226
SDL_AudioSpec spec
Definition: loopwave.c:31
#define SDL_memcpy
#define SDL_ConvertAudio
Uint8 channels
Definition: SDL_audio.h:182
uint8_t Uint8
Definition: SDL_stdinc.h:179
#define SDL_free
#define SDL_LoadWAV(file, spec, audio_buf, audio_len)
Definition: SDL_audio.h:451
#define NULL
Definition: begin_code.h:164
SDL_AudioFormat format
Definition: SDL_audio.h:181
Uint32 length
Definition: mixer.c:25
#define SDL_malloc

◆ main()

int main ( int  argc,
char *  argv[] 
)

Definition at line 272 of file mixer.c.

References AUDIO_S16LSB, audioCallback(), done, drums, fatalError(), handleMouseButtonDown(), handleMouseButtonUp(), i, initializeButtons(), loadSound(), mixer, NULL, NUM_DRUMS, render(), renderer, SDL_CreateRenderer, SDL_CreateWindow, SDL_Delay, SDL_free, SDL_GetWindowSize, SDL_Init, SDL_INIT_AUDIO, SDL_INIT_VIDEO, SDL_memset, SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP, SDL_OpenAudio, SDL_PollEvent, SDL_Quit, SDL_QUIT, SDL_RenderSetLogicalSize, SDL_WINDOW_ALLOW_HIGHDPI, SDL_WINDOW_BORDERLESS, and SDL_Event::type.

273 {
274  int done; /* has user tried to quit ? */
275  SDL_Window *window; /* main window */
278  int i;
279  int width;
280  int height;
281 
283  fatalError("could not initialize SDL");
284  }
286  renderer = SDL_CreateRenderer(window, 0, 0);
287 
288  SDL_GetWindowSize(window, &width, &height);
289  SDL_RenderSetLogicalSize(renderer, width, height);
290 
291  /* initialize the mixer */
292  SDL_memset(&mixer, 0, sizeof(mixer));
293  /* setup output format */
294  mixer.outputSpec.freq = 44100;
295  mixer.outputSpec.format = AUDIO_S16LSB;
296  mixer.outputSpec.channels = 2;
297  mixer.outputSpec.samples = 256;
298  mixer.outputSpec.callback = audioCallback;
299  mixer.outputSpec.userdata = NULL;
300 
301  /* open audio for output */
302  if (SDL_OpenAudio(&mixer.outputSpec, NULL) != 0) {
303  fatalError("Opening audio failed");
304  }
305 
306  /* load our drum noises */
307  loadSound("ds_kick_big_amb.wav", &drums[3]);
308  loadSound("ds_brush_snare.wav", &drums[2]);
309  loadSound("ds_loose_skin_mute.wav", &drums[1]);
310  loadSound("ds_china.wav", &drums[0]);
311 
312  /* setup positions, colors, and state of buttons */
313  initializeButtons(renderer);
314 
315  /* enter main loop */
316  done = 0;
317  while (!done) {
318  while (SDL_PollEvent(&event)) {
319  switch (event.type) {
320  case SDL_MOUSEBUTTONDOWN:
321  handleMouseButtonDown(&event);
322  break;
323  case SDL_MOUSEBUTTONUP:
324  handleMouseButtonUp(&event);
325  break;
326  case SDL_QUIT:
327  done = 1;
328  break;
329  }
330  }
331  render(renderer); /* draw buttons */
332 
333  SDL_Delay(1);
334  }
335 
336  /* cleanup code, let's free up those sound buffers */
337  for (i = 0; i < NUM_DRUMS; i++) {
338  SDL_free(drums[i].buffer);
339  }
340  /* let SDL do its exit code */
341  SDL_Quit();
342 
343  return 0;
344 }
#define SDL_PollEvent
#define SDL_OpenAudio
void fatalError(const char *string)
Definition: common.c:32
void loadSound(const char *file, struct sound *s)
Definition: mixer.c:88
#define SDL_CreateWindow
struct @64 mixer
#define NUM_DRUMS
Definition: mixer.c:11
GLint GLint GLsizei width
Definition: SDL_opengl.h:1572
#define SDL_GetWindowSize
void initializeButtons(SDL_Renderer *)
Definition: mixer.c:54
static SDL_Renderer * renderer
#define SDL_free
struct _cl_event * event
#define SDL_RenderSetLogicalSize
void handleMouseButtonUp(SDL_Event *event)
Definition: mixer.c:152
#define SDL_Quit
int done
Definition: checkkeys.c:28
static struct sound drums[NUM_DRUMS]
Definition: mixer.c:29
void audioCallback(void *userdata, Uint8 *stream, int len)
Definition: mixer.c:234
void handleMouseButtonDown(SDL_Event *event)
Definition: mixer.c:122
#define SDL_Delay
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:164
GLuint buffer
GLint GLint GLsizei GLsizei height
Definition: SDL_opengl.h:1572
#define SDL_INIT_AUDIO
Definition: SDL.h:78
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
The type used to identify a window.
Definition: SDL_sysvideo.h:73
#define AUDIO_S16LSB
Definition: SDL_audio.h:92
#define SDL_Init
General event structure.
Definition: SDL_events.h:557
void render(SDL_Renderer *renderer)
Definition: mixer.c:166
#define SDL_INIT_VIDEO
Definition: SDL.h:79
#define SDL_CreateRenderer
#define SDL_memset
Uint32 type
Definition: SDL_events.h:559

◆ playSound()

int playSound ( struct sound s)

Definition at line 187 of file mixer.c.

References sound::buffer, i, sound::length, mixer, NULL, NUM_CHANNELS, SDL_GetTicks(), and SDL_PauseAudio.

Referenced by handleMouseButtonDown().

188 {
189  /*
190  find an empty channel to play on.
191  if no channel is available, use oldest channel
192  */
193  int i;
194  int selected_channel = -1;
195  int oldest_channel = 0;
196 
197  if (mixer.numSoundsPlaying == 0) {
198  /* we're playing a sound now, so start audio callback back up */
199  SDL_PauseAudio(0);
200  }
201 
202  /* find a sound channel to play the sound on */
203  for (i = 0; i < NUM_CHANNELS; i++) {
204  if (mixer.channels[i].position == NULL) {
205  /* if no sound on this channel, select it */
206  selected_channel = i;
207  break;
208  }
209  /* if this channel's sound is older than the oldest so far, set it to oldest */
210  if (mixer.channels[i].timestamp <
211  mixer.channels[oldest_channel].timestamp)
212  oldest_channel = i;
213  }
214 
215  /* no empty channels, take the oldest one */
216  if (selected_channel == -1)
217  selected_channel = oldest_channel;
218  else
219  mixer.numSoundsPlaying++;
220 
221  /* point channel data to wav data */
222  mixer.channels[selected_channel].position = s->buffer;
223  mixer.channels[selected_channel].remaining = s->length;
224  mixer.channels[selected_channel].timestamp = SDL_GetTicks();
225 
226  return selected_channel;
227 }
Uint8 * buffer
Definition: mixer.c:24
struct @64 mixer
#define SDL_PauseAudio
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:164
Uint32 length
Definition: mixer.c:25
#define NUM_CHANNELS
Definition: mixer.c:10

◆ render()

void render ( SDL_Renderer renderer)

Definition at line 166 of file mixer.c.

References SDL_Color::a, SDL_Color::b, buttons, SDL_Color::g, i, NUM_DRUMS, SDL_Color::r, rect, SDL_RenderClear, SDL_RenderFillRect, SDL_RenderPresent, and SDL_SetRenderDrawColor.

Referenced by main().

167 {
168  int i;
169  SDL_SetRenderDrawColor(renderer, 50, 50, 50, 255);
170  SDL_RenderClear(renderer); /* draw background (gray) */
171  /* draw the drum buttons */
172  for (i = 0; i < NUM_DRUMS; i++) {
173  SDL_Color color =
174  buttons[i].isPressed ? buttons[i].downColor : buttons[i].upColor;
175  SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
176  SDL_RenderFillRect(renderer, &buttons[i].rect);
177  }
178  /* update the screen */
179  SDL_RenderPresent(renderer);
180 }
Uint8 g
Definition: SDL_pixels.h:298
#define SDL_RenderFillRect
Uint8 b
Definition: SDL_pixels.h:299
#define NUM_DRUMS
Definition: mixer.c:11
Uint8 r
Definition: SDL_pixels.h:297
Uint8 a
Definition: SDL_pixels.h:300
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define SDL_RenderClear
GLuint color
#define SDL_SetRenderDrawColor
SDL_Rect rect
Definition: mixer.c:15
static struct @63 buttons[NUM_DRUMS]
#define SDL_RenderPresent

Variable Documentation

◆ buttons

◆ channels

struct { ... } channels[NUM_CHANNELS]

Referenced by IMA_ADPCM_decode().

◆ downColor

SDL_Color downColor

Definition at line 17 of file mixer.c.

Referenced by initializeButtons().

◆ drums

struct sound drums[NUM_DRUMS]
static

Definition at line 29 of file mixer.c.

Referenced by handleMouseButtonDown(), and main().

◆ isPressed

int isPressed

Definition at line 18 of file mixer.c.

◆ mixer

struct { ... } mixer

◆ numSoundsPlaying

int numSoundsPlaying

Definition at line 49 of file mixer.c.

◆ outputSpec

SDL_AudioSpec outputSpec

Definition at line 48 of file mixer.c.

◆ position

Uint8* position

Definition at line 44 of file mixer.c.

Referenced by MoveSprites(), and SDLTest_PrintEvent().

◆ rect

SDL_Rect rect

Definition at line 15 of file mixer.c.

Referenced by handleMouseButtonDown(), and render().

◆ remaining

Uint32 remaining

Definition at line 45 of file mixer.c.

◆ timestamp

Uint32 timestamp

Definition at line 46 of file mixer.c.

Referenced by SDLTest_TimestampToString().

◆ touchIndex

int touchIndex

Definition at line 19 of file mixer.c.

Referenced by handleMouseButtonUp().

◆ upColor

SDL_Color upColor

Definition at line 16 of file mixer.c.

Referenced by initializeButtons().