Can change zone.
[cantaveria.git] / audio.c
blob2855d1daa5c99f364c1009eca58579fcacb26432
1 /*
2 Cantaveria - action adventure platform game
3 Copyright (C) 2009 2010 Evan Rinehart
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to
18 The Free Software Foundation, Inc.
19 51 Franklin Street, Fifth Floor
20 Boston, MA 02110-1301, USA
24 audio module is the low level audio output support.
25 the audio thread operates independently of the rest of the
26 game and is backwards from the rest of the modules. After
27 initializing the audio system, it will periodically use a
28 callback to generate needed audio output. This callback is
29 basically defined in synth.c which mixes music and sound.
32 #include <stdlib.h>
33 #include <math.h>
35 #include <SDL/SDL.h>
37 #include <list.h>
38 #include <synth.h>
39 #include <util.h>
40 #include <audio.h>
42 float* lout;
43 float* rout;
45 static int rms_level;
46 static int peak_level;
48 void audio_callback(void *userdata, Uint8 *stream, int bytes){
49 int i, j;
50 Sint16* out = (Sint16*)stream;
51 int buflen = bytes / 2; /* Sint16 = 2 bytes */
52 int samples = buflen / 2; /* 2 channels */
54 float accum = 0;
55 int max = 0;
56 float db = 0;
58 synth_generate(lout, rout, samples);
59 for(i=0, j=0; i<samples; i++){
60 out[j] = (Sint16)(lout[i]*32767); j++;
61 out[j] = (Sint16)(rout[i]*32767); j++;
63 /* output level.
64 dB rms, 20log ( sqrt( avg( x^2 ) ) )
65 dB peak, 20log ( max ( x ) )
68 accum += out[j-1] * out[j-1];
69 if(abs(out[j-1]) > max){
70 max = abs(out[j-1]);
74 accum /= samples;
75 accum = sqrt(accum);
76 db = 20*log10(accum/32767);
77 if(db > -9999){
78 rms_level = db;
80 else{
81 rms_level = -9999;
84 db = 20*log10(max/32767.0);
85 if(db > -9999){
86 peak_level = db;
88 else{
89 peak_level = -9999;
95 char* sample_format_str(int format){
96 switch(format){
97 case AUDIO_S16: return "signed 16-bit LE";
98 case AUDIO_U16: return "unsigned 16-bit LE";
99 case AUDIO_S16MSB: return "signed 16-bit BE";
100 case AUDIO_U16MSB: return "unsigned 16-bit BE";
101 case AUDIO_S8: return "signed 8-bit";
102 case AUDIO_U8: return "unsigned 8-bit";
103 default: return "unknown";
107 void audio_init(){
108 SDL_AudioSpec want;
109 SDL_AudioSpec got;
112 want.freq = SAMPLE_RATE;
113 want.format = AUDIO_S16;
114 want.channels = 2;
115 want.samples = BUFFER_SIZE;
116 want.callback = audio_callback;
119 if(SDL_OpenAudio(&want, &got)<0){
120 fatal_error("sdl: cannot open audio (%s)\n", SDL_GetError());
123 boot_msg("audio:\n");
124 boot_msg(" sample rate: %d\n", got.freq);
125 boot_msg(" channels: %d\n", got.channels);
126 boot_msg(" samples: %d\n", got.samples);
127 boot_msg(" format: %s\n", sample_format_str(got.format));
129 if(got.format != AUDIO_S16){
130 boot_msg(" WARNING: audio format not AUDIO_S16 :(\n");
131 SDL_CloseAudio();
132 boot_msg(" *no sound*\n");
133 return;
135 lout = xmalloc(got.samples*sizeof(float));
136 rout = xmalloc(got.samples*sizeof(float));
137 memset(lout, 0, got.samples*sizeof(float));
138 memset(rout, 0, got.samples*sizeof(float));
140 boot_msg(" sound online\n");
141 SDL_PauseAudio(0);
145 void audio_quit(){
146 SDL_CloseAudio();
147 free(lout);
148 free(rout);
151 int audio_peak_level(){
152 return peak_level;
155 int audio_rms_level(){
156 return rms_level;
160 void audio_lock(){
161 SDL_LockAudio();
164 void audio_unlock(){
165 SDL_UnlockAudio();