-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathmusic_vorbis.c
207 lines (175 loc) · 5.2 KB
/
music_vorbis.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/*
Copyright (C) 2007 Will Glynn
Derived from music.c:
Copyright (C) 2005 Michael K. McCarty & Fritz Bronner
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <race.h>
#include <Buzz_inc.h>
#include <mmfile.h>
#include <pace.h>
#include <utils.h>
// A map of music_tracks to filenames
struct music_key {
enum music_track track;
char *name;
} music_key[] = {
{ M_ASSEMBLY, "assembly" },
{ M_ASTTRNG, "asttrng" },
{ M_BADNEWS, "badnews" },
{ M_DRUMSM, "drumsm" },
{ M_ELEPHANT, "elephant" },
{ M_FILLER, "filler" },
{ M_FUTURE, "future" },
{ M_GOOD, "good" },
{ M_HARDWARE, "hardware" },
{ M_HISTORY, "history" },
{ M_INTEL, "intel" },
{ M_INTELLEG, "intelleg" },
{ M_INTERLUD, "interlud" },
{ M_LIFTOFF, "liftoff" },
{ M_MISSPLAN, "missplan" },
{ M_NEW1950, "new1950" },
{ M_NEW1970, "new1970" },
{ M_PRES, "pres" },
{ M_PRGMTRG, "prgmtrg" },
{ M_RD, "r&d" },
{ M_SOVTYP, "sovtyp" },
{ M_SUCCESS, "success" },
{ M_SVFUN, "svfun" },
{ M_SVLOGO, "svlogo" },
{ M_SVPORT, "svport2" },
{ M_THEME, "theme" },
{ M_UNSUCC, "unsucc" },
{ M_USFUN, "usfun" },
{ M_USMIL, "usmil" },
{ M_USPORT, "usport2" },
{ M_USSRMIL, "ussrmil" },
{ M_VICTORY, "victory" },
{ M_MAX_MUSIC, NULL },
};
// This structure defines each track
struct music_file {
// Pointer to the audio buffer, once loaded from disk
char * buf;
size_t buf_size;
// Can this track be played? i.e., does it exist?
int unplayable;
// Is this track playing?
int playing;
// The SDL audio chunk describing this track
struct audio_chunk chunk;
};
struct music_file music_files[M_MAX_MUSIC];
// Ensure that the specified music track is in memory, loading it if required
void music_load(enum music_track track)
{
char fname[20] = "";
int i;
ssize_t bytes;
// Check to see if the track is already loaded or known broken; if so, we're already done
if (music_files[track].buf != NULL || music_files[track].unplayable)
return;
// Find the name for this track
for (i = 0; music_key[i].track != M_MAX_MUSIC; i++) {
if (music_key[i].track == track && music_key[i].name) {
snprintf(fname, sizeof(fname), "%s.OGG", music_key[track].name);
break;
}
}
// Bail out if this track isn't known
if (strlen(fname) == 0) {
music_files[track].unplayable = 1;
return;
}
// Load the file
bytes = load_audio_file(fname, &music_files[track].buf, &music_files[track].buf_size);
// Handle failure gracefully
if (bytes < 0) {
free(music_files[track].buf);
music_files[track].unplayable = 1;
return;
}
// XXX: Trim the last two seconds from the audio file, since it's broken
// This should really be done on the Vorbis files, rather than in the player
if (bytes > 2 * 11025) {
music_files[track].buf_size -= 2 * 11025;
music_files[track].buf = xrealloc(music_files[track].buf, music_files[track].buf_size);
}
}
// Start playing the given track
void music_start_loop(enum music_track track, int loop)
{
// Load the track as necessary
music_load(track);
// Ensure that this track is playable
if (music_files[track].unplayable)
return;
// Ignore requests to play a track that's already playing
if (music_files[track].playing)
return;
// Initialize the audio chunk
music_files[track].chunk.data = music_files[track].buf;
music_files[track].chunk.size = music_files[track].buf_size;
music_files[track].chunk.loop = loop;
// XXX: Stop the existing music, since we need the music channel
// This should be changed to dynamic channel allocation, to allow layering music tracks
music_stop();
// Play the track, and indicate that it's playing
play(&music_files[track].chunk, AV_MUSIC_CHANNEL);
music_files[track].playing = 1;
}
// Stop a specific track
void music_stop_track(enum music_track track)
{
if (music_files[track].playing) {
// XXX: stop the global music channel
// This should be assigned on a per-track basis
av_silence(AV_MUSIC_CHANNEL);
music_files[track].playing = 0;
}
}
// Stop all tracks
void music_stop()
{
int i;
// Iterate through the list and stop any playing tracks by calling music_stop_track()
for (i = 0; i < M_MAX_MUSIC; i ++) {
if (music_files[i].playing) {
music_stop_track(i);
}
}
}
int music_is_playing()
{
int i;
for (i = 0; i < M_MAX_MUSIC; i ++) {
if (music_files[i].playing) {
return 1;
}
}
return 0;
}
int music_is_track_playing(enum music_track track)
{
return music_files[track].playing;
}
void music_pump()
{
// TODO: Check to see that all the tracks we think are playing actually are
// This doesn't apply to looped tracks, since those keep playing forever
}
void music_set_mute(int muted)
{
MuteChannel(AV_MUSIC_CHANNEL, muted);
}