gosu 0.7.26.1 → 0.7.27

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,493 +0,0 @@
1
- #include <Gosu/Audio.hpp>
2
- #include <Gosu/Math.hpp>
3
- #include <Gosu/IO.hpp>
4
- #include <Gosu/Utility.hpp>
5
- #include <boost/algorithm/string.hpp>
6
- #include <cassert>
7
- #include <cstdlib>
8
- #include <algorithm>
9
- #include <stdexcept>
10
- #include <vector>
11
-
12
- #include <fmod.h>
13
- #include <fmod_errors.h>
14
-
15
- namespace Gosu
16
- {
17
- extern HWND __Gosu_HWND_for_FMOD;
18
-
19
- namespace
20
- {
21
- GOSU_NORETURN void throwLastFMODError()
22
- {
23
- throw std::runtime_error(FMOD_ErrorString(FSOUND_GetError()));
24
- }
25
-
26
- inline unsigned char fmodCheck(unsigned char retVal)
27
- {
28
- if (retVal == 0 && FSOUND_GetError() != FMOD_ERR_NONE)
29
- throwLastFMODError();
30
-
31
- return retVal;
32
- }
33
-
34
- #ifdef GOSU_IS_WIN
35
- bool setWindow()
36
- {
37
- // Copied and pasted from MSDN.
38
- #define FACILITY_VISUALCPP ((LONG)0x6d)
39
- #define VcppException(sev,err) ((sev) | (FACILITY_VISUALCPP<<16) | err)
40
- #define BAD_MOD VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND)
41
-
42
- HWND fmodWindow = __Gosu_HWND_for_FMOD;
43
- if (fmodWindow == 0)
44
- fmodWindow = GetDesktopWindow();
45
-
46
- // Try to call the first function from fmod.dll, which is lazily
47
- // linked. With this guard, we can raise a catchable C++ exception
48
- // if the library is not found, instead of crashing the game.
49
- __try
50
- {
51
- FSOUND_SetHWND(fmodWindow);
52
- }
53
- __except ((GetExceptionCode() == BAD_MOD) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
54
- {
55
- return false;
56
- }
57
- return true;
58
-
59
- #undef BAD_MOD
60
- #undef VcppException
61
- #undef FACILITY_VISUALCPP
62
- }
63
- #endif
64
-
65
- void requireFMOD()
66
- {
67
- static bool initialized = false;
68
- if (initialized)
69
- return;
70
-
71
- #ifdef GOSU_IS_WIN
72
- if (!setWindow())
73
- throw std::runtime_error("Could not load fmod.dll");
74
- #endif
75
- fmodCheck(FSOUND_Init(44100, 32, 0));
76
-
77
- initialized = true;
78
- }
79
- Song* curSong = 0;
80
- }
81
- }
82
-
83
- Gosu::SampleInstance::SampleInstance(int handle, int extra)
84
- : handle(handle), extra(extra)
85
- {
86
- }
87
-
88
- bool Gosu::SampleInstance::playing() const
89
- {
90
- return FSOUND_IsPlaying(handle);
91
- }
92
-
93
- bool Gosu::SampleInstance::paused() const
94
- {
95
- return FSOUND_GetPaused(handle);
96
- }
97
-
98
- void Gosu::SampleInstance::pause()
99
- {
100
- FSOUND_SetPaused(handle, 1);
101
- }
102
-
103
- void Gosu::SampleInstance::resume()
104
- {
105
- FSOUND_SetPaused(handle, 0);
106
- }
107
-
108
- void Gosu::SampleInstance::stop()
109
- {
110
- FSOUND_StopSound(handle);
111
- }
112
-
113
- void Gosu::SampleInstance::changeVolume(double volume)
114
- {
115
- FSOUND_SetVolume(handle, clamp<int>(volume * 255, 0, 255));
116
- }
117
-
118
- void Gosu::SampleInstance::changePan(double pan)
119
- {
120
- FSOUND_SetPan(handle, clamp<int>(pan * 127 + 127, 0, 255));
121
- }
122
-
123
- void Gosu::SampleInstance::changeSpeed(double speed)
124
- {
125
- FSOUND_SetFrequency(handle, clamp<int>(speed * extra, 100, 705600));
126
- }
127
-
128
- struct Gosu::Sample::SampleData : boost::noncopyable
129
- {
130
- FSOUND_SAMPLE* rep;
131
-
132
- SampleData()
133
- : rep(0)
134
- {
135
- }
136
-
137
- ~SampleData()
138
- {
139
- if (rep != 0)
140
- FSOUND_Sample_Free(rep);
141
- }
142
- };
143
-
144
- Gosu::Sample::Sample(const std::wstring& filename)
145
- {
146
- requireFMOD();
147
-
148
- Buffer buf;
149
- loadFile(buf, filename);
150
-
151
- // Forward.
152
- Sample(buf.frontReader()).data.swap(data);
153
- }
154
-
155
- Gosu::Sample::Sample(Reader reader)
156
- {
157
- requireFMOD();
158
-
159
- std::vector<char> buffer(reader.resource().size() - reader.position());
160
- reader.read(&buffer.front(), buffer.size());
161
-
162
- data.reset(new SampleData);
163
- data->rep = FSOUND_Sample_Load(FSOUND_FREE | FSOUND_UNMANAGED,
164
- &buffer.front(), FSOUND_NORMAL | FSOUND_LOADMEMORY, 0, buffer.size());
165
- if (data->rep == 0)
166
- throwLastFMODError();
167
- }
168
-
169
- Gosu::SampleInstance Gosu::Sample::play(double volume, double speed,
170
- bool looping) const
171
- {
172
- int handle = FSOUND_PlaySound(FSOUND_FREE, data->rep);
173
- int freq;
174
- if (handle > 0)
175
- {
176
- if (looping)
177
- FSOUND_SetLoopMode(handle, FSOUND_LOOP_NORMAL);
178
- freq = FSOUND_GetFrequency(handle);
179
- FSOUND_SetPan(handle, FSOUND_STEREOPAN);
180
- }
181
-
182
- SampleInstance result(handle, freq);
183
- result.changeVolume(volume);
184
- result.changeSpeed(speed);
185
- return result;
186
- }
187
-
188
- Gosu::SampleInstance Gosu::Sample::playPan(double pan, double volume,
189
- double speed, bool looping) const
190
- {
191
- int handle = FSOUND_PlaySound(FSOUND_FREE, data->rep);
192
- int freq;
193
- if (handle > 0)
194
- {
195
- if (looping)
196
- FSOUND_SetLoopMode(handle, FSOUND_LOOP_NORMAL);
197
- freq = FSOUND_GetFrequency(handle);
198
- }
199
-
200
- SampleInstance result(handle, freq);
201
- result.changeVolume(volume);
202
- result.changePan(pan);
203
- result.changeSpeed(speed);
204
- return result;
205
- }
206
-
207
- class Gosu::Song::BaseData : boost::noncopyable
208
- {
209
- double volume_;
210
-
211
- protected:
212
- BaseData() : volume_(1) {}
213
- virtual void applyVolume() = 0;
214
-
215
- public:
216
- virtual ~BaseData() {}
217
-
218
- virtual void play(bool looping) = 0;
219
- virtual void pause() = 0;
220
- virtual bool paused() const = 0;
221
- virtual void stop() = 0;
222
-
223
- double volume() const
224
- {
225
- return volume_;
226
- }
227
-
228
- void changeVolume(double volume)
229
- {
230
- volume_ = clamp(volume, 0.0, 1.0);
231
- applyVolume();
232
- }
233
- };
234
-
235
- class Gosu::Song::StreamData : public BaseData
236
- {
237
- FSOUND_STREAM* stream;
238
- int handle;
239
- std::vector<char> buffer;
240
-
241
- static signed char F_CALLBACKAPI endSongCallback(FSOUND_STREAM*, void*,
242
- int, void* self)
243
- {
244
- curSong = 0;
245
- static_cast<StreamData*>(self)->handle = -1;
246
- return 0;
247
- }
248
-
249
- public:
250
- StreamData(Gosu::Reader reader)
251
- : stream(0), handle(-1)
252
- {
253
- buffer.resize(reader.resource().size() - reader.position());
254
- reader.read(&buffer[0], buffer.size());
255
-
256
- // Disabled for licensing reasons.
257
- // If you have a license to play MP3 files, compile with GOSU_ALLOW_MP3.
258
- #ifndef GOSU_ALLOW_MP3
259
- if (buffer.size() > 2 &&
260
- ((buffer[0] == '\xff' && (buffer[1] & 0xfe) == '\xfa') ||
261
- (buffer[0] == 'I' && buffer[1] == 'D' && buffer[2] == '3')))
262
- {
263
- throw std::runtime_error("MP3 file playback not allowed");
264
- }
265
- #endif
266
-
267
- stream = FSOUND_Stream_Open(&buffer[0], FSOUND_LOADMEMORY | FSOUND_LOOP_NORMAL,
268
- 0, buffer.size());
269
- if (stream == 0)
270
- throwLastFMODError();
271
-
272
- FSOUND_Stream_SetEndCallback(stream, endSongCallback, this);
273
- }
274
-
275
- ~StreamData()
276
- {
277
- if (stream != 0)
278
- FSOUND_Stream_Close(stream);
279
- }
280
-
281
- void play(bool looping)
282
- {
283
- if (handle == -1)
284
- {
285
- handle = FSOUND_Stream_Play(FSOUND_FREE, stream);
286
- FSOUND_Stream_SetLoopCount(stream, looping ? -1 : 0);
287
- }
288
- else if (paused())
289
- FSOUND_SetPaused(handle, 0);
290
- applyVolume();
291
- }
292
-
293
- void pause()
294
- {
295
- if (handle != -1)
296
- FSOUND_SetPaused(handle, 1);
297
- }
298
-
299
- bool paused() const
300
- {
301
- return handle != -1 && FSOUND_GetPaused(handle);
302
- }
303
-
304
- void stop()
305
- {
306
- fmodCheck(FSOUND_Stream_Stop(stream));
307
- handle = -1; // The end callback is NOT being called!
308
- }
309
-
310
- void applyVolume()
311
- {
312
- if (handle != -1)
313
- FSOUND_SetVolume(handle, static_cast<int>(volume() * 255));
314
- }
315
- };
316
-
317
- class Gosu::Song::ModuleData : public Gosu::Song::BaseData
318
- {
319
- FMUSIC_MODULE* module_;
320
-
321
- public:
322
- ModuleData(Reader reader)
323
- : module_(0)
324
- {
325
- std::vector<char> buffer(reader.resource().size() - reader.position());
326
- reader.read(&buffer[0], buffer.size());
327
-
328
- module_ = FMUSIC_LoadSongEx(&buffer[0], 0, buffer.size(),
329
- FSOUND_LOADMEMORY | FSOUND_LOOP_OFF, 0, 0);
330
- if (module_ == 0)
331
- throwLastFMODError();
332
- }
333
-
334
- ~ModuleData()
335
- {
336
- if (module_ != 0)
337
- FMUSIC_FreeSong(module_);
338
- }
339
-
340
- void play(bool looping)
341
- {
342
- if (paused())
343
- FMUSIC_SetPaused(module_, 0);
344
- else
345
- FMUSIC_PlaySong(module_);
346
- FMUSIC_SetLooping(module_, looping);
347
- applyVolume();
348
- }
349
-
350
- void pause()
351
- {
352
- FMUSIC_SetPaused(module_, 1);
353
- }
354
-
355
- bool paused() const
356
- {
357
- return FMUSIC_GetPaused(module_);
358
- }
359
-
360
- void stop()
361
- {
362
- fmodCheck(FMUSIC_StopSong(module_));
363
- FMUSIC_SetPaused(module_, false);
364
- }
365
-
366
- void applyVolume()
367
- {
368
- // Weird as it may seem, the FMOD doc really says volume can
369
- // be 0 to 256, *inclusive*, for this function.
370
- FMUSIC_SetMasterVolume(module_, static_cast<int>(volume() * 256.0));
371
- }
372
- };
373
-
374
- Gosu::Song::Song(const std::wstring& filename)
375
- {
376
- requireFMOD();
377
-
378
- Buffer buf;
379
- loadFile(buf, filename);
380
- Type type = stStream;
381
-
382
- using boost::iends_with;
383
- if (iends_with(filename, ".mod") || iends_with(filename, ".mid") ||
384
- iends_with(filename, ".s3m") || iends_with(filename, ".it") ||
385
- iends_with(filename, ".xm"))
386
- {
387
- type = stModule;
388
- }
389
-
390
- // Forward.
391
- Song(type, buf.frontReader()).data.swap(data);
392
- }
393
-
394
- Gosu::Song::Song(Type type, Reader reader)
395
- {
396
- requireFMOD();
397
-
398
- switch (type)
399
- {
400
- case stStream:
401
- data.reset(new StreamData(reader));
402
- break;
403
-
404
- case stModule:
405
- data.reset(new ModuleData(reader));
406
- break;
407
-
408
- default:
409
- throw std::logic_error("Invalid song type");
410
- }
411
- }
412
-
413
- Gosu::Song::~Song()
414
- {
415
- }
416
-
417
- Gosu::Song* Gosu::Song::currentSong()
418
- {
419
- return curSong;
420
- }
421
-
422
- void Gosu::Song::play(bool looping)
423
- {
424
- if (curSong && curSong != this)
425
- {
426
- curSong->stop();
427
- assert(curSong == 0);
428
- }
429
-
430
- data->play(looping);
431
- curSong = this; // may be redundant
432
- }
433
-
434
- void Gosu::Song::pause()
435
- {
436
- if (curSong == this)
437
- data->pause(); // may be redundant
438
- }
439
-
440
- bool Gosu::Song::paused() const
441
- {
442
- return curSong == this && data->paused();
443
- }
444
-
445
- void Gosu::Song::stop()
446
- {
447
- if (curSong == this)
448
- {
449
- data->stop();
450
- curSong = 0;
451
- }
452
- }
453
-
454
- bool Gosu::Song::playing() const
455
- {
456
- return curSong == this && !data->paused();
457
- }
458
-
459
- double Gosu::Song::volume() const
460
- {
461
- return data->volume();
462
- }
463
-
464
- void Gosu::Song::changeVolume(double volume)
465
- {
466
- data->changeVolume(volume);
467
- }
468
-
469
- void Gosu::Song::update()
470
- {
471
- }
472
-
473
- // Deprecated constructors.
474
-
475
- Gosu::Sample::Sample(Audio& audio, const std::wstring& filename)
476
- {
477
- Sample(filename).data.swap(data);
478
- }
479
-
480
- Gosu::Sample::Sample(Audio& audio, Reader reader)
481
- {
482
- Sample(reader).data.swap(data);
483
- }
484
-
485
- Gosu::Song::Song(Audio& audio, const std::wstring& filename)
486
- {
487
- Song(filename).data.swap(data);
488
- }
489
-
490
- Gosu::Song::Song(Audio& audio, Type type, Reader reader)
491
- {
492
- Song(type, reader).data.swap(data);
493
- }