Added simple SDL mixer example
This commit is contained in:
288
project/jni/application/simplemixer/simplemixer.c
Normal file
288
project/jni/application/simplemixer/simplemixer.c
Normal file
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
* SimpleMixer 1.1
|
||||
*
|
||||
* Simple sound mixing example for SDL.
|
||||
*
|
||||
* (C) David Olofson, 2003
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include "SDL.h"
|
||||
#include "SDL_audio.h"
|
||||
|
||||
#define SM_SOUNDS 4
|
||||
#define SM_VOICES 4
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Uint8 *data;
|
||||
Uint32 length;
|
||||
} SM_sound;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Sint16 *data;
|
||||
int length;
|
||||
int position;
|
||||
int l_vol;
|
||||
int r_vol;
|
||||
} SM_voice;
|
||||
|
||||
|
||||
SM_sound sounds[SM_SOUNDS];
|
||||
SM_voice voices[SM_VOICES];
|
||||
SDL_AudioSpec audiospec;
|
||||
int die = 0;
|
||||
|
||||
|
||||
void sm_play(unsigned voice, unsigned sound, float lvol, float rvol)
|
||||
{
|
||||
if(voice >= SM_VOICES || sound >= SM_SOUNDS)
|
||||
return;
|
||||
|
||||
/* Stop voice */
|
||||
voices[voice].data = NULL;
|
||||
|
||||
/* Reprogram */
|
||||
voices[voice].length = sounds[sound].length / 2;
|
||||
voices[voice].position = 0;
|
||||
voices[voice].l_vol = (int)(lvol * 256.0);
|
||||
voices[voice].r_vol = (int)(rvol * 256.0);
|
||||
|
||||
/* Start! */
|
||||
voices[voice].data = (Sint16*)(sounds[sound].data);
|
||||
}
|
||||
|
||||
|
||||
static void sm_mixer(void *ud, Uint8 *stream, int len)
|
||||
{
|
||||
int vi, s;
|
||||
Sint16 *buf = (Sint16 *)stream;
|
||||
|
||||
/* Clear the buffer */
|
||||
memset(buf, 0, len);
|
||||
|
||||
/* 2 channels, 2 bytes/sample = 4 bytes/frame */
|
||||
len /= 4;
|
||||
|
||||
/* For each voice... */
|
||||
for(vi = 0; vi < SM_VOICES; ++vi)
|
||||
{
|
||||
SM_voice *v = &voices[vi];
|
||||
if(!v->data)
|
||||
continue;
|
||||
|
||||
/* For each sample... */
|
||||
for(s = 0; s < len; ++s)
|
||||
{
|
||||
if(v->position >= v->length)
|
||||
{
|
||||
v->data = NULL;
|
||||
break;
|
||||
}
|
||||
buf[s * 2] += v->data[v->position] * v->l_vol >> 8;
|
||||
buf[s * 2 + 1] += v->data[v->position] * v->r_vol >> 8;
|
||||
++v->position;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int sm_open(void)
|
||||
{
|
||||
SDL_AudioSpec as;
|
||||
|
||||
memset(sounds, 0, sizeof(sounds));
|
||||
memset(voices, 0, sizeof(voices));
|
||||
|
||||
if(SDL_InitSubSystem(SDL_INIT_AUDIO|SDL_INIT_VIDEO) < 0)
|
||||
return -2;
|
||||
|
||||
as.freq = 44100;
|
||||
as.format = AUDIO_S16SYS;
|
||||
as.channels = 2;
|
||||
as.samples = 1024;
|
||||
as.callback = sm_mixer;
|
||||
if(SDL_OpenAudio(&as, &audiospec) < 0)
|
||||
return -3;
|
||||
|
||||
if(audiospec.format != AUDIO_S16SYS)
|
||||
return -4;
|
||||
|
||||
SDL_PauseAudio(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void sm_close(void)
|
||||
{
|
||||
int i;
|
||||
SDL_PauseAudio(1);
|
||||
for(i = 0; i < SM_VOICES; ++i)
|
||||
voices[i].data = NULL;
|
||||
SDL_CloseAudio();
|
||||
for(i = 0; i < SM_SOUNDS; ++i)
|
||||
SDL_FreeWAV(sounds[i].data);
|
||||
memset(sounds, 0, sizeof(sounds));
|
||||
memset(voices, 0, sizeof(voices));
|
||||
}
|
||||
|
||||
|
||||
void flip_endian(Uint8 *data, int length)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < length; i += 2)
|
||||
{
|
||||
int x = data[i];
|
||||
data[i] = data[i + 1];
|
||||
data[i + 1] = x;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int sm_load(int sound, const char *file)
|
||||
{
|
||||
int failed = 0;
|
||||
SDL_AudioSpec spec;
|
||||
if(sounds[sound].data)
|
||||
SDL_FreeWAV(sounds[sound].data);
|
||||
sounds[sound].data = NULL;
|
||||
if(SDL_LoadWAV(file, &spec, &sounds[sound].data,
|
||||
&sounds[sound].length) == NULL)
|
||||
return -1;
|
||||
if(spec.freq != 44100)
|
||||
fprintf(stderr, "WARNING: File '%s' is not 44.1 kHz."
|
||||
" Might sound weird...\n", file);
|
||||
if(spec.channels != 1)
|
||||
{
|
||||
fprintf(stderr, "Only mono sounds are supported!\n");
|
||||
failed = 1;
|
||||
}
|
||||
switch(spec.format)
|
||||
{
|
||||
case AUDIO_S16LSB:
|
||||
case AUDIO_S16MSB:
|
||||
if(spec.format != AUDIO_S16SYS)
|
||||
flip_endian(sounds[sound].data, sounds[sound].length);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unsupported sample format!\n");
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
if(failed)
|
||||
{
|
||||
SDL_FreeWAV(sounds[sound].data);
|
||||
sounds[sound].data = NULL;
|
||||
return -2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void breakhandler(int a)
|
||||
{
|
||||
die = 1;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const char *bd = "#...#...#...#..##...#...#...#.##";
|
||||
const char *cl = "....#..*....#....*..#....*..#.**";
|
||||
const char *cb = "#...*..#..*...#.#...*..#..*..*#*";
|
||||
const char *hh = "..#...#...#...#...#...#...#...#.";
|
||||
int res;
|
||||
Uint32 step = 0;
|
||||
Sint32 timer;
|
||||
SDL_Event event;
|
||||
int color = 0;
|
||||
if(SDL_Init(0) < 0)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
atexit(SDL_Quit);
|
||||
signal(SIGTERM, breakhandler);
|
||||
signal(SIGINT, breakhandler);
|
||||
*/
|
||||
|
||||
if(sm_open() < 0)
|
||||
{
|
||||
fprintf(stderr, "Couldn't start mixer!\n");
|
||||
SDL_Quit();
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_SetVideoMode(320, 200, 16, SDL_SWSURFACE);
|
||||
|
||||
res = 0;
|
||||
res |= sm_load(0, "808-bassdrum.wav");
|
||||
res |= sm_load(1, "808-clap.wav");
|
||||
res |= sm_load(2, "808-cowbell.wav");
|
||||
res |= sm_load(3, "808-hihat.wav");
|
||||
if(res)
|
||||
{
|
||||
sm_close();
|
||||
SDL_Quit();
|
||||
fprintf(stderr, "Couldn't load sounds!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Of course, playing this stuff would be
|
||||
* much better done in the audio callback,
|
||||
* since the timing out here jitters a lot.
|
||||
*
|
||||
* However, this is just a fun hack to get
|
||||
* the thing to make some sound, without
|
||||
* slapping in a game or something. :-)
|
||||
*/
|
||||
SDL_Delay(200);
|
||||
timer = (Sint32)SDL_GetTicks();
|
||||
while(!die)
|
||||
{
|
||||
if('#' == bd[step])
|
||||
sm_play(0, 0, 1.0, 1.0);
|
||||
|
||||
if('#' == cl[step])
|
||||
sm_play(1, 1, 0.6, 0.5);
|
||||
else if('*' == cl[step])
|
||||
sm_play(1, 1, 0.2, 0.3);
|
||||
|
||||
if('#' == cb[step])
|
||||
sm_play(2, 2, 0.3, 0.2);
|
||||
else if('*' == cb[step])
|
||||
sm_play(2, 2, 0.1, 0.2);
|
||||
|
||||
if('#' == hh[step])
|
||||
sm_play(3, 3, 0.3, 0.4);
|
||||
|
||||
step = (step + 1) % 32;
|
||||
|
||||
timer += 120;
|
||||
|
||||
while(SDL_PollEvent(&event) > 0)
|
||||
{
|
||||
if(event.type & (SDL_KEYUP | SDL_KEYDOWN))
|
||||
{
|
||||
Uint8 *keys = SDL_GetKeyState(NULL);
|
||||
if(keys[SDLK_ESCAPE])
|
||||
die = 1;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_FillRect(SDL_GetVideoSurface(), NULL, color);
|
||||
color += 10;
|
||||
SDL_Flip(SDL_GetVideoSurface()); // Program is required to call SDL_Flip(), or it will invoke Application Not Responding dialog
|
||||
|
||||
while(((Sint32)SDL_GetTicks() - timer) < 0)
|
||||
SDL_Delay(10);
|
||||
}
|
||||
|
||||
sm_close();
|
||||
SDL_Quit();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user