pass LDFLAGS to compiler at link time
[tennix.git] / sound.cc
blobf36c620c4f2067d39651c6c4f79f06b141275a73
2 /**
4 * Tennix! SDL Port
5 * Copyright (C) 2003, 2007, 2008, 2009 Thomas Perl <thp@thpinfo.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20 * MA 02110-1301, USA.
22 **/
24 #include "tennix.h"
25 #include "sound.h"
26 #include "archive.hh"
27 #include "graphics.h"
29 #include <stdarg.h>
30 #include <stdlib.h>
31 #include <assert.h>
33 static Sound* sounds;
35 static const char* samples[] = {
36 "rain.ogg",
37 "racket1.ogg",
38 "racket2.ogg",
39 "ground1.ogg",
40 "ground2.ogg",
41 "audience.ogg",
42 "applause.ogg",
43 "out.ogg",
44 "background.ogg",
45 "mouseover.ogg",
46 "mouseclick.ogg",
48 #ifdef HAVE_VOICE_FILES
49 "to.ogg",
50 "all.ogg",
51 "love-in.ogg",
52 "love-out.ogg",
53 "fifteen-in.ogg",
54 "fifteen-out.ogg",
55 "thirty-in.ogg",
56 "thirty-out.ogg",
57 "forty-in.ogg",
58 "forty-out.ogg",
59 "deuce.ogg",
60 "advantage-player-one.ogg",
61 "advantage-player-two.ogg",
63 "zero-in.ogg",
64 "zero-out.ogg",
65 "one-in.ogg",
66 "one-out.ogg",
67 "two-in.ogg",
68 "two-out.ogg",
69 "three-in.ogg",
70 "three-out.ogg",
71 "four-in.ogg",
72 "four-out.ogg",
73 "five-in.ogg",
74 "five-out.ogg",
75 "six-in.ogg",
76 "six-out.ogg",
77 "seven-in.ogg",
78 "seven-out.ogg",
80 "in-the-first-set.ogg",
81 "in-the-second-set.ogg",
82 "in-the-third-set.ogg",
83 "in-the-fourth-set.ogg",
84 "in-the-fifth-set.ogg",
86 "quit-it1.ogg",
87 "quit-it2.ogg",
88 "quit-it3.ogg",
89 "quit-it4.ogg",
91 "new-game1.ogg",
92 "new-game2.ogg",
93 "new-game3.ogg",
94 "new-game4.ogg",
95 "new-game5.ogg",
96 "new-game6.ogg",
98 "lets-go1.ogg",
99 "lets-go2.ogg",
100 "lets-go3.ogg",
101 "lets-go4.ogg",
102 #endif
105 static sound_id voice_queue[VOICE_QUEUE_MAX];
106 static int voice_queue_size = 0;
107 static int voice_queue_position = 0;
109 int voice_finished_flag = 1;
110 static int available_channels = 0;
112 void init_sound(TennixArchive& tnxar) {
113 int i;
114 char *d;
115 Mix_Chunk* data;
117 if( Mix_OpenAudio( 44100, AUDIO_S16SYS, 2, 1024) < 0) {
118 fprintf( stderr, "Error initializing SDL_mixer: %s\n", Mix_GetError());
121 sounds = (Sound*)calloc(SOUND_MAX, sizeof(Sound));
123 draw_button(40, (HEIGHT-40)/2, WIDTH-80, 40, 100, 100, 100, 1);
124 store_screen();
126 /* +1 because of zero-based indexing AND +1 for voice channel */
127 available_channels = Mix_AllocateChannels(LAST_SOUNDEFFECT_ID+1+1);
129 if (available_channels < LAST_SOUNDEFFECT_ID+1+1) {
130 fprintf(stderr, "Warning: Got only %d audio channels (requested %d).\n",
131 available_channels,
132 LAST_SOUNDEFFECT_ID+1+1);
135 for( i=0; i<SOUND_MAX; i++) {
136 if (tnxar.setItemFilename(samples[i]) != 0) {
137 d = tnxar.getItemBytes();
138 data = Mix_LoadWAV_RW(SDL_RWFromMem(d, tnxar.getItemSize()), 0);
139 free(d);
140 } else {
141 fprintf(stderr, "Cannot find %s\n", samples[i]);
142 exit(EXIT_FAILURE);
144 if( !data) {
145 fprintf( stderr, "Error: %s\n", SDL_GetError());
146 continue;
149 sounds[i].data = data;
151 draw_button(40, (HEIGHT-40)/2, (WIDTH-80)*(GR_COUNT+i)/(SOUND_MAX+GR_COUNT), 40, 100, 250, 100, 0);
152 rectangle(40+BUTTON_BORDER, (HEIGHT-40)/2+20, (WIDTH-80)*(GR_COUNT+i)/(SOUND_MAX+GR_COUNT)-2*BUTTON_BORDER, 10, 170, 250, 170);
153 updatescr();
156 clear_screen();
157 store_screen();
158 updatescr();
160 /* for Voice Queue processing */
161 Mix_ChannelFinished(voice_channel_finished);
164 void play_sample_n(sound_id id, int n)
166 if (id >= SOUND_MAX) {
167 fprintf(stderr, "Cannot play sound #%d.\n", id);
168 return;
171 if (n == -2) {
172 Mix_FadeInChannel(CHANNEL_BY_ID(id, available_channels), sounds[id].data, -1, FADE_IN_MS);
173 } else {
174 Mix_PlayChannel(CHANNEL_BY_ID(id, available_channels), sounds[id].data, n);
177 /* Audience stops clapping when ball is served */
178 if (id >= SOUND_RACKET_FIRST && id <= SOUND_RACKET_LAST) {
179 stop_sample(SOUND_APPLAUSE);
183 void stop_sample(sound_id id)
185 Mix_FadeOutChannel(CHANNEL_BY_ID(id, available_channels), FADE_OUT_MS);
188 void sample_volume(sound_id id, float volume)
190 Mix_Volume(CHANNEL_BY_ID(id, available_channels), volume*MIX_MAX_VOLUME);
193 void sample_volume_group(sound_id first, sound_id last, float volume)
195 unsigned int i;
197 for (i=first; i<=last; i++) {
198 sample_volume(i, volume);
201 void pan_sample(sound_id id, float position)
203 if (position == 0.5) {
204 Mix_SetPanning(CHANNEL_BY_ID(id, available_channels), 255, 255);
206 else {
207 Mix_SetPanning(CHANNEL_BY_ID(id, available_channels), 255*(1.0-position), 255*(position));
211 void pan_sample_group(sound_id first, sound_id last, float position)
213 unsigned int i;
215 for (i=first; i<=last; i++) {
216 pan_sample(i, position);
219 void voice_clear()
221 voice_queue_size = 0;
222 Mix_HaltChannel(CHANNEL_VOICE);
225 void voice_enqueue(sound_id id)
227 if (voice_queue_size < VOICE_QUEUE_MAX) {
228 voice_queue[voice_queue_size++] = id;
229 } else {
230 fprintf(stderr, "Voice queue overflow. Skipping: %d\n", id);
234 void voice_say()
236 if (voice_queue_size > 0) {
237 voice_queue_position = 0;
238 voice_finished_flag = 0;
239 Mix_PlayChannel(CHANNEL_VOICE, sounds[voice_queue[voice_queue_position]].data, 0);
240 voice_queue_position++;
244 void voice_say_list(int n, ...)
246 va_list ap;
247 int i;
248 sound_id id;
250 voice_clear();
252 va_start(ap, n);
253 for (i=0; i<n; i++) {
254 id = (sound_id)va_arg(ap, int);
255 voice_enqueue(id);
257 va_end(ap);
258 voice_say();
261 void voice_channel_finished(int channel)
263 if (channel == CHANNEL_VOICE) {
264 if (voice_queue_position < voice_queue_size) {
265 Mix_PlayChannel(CHANNEL_VOICE, sounds[voice_queue[voice_queue_position]].data, 0);
266 voice_queue_position++;
267 } else {
268 voice_finished_flag = 1;
269 voice_queue_position = 0;