gosu 0.15.2 → 1.1.0.pre2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/dependencies/SDL/include/SDL.h +138 -0
- data/dependencies/SDL/include/SDL_assert.h +293 -0
- data/dependencies/SDL/include/SDL_atomic.h +295 -0
- data/dependencies/SDL/include/SDL_audio.h +859 -0
- data/dependencies/SDL/include/SDL_bits.h +121 -0
- data/dependencies/SDL/include/SDL_blendmode.h +123 -0
- data/dependencies/SDL/include/SDL_clipboard.h +71 -0
- data/dependencies/SDL/include/SDL_config.h +55 -0
- data/dependencies/SDL/include/SDL_config_android.h +182 -0
- data/dependencies/SDL/include/SDL_config_iphoneos.h +207 -0
- data/dependencies/SDL/include/SDL_config_macosx.h +266 -0
- data/dependencies/SDL/include/SDL_config_minimal.h +85 -0
- data/dependencies/SDL/include/SDL_config_os2.h +188 -0
- data/dependencies/SDL/include/SDL_config_pandora.h +135 -0
- data/dependencies/SDL/include/SDL_config_psp.h +165 -0
- data/dependencies/SDL/include/SDL_config_windows.h +288 -0
- data/dependencies/SDL/include/SDL_config_winrt.h +243 -0
- data/dependencies/SDL/include/SDL_config_wiz.h +149 -0
- data/dependencies/SDL/include/SDL_copying.h +20 -0
- data/dependencies/SDL/include/SDL_cpuinfo.h +299 -0
- data/dependencies/SDL/include/SDL_egl.h +1676 -0
- data/dependencies/SDL/include/SDL_endian.h +263 -0
- data/dependencies/SDL/include/SDL_error.h +112 -0
- data/dependencies/SDL/include/SDL_events.h +827 -0
- data/dependencies/SDL/include/SDL_filesystem.h +136 -0
- data/dependencies/SDL/include/SDL_gamecontroller.h +541 -0
- data/dependencies/SDL/include/SDL_gesture.h +87 -0
- data/dependencies/SDL/include/SDL_haptic.h +1247 -0
- data/dependencies/SDL/include/SDL_hints.h +1578 -0
- data/dependencies/SDL/include/SDL_joystick.h +499 -0
- data/dependencies/SDL/include/SDL_keyboard.h +217 -0
- data/dependencies/SDL/include/SDL_keycode.h +351 -0
- data/dependencies/SDL/include/SDL_loadso.h +81 -0
- data/dependencies/SDL/include/SDL_locale.h +101 -0
- data/dependencies/SDL/include/SDL_log.h +211 -0
- data/dependencies/SDL/include/SDL_main.h +180 -0
- data/dependencies/SDL/include/SDL_messagebox.h +146 -0
- data/dependencies/SDL/include/SDL_metal.h +117 -0
- data/dependencies/SDL/include/SDL_misc.h +75 -0
- data/dependencies/SDL/include/SDL_mouse.h +302 -0
- data/dependencies/SDL/include/SDL_mutex.h +251 -0
- data/dependencies/SDL/include/SDL_name.h +33 -0
- data/dependencies/SDL/include/SDL_opengl.h +2183 -0
- data/dependencies/SDL/include/SDL_opengl_glext.h +11180 -0
- data/dependencies/SDL/include/SDL_opengles.h +39 -0
- data/dependencies/SDL/include/SDL_opengles2.h +52 -0
- data/dependencies/SDL/include/SDL_opengles2_gl2.h +621 -0
- data/dependencies/SDL/include/SDL_opengles2_gl2ext.h +2050 -0
- data/dependencies/SDL/include/SDL_opengles2_gl2platform.h +30 -0
- data/dependencies/SDL/include/SDL_opengles2_khrplatform.h +282 -0
- data/dependencies/SDL/include/SDL_pixels.h +479 -0
- data/dependencies/SDL/include/SDL_platform.h +198 -0
- data/dependencies/SDL/include/SDL_power.h +75 -0
- data/dependencies/SDL/include/SDL_quit.h +58 -0
- data/dependencies/SDL/include/SDL_rect.h +174 -0
- data/dependencies/SDL/include/SDL_render.h +1158 -0
- data/dependencies/SDL/include/SDL_revision.h +2 -0
- data/dependencies/SDL/include/SDL_rwops.h +283 -0
- data/dependencies/SDL/include/SDL_scancode.h +413 -0
- data/dependencies/SDL/include/SDL_sensor.h +267 -0
- data/dependencies/SDL/include/SDL_shape.h +144 -0
- data/dependencies/SDL/include/SDL_stdinc.h +647 -0
- data/dependencies/SDL/include/SDL_surface.h +563 -0
- data/dependencies/SDL/include/SDL_system.h +325 -0
- data/dependencies/SDL/include/SDL_syswm.h +354 -0
- data/dependencies/SDL/include/SDL_test.h +69 -0
- data/dependencies/SDL/include/SDL_test_assert.h +105 -0
- data/dependencies/SDL/include/SDL_test_common.h +218 -0
- data/dependencies/SDL/include/SDL_test_compare.h +69 -0
- data/dependencies/SDL/include/SDL_test_crc32.h +124 -0
- data/dependencies/SDL/include/SDL_test_font.h +81 -0
- data/dependencies/SDL/include/SDL_test_fuzzer.h +384 -0
- data/dependencies/SDL/include/SDL_test_harness.h +134 -0
- data/dependencies/SDL/include/SDL_test_images.h +78 -0
- data/dependencies/SDL/include/SDL_test_log.h +67 -0
- data/dependencies/SDL/include/SDL_test_md5.h +129 -0
- data/dependencies/SDL/include/SDL_test_memory.h +63 -0
- data/dependencies/SDL/include/SDL_test_random.h +115 -0
- data/dependencies/SDL/include/SDL_thread.h +366 -0
- data/dependencies/SDL/include/SDL_timer.h +115 -0
- data/dependencies/SDL/include/SDL_touch.h +102 -0
- data/dependencies/SDL/include/SDL_types.h +29 -0
- data/dependencies/SDL/include/SDL_version.h +162 -0
- data/dependencies/SDL/include/SDL_video.h +1282 -0
- data/dependencies/SDL/include/SDL_vulkan.h +276 -0
- data/dependencies/SDL/include/begin_code.h +166 -0
- data/dependencies/SDL/include/close_code.h +40 -0
- data/dependencies/SDL/lib/x64/libSDL2.dll.a +0 -0
- data/dependencies/SDL/lib/x86/libSDL2.dll.a +0 -0
- data/dependencies/SDL_sound/SDL_sound.c +795 -0
- data/dependencies/SDL_sound/SDL_sound.h +725 -0
- data/dependencies/SDL_sound/SDL_sound_aiff.c +537 -0
- data/dependencies/SDL_sound/SDL_sound_au.c +352 -0
- data/dependencies/SDL_sound/SDL_sound_coreaudio.c +747 -0
- data/dependencies/SDL_sound/SDL_sound_flac.c +182 -0
- data/dependencies/SDL_sound/SDL_sound_internal.h +304 -0
- data/dependencies/SDL_sound/SDL_sound_modplug.c +228 -0
- data/dependencies/SDL_sound/SDL_sound_mp3.c +184 -0
- data/dependencies/SDL_sound/SDL_sound_raw.c +164 -0
- data/dependencies/SDL_sound/SDL_sound_shn.c +1309 -0
- data/dependencies/SDL_sound/SDL_sound_voc.c +550 -0
- data/dependencies/SDL_sound/SDL_sound_vorbis.c +223 -0
- data/dependencies/SDL_sound/SDL_sound_wav.c +783 -0
- data/dependencies/SDL_sound/dr_flac.h +5906 -0
- data/dependencies/SDL_sound/dr_mp3.h +2832 -0
- data/dependencies/SDL_sound/libmodplug/fastmix.c +1748 -0
- data/dependencies/SDL_sound/libmodplug/libmodplug.h +1001 -0
- data/dependencies/SDL_sound/libmodplug/load_669.c +188 -0
- data/dependencies/SDL_sound/libmodplug/load_abc.c +4725 -0
- data/dependencies/SDL_sound/libmodplug/load_amf.c +403 -0
- data/dependencies/SDL_sound/libmodplug/load_ams.c +587 -0
- data/dependencies/SDL_sound/libmodplug/load_dbm.c +357 -0
- data/dependencies/SDL_sound/libmodplug/load_dmf.c +531 -0
- data/dependencies/SDL_sound/libmodplug/load_dsm.c +232 -0
- data/dependencies/SDL_sound/libmodplug/load_far.c +253 -0
- data/dependencies/SDL_sound/libmodplug/load_it.c +796 -0
- data/dependencies/SDL_sound/libmodplug/load_mdl.c +488 -0
- data/dependencies/SDL_sound/libmodplug/load_med.c +757 -0
- data/dependencies/SDL_sound/libmodplug/load_mid.c +1405 -0
- data/dependencies/SDL_sound/libmodplug/load_mod.c +269 -0
- data/dependencies/SDL_sound/libmodplug/load_mt2.c +546 -0
- data/dependencies/SDL_sound/libmodplug/load_mtm.c +142 -0
- data/dependencies/SDL_sound/libmodplug/load_okt.c +192 -0
- data/dependencies/SDL_sound/libmodplug/load_pat.c +1143 -0
- data/dependencies/SDL_sound/libmodplug/load_pat.h +25 -0
- data/dependencies/SDL_sound/libmodplug/load_psm.c +350 -0
- data/dependencies/SDL_sound/libmodplug/load_ptm.c +204 -0
- data/dependencies/SDL_sound/libmodplug/load_s3m.c +325 -0
- data/dependencies/SDL_sound/libmodplug/load_stm.c +180 -0
- data/dependencies/SDL_sound/libmodplug/load_ult.c +206 -0
- data/dependencies/SDL_sound/libmodplug/load_umx.c +51 -0
- data/dependencies/SDL_sound/libmodplug/load_xm.c +554 -0
- data/dependencies/SDL_sound/libmodplug/mmcmp.c +382 -0
- data/dependencies/SDL_sound/libmodplug/modplug.c +170 -0
- data/dependencies/SDL_sound/libmodplug/modplug.h +90 -0
- data/dependencies/SDL_sound/libmodplug/snd_dsp.c +301 -0
- data/dependencies/SDL_sound/libmodplug/snd_flt.c +63 -0
- data/dependencies/SDL_sound/libmodplug/snd_fx.c +2350 -0
- data/dependencies/SDL_sound/libmodplug/sndfile.c +1169 -0
- data/dependencies/SDL_sound/libmodplug/sndmix.c +1034 -0
- data/dependencies/SDL_sound/libmodplug/tables.h +371 -0
- data/{src/stb_vorbis.c → dependencies/SDL_sound/stb_vorbis.h} +143 -78
- data/dependencies/al_soft/AL/al.h +655 -0
- data/dependencies/al_soft/AL/alc.h +270 -0
- data/dependencies/al_soft/AL/alext.h +585 -0
- data/dependencies/al_soft/AL/efx-creative.h +3 -0
- data/dependencies/al_soft/AL/efx-presets.h +402 -0
- data/dependencies/al_soft/AL/efx.h +762 -0
- data/dependencies/al_soft/x64/libOpenAL32.dll.a +0 -0
- data/dependencies/al_soft/x86/libOpenAL32.dll.a +0 -0
- data/{src → dependencies/stb}/stb_image.h +330 -127
- data/{src → dependencies/stb}/stb_image_write.h +156 -85
- data/{src → dependencies/stb}/stb_truetype.h +192 -69
- data/{src → dependencies/utf8proc}/utf8proc.c +0 -0
- data/{src → dependencies/utf8proc}/utf8proc.h +0 -0
- data/{src → dependencies/utf8proc}/utf8proc_data.h +0 -0
- data/ext/gosu/extconf.rb +53 -39
- data/{Gosu → include/Gosu}/Audio.hpp +6 -8
- data/include/Gosu/Bitmap.hpp +100 -0
- data/{Gosu → include/Gosu}/Buttons.hpp +104 -44
- data/{Gosu → include/Gosu}/Color.hpp +0 -0
- data/{Gosu → include/Gosu}/Directories.hpp +0 -0
- data/{Gosu → include/Gosu}/Font.hpp +1 -1
- data/{Gosu → include/Gosu}/Fwd.hpp +0 -5
- data/{Gosu → include/Gosu}/Gosu.hpp +0 -0
- data/{Gosu → include/Gosu}/Graphics.hpp +0 -0
- data/{Gosu → include/Gosu}/GraphicsBase.hpp +0 -0
- data/{Gosu → include/Gosu}/IO.hpp +0 -0
- data/{Gosu → include/Gosu}/Image.hpp +7 -6
- data/{Gosu → include/Gosu}/ImageData.hpp +0 -0
- data/{Gosu → include/Gosu}/Input.hpp +39 -51
- data/{Gosu → include/Gosu}/Inspection.hpp +0 -0
- data/{Gosu → include/Gosu}/Math.hpp +0 -0
- data/{Gosu → include/Gosu}/Platform.hpp +0 -0
- data/{Gosu → include/Gosu}/Text.hpp +0 -0
- data/{Gosu → include/Gosu}/TextInput.hpp +0 -0
- data/{Gosu → include/Gosu}/Timing.hpp +0 -0
- data/{Gosu → include/Gosu}/Utility.hpp +15 -4
- data/{Gosu → include/Gosu}/Version.hpp +3 -3
- data/{Gosu → include/Gosu}/Window.hpp +46 -34
- data/lib/OpenAL32.dll +0 -0
- data/lib/SDL2.dll +0 -0
- data/lib/gosu.rb +0 -3
- data/lib/gosu/patches.rb +0 -23
- data/lib/gosu/preview.rb +1 -3
- data/lib/gosu/swig_patches.rb +14 -12
- data/lib64/OpenAL32.dll +0 -0
- data/lib64/SDL2.dll +0 -0
- data/rdoc/gosu.rb +112 -23
- data/src/Audio.cpp +50 -224
- data/src/AudioFile.hpp +20 -37
- data/src/AudioFileAudioToolbox.cpp +237 -0
- data/src/AudioFileSDLSound.cpp +147 -0
- data/src/AudioImpl.cpp +3 -12
- data/src/AudioImpl.hpp +3 -1
- data/src/Bitmap.cpp +85 -83
- data/src/BitmapIO.cpp +52 -58
- data/src/Font.cpp +3 -1
- data/src/Graphics.cpp +7 -4
- data/src/Image.cpp +13 -16
- data/src/Input.cpp +412 -164
- data/src/LargeImageData.cpp +1 -1
- data/src/MarkupParser.cpp +2 -1
- data/src/Resolution.cpp +8 -8
- data/src/RubyGosu.cxx +1017 -196
- data/src/RubyGosu.h +4 -2
- data/src/TexChunk.cpp +1 -1
- data/src/TextBuilder.cpp +3 -1
- data/src/Texture.cpp +1 -1
- data/src/TrueTypeFont.cpp +1 -1
- data/src/TrueTypeFontWin.cpp +3 -3
- data/src/Utility.cpp +11 -7
- data/src/Window.cpp +90 -62
- data/src/WindowUIKit.cpp +21 -9
- metadata +194 -65
- data/Gosu/AutoLink.hpp +0 -14
- data/Gosu/Bitmap.hpp +0 -113
- data/Gosu/Channel.h +0 -25
- data/Gosu/Color.h +0 -38
- data/Gosu/Font.h +0 -36
- data/Gosu/Gosu.h +0 -79
- data/Gosu/Image.h +0 -54
- data/Gosu/Sample.h +0 -19
- data/Gosu/Song.h +0 -24
- data/Gosu/TextInput.h +0 -30
- data/Gosu/Window.h +0 -61
- data/lib/gosu/zen.rb +0 -89
- data/src/AudioToolboxFile.hpp +0 -210
- data/src/ChannelWrapper.cpp +0 -50
- data/src/ColorWrapper.cpp +0 -126
- data/src/Constants.cpp +0 -287
- data/src/FontWrapper.cpp +0 -74
- data/src/GosuWrapper.cpp +0 -232
- data/src/ImageWrapper.cpp +0 -168
- data/src/MPEGFile.hpp +0 -90
- data/src/OggFile.hpp +0 -92
- data/src/SampleWrapper.cpp +0 -30
- data/src/SndFile.hpp +0 -174
- data/src/SongWrapper.cpp +0 -52
- data/src/TextInputWrapper.cpp +0 -101
- data/src/WinMain.cpp +0 -64
- data/src/WindowWrapper.cpp +0 -289
@@ -0,0 +1,223 @@
|
|
1
|
+
/**
|
2
|
+
* SDL_sound; A sound processing toolkit.
|
3
|
+
*
|
4
|
+
* Please see the file LICENSE.txt in the source's root directory.
|
5
|
+
*
|
6
|
+
* This file written by Ryan C. Gordon.
|
7
|
+
*/
|
8
|
+
|
9
|
+
/*
|
10
|
+
* Ogg Vorbis decoder for SDL_sound.
|
11
|
+
*
|
12
|
+
* This driver handles .OGG audio files, and uses Sean Barrett's excellent
|
13
|
+
* stb_vorbis for the heavy lifting. Since stb_vorbis is a single,
|
14
|
+
* public domain C header file, it's just compiled into this source and
|
15
|
+
* needs no external dependencies.
|
16
|
+
*
|
17
|
+
* stb_vorbis homepage: https://nothings.org/stb_vorbis/
|
18
|
+
*/
|
19
|
+
|
20
|
+
#define __SDL_SOUND_INTERNAL__
|
21
|
+
#include "SDL_sound_internal.h"
|
22
|
+
|
23
|
+
#if SOUND_SUPPORTS_VORBIS
|
24
|
+
|
25
|
+
/* Configure and include stb_vorbis for compiling... */
|
26
|
+
#define STB_VORBIS_NO_STDIO 1
|
27
|
+
#define STB_VORBIS_NO_CRT 1
|
28
|
+
#define STB_VORBIS_NO_PUSHDATA_API 1
|
29
|
+
#define STB_VORBIS_MAX_CHANNELS 6
|
30
|
+
#define STBV_CDECL
|
31
|
+
#define STB_FORCEINLINE SDL_FORCE_INLINE
|
32
|
+
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
33
|
+
#define STB_VORBIS_BIG_ENDIAN 1
|
34
|
+
#endif
|
35
|
+
|
36
|
+
#if !defined(__clang_analyzer__)
|
37
|
+
#ifdef assert
|
38
|
+
#undef assert
|
39
|
+
#endif
|
40
|
+
#ifdef memset
|
41
|
+
#undef memset
|
42
|
+
#endif
|
43
|
+
#ifdef memcpy
|
44
|
+
#undef memcpy
|
45
|
+
#endif
|
46
|
+
#ifdef alloca
|
47
|
+
#undef alloca
|
48
|
+
#endif
|
49
|
+
#define assert SDL_assert
|
50
|
+
#define memset SDL_memset
|
51
|
+
#define memcmp SDL_memcmp
|
52
|
+
#define memcpy SDL_memcpy
|
53
|
+
#define qsort SDL_qsort
|
54
|
+
#define pow SDL_pow
|
55
|
+
#define floor SDL_floor
|
56
|
+
#define malloc SDL_malloc
|
57
|
+
#define realloc SDL_realloc
|
58
|
+
#define free SDL_free
|
59
|
+
#define alloca(x) ((void *) SDL_stack_alloc(Uint8, (x)))
|
60
|
+
#define dealloca(x) SDL_stack_free((x))
|
61
|
+
#define ldexp(v, e) SDL_scalbn((v), (e))
|
62
|
+
#define abs(x) SDL_abs(x)
|
63
|
+
#define cos(x) SDL_cos(x)
|
64
|
+
#define sin(x) SDL_sin(x)
|
65
|
+
#define log(x) SDL_log(x)
|
66
|
+
#endif
|
67
|
+
#include "stb_vorbis.h"
|
68
|
+
|
69
|
+
static const char *vorbis_error_string(const int err)
|
70
|
+
{
|
71
|
+
switch (err)
|
72
|
+
{
|
73
|
+
case VORBIS__no_error: return NULL;
|
74
|
+
case VORBIS_need_more_data: return "VORBIS: need more data";
|
75
|
+
case VORBIS_invalid_api_mixing: return "VORBIS: can't mix API modes";
|
76
|
+
case VORBIS_outofmem: return "VORBIS: out of memory";
|
77
|
+
case VORBIS_feature_not_supported: return "VORBIS: feature not supported";
|
78
|
+
case VORBIS_too_many_channels: return "VORBIS: too many channels";
|
79
|
+
case VORBIS_seek_without_length: return "VORBIS: can't seek in unknown length stream";
|
80
|
+
case VORBIS_unexpected_eof: return "VORBIS: unexpected eof";
|
81
|
+
case VORBIS_seek_invalid: return "VORBIS: invalid seek";
|
82
|
+
case VORBIS_invalid_setup: return "VORBIS: invalid setup";
|
83
|
+
case VORBIS_invalid_stream: return "VORBIS: invalid stream";
|
84
|
+
case VORBIS_missing_capture_pattern: return "VORBIS: missing capture pattern";
|
85
|
+
case VORBIS_invalid_stream_structure_version: return "VORBIS: invalid stream structure version";
|
86
|
+
case VORBIS_continued_packet_flag_invalid: return "VORBIS: continued packet flag invalid";
|
87
|
+
case VORBIS_incorrect_stream_serial_number: return "VORBIS: incorrect stream serial number";
|
88
|
+
case VORBIS_invalid_first_page: return "VORBIS: invalid first page";
|
89
|
+
case VORBIS_bad_packet_type: return "VORBIS: bad packet type";
|
90
|
+
case VORBIS_cant_find_last_page: return "VORBIS: can't find last page";
|
91
|
+
case VORBIS_seek_failed: return "VORBIS: seek failed";
|
92
|
+
default: break;
|
93
|
+
} /* switch */
|
94
|
+
|
95
|
+
return "VORBIS: unknown error";
|
96
|
+
} /* vorbis_error_string */
|
97
|
+
|
98
|
+
static int VORBIS_init(void)
|
99
|
+
{
|
100
|
+
return 1; /* always succeeds. */
|
101
|
+
} /* VORBIS_init */
|
102
|
+
|
103
|
+
static void VORBIS_quit(void)
|
104
|
+
{
|
105
|
+
/* it's a no-op. */
|
106
|
+
} /* VORBIS_quit */
|
107
|
+
|
108
|
+
static int VORBIS_open(Sound_Sample *sample, const char *ext)
|
109
|
+
{
|
110
|
+
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
|
111
|
+
SDL_RWops *rw = internal->rw;
|
112
|
+
int err = 0;
|
113
|
+
stb_vorbis *stb = stb_vorbis_open_rwops(rw, 0, &err, NULL);
|
114
|
+
unsigned int num_frames;
|
115
|
+
|
116
|
+
BAIL_IF_MACRO(!stb, vorbis_error_string(err), 0);
|
117
|
+
|
118
|
+
SNDDBG(("VORBIS: Accepting data stream.\n"));
|
119
|
+
|
120
|
+
internal->decoder_private = stb;
|
121
|
+
sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
|
122
|
+
sample->actual.format = AUDIO_F32SYS;
|
123
|
+
sample->actual.channels = stb->channels;
|
124
|
+
sample->actual.rate = stb->sample_rate;
|
125
|
+
num_frames = stb_vorbis_stream_length_in_samples(stb);
|
126
|
+
if (!num_frames)
|
127
|
+
internal->total_time = -1;
|
128
|
+
else
|
129
|
+
{
|
130
|
+
const unsigned int rate = stb->sample_rate;
|
131
|
+
internal->total_time = (num_frames / rate) * 1000;
|
132
|
+
internal->total_time += (num_frames % rate) * 1000 / rate;
|
133
|
+
} /* else */
|
134
|
+
|
135
|
+
return 1; /* we'll handle this data. */
|
136
|
+
} /* VORBIS_open */
|
137
|
+
|
138
|
+
|
139
|
+
static void VORBIS_close(Sound_Sample *sample)
|
140
|
+
{
|
141
|
+
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
|
142
|
+
stb_vorbis *stb = (stb_vorbis *) internal->decoder_private;
|
143
|
+
stb_vorbis_close(stb);
|
144
|
+
} /* VORBIS_close */
|
145
|
+
|
146
|
+
|
147
|
+
static Uint32 VORBIS_read(Sound_Sample *sample)
|
148
|
+
{
|
149
|
+
Uint32 retval;
|
150
|
+
int rc;
|
151
|
+
int err;
|
152
|
+
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
|
153
|
+
stb_vorbis *stb = (stb_vorbis *) internal->decoder_private;
|
154
|
+
const int channels = (int) sample->actual.channels;
|
155
|
+
const int want_samples = (int) (internal->buffer_size / sizeof (float));
|
156
|
+
|
157
|
+
stb_vorbis_get_error(stb); /* clear any error state */
|
158
|
+
rc = stb_vorbis_get_samples_float_interleaved(stb, channels, (float *) internal->buffer, want_samples);
|
159
|
+
retval = (Uint32) (rc * channels * sizeof (float)); /* rc == number of sample frames read */
|
160
|
+
err = stb_vorbis_get_error(stb);
|
161
|
+
|
162
|
+
if (retval == 0)
|
163
|
+
{
|
164
|
+
if (!err)
|
165
|
+
sample->flags |= SOUND_SAMPLEFLAG_EOF;
|
166
|
+
else
|
167
|
+
{
|
168
|
+
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
|
169
|
+
/* !!! FIXME: should I set this? __Sound_SetError(vorbis_error_string(err)); */
|
170
|
+
} /* else */
|
171
|
+
} /* if */
|
172
|
+
|
173
|
+
else if (retval < internal->buffer_size)
|
174
|
+
sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
|
175
|
+
|
176
|
+
return retval;
|
177
|
+
} /* VORBIS_read */
|
178
|
+
|
179
|
+
|
180
|
+
static int VORBIS_rewind(Sound_Sample *sample)
|
181
|
+
{
|
182
|
+
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
|
183
|
+
stb_vorbis *stb = (stb_vorbis *) internal->decoder_private;
|
184
|
+
BAIL_IF_MACRO(!stb_vorbis_seek_start(stb), vorbis_error_string(stb_vorbis_get_error(stb)), 0);
|
185
|
+
return 1;
|
186
|
+
} /* VORBIS_rewind */
|
187
|
+
|
188
|
+
|
189
|
+
static int VORBIS_seek(Sound_Sample *sample, Uint32 ms)
|
190
|
+
{
|
191
|
+
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
|
192
|
+
stb_vorbis *stb = (stb_vorbis *) internal->decoder_private;
|
193
|
+
const float frames_per_ms = ((float) sample->actual.rate) / 1000.0f;
|
194
|
+
const Uint32 frame_offset = (Uint32) (frames_per_ms * ((float) ms));
|
195
|
+
const unsigned int sampnum = (unsigned int) frame_offset;
|
196
|
+
BAIL_IF_MACRO(!stb_vorbis_seek(stb, sampnum), vorbis_error_string(stb_vorbis_get_error(stb)), 0);
|
197
|
+
return 1;
|
198
|
+
} /* VORBIS_seek */
|
199
|
+
|
200
|
+
|
201
|
+
static const char *extensions_vorbis[] = { "OGG", NULL };
|
202
|
+
const Sound_DecoderFunctions __Sound_DecoderFunctions_VORBIS =
|
203
|
+
{
|
204
|
+
{
|
205
|
+
extensions_vorbis,
|
206
|
+
"Ogg Vorbis audio",
|
207
|
+
"Ryan C. Gordon <icculus@icculus.org>",
|
208
|
+
"https://icculus.org/SDL_sound/"
|
209
|
+
},
|
210
|
+
|
211
|
+
VORBIS_init, /* init() method */
|
212
|
+
VORBIS_quit, /* quit() method */
|
213
|
+
VORBIS_open, /* open() method */
|
214
|
+
VORBIS_close, /* close() method */
|
215
|
+
VORBIS_read, /* read() method */
|
216
|
+
VORBIS_rewind, /* rewind() method */
|
217
|
+
VORBIS_seek /* seek() method */
|
218
|
+
};
|
219
|
+
|
220
|
+
#endif /* SOUND_SUPPORTS_VORBIS */
|
221
|
+
|
222
|
+
/* end of SDL_sound_vorbis.c ... */
|
223
|
+
|
@@ -0,0 +1,783 @@
|
|
1
|
+
/**
|
2
|
+
* SDL_sound; A sound processing toolkit.
|
3
|
+
*
|
4
|
+
* Please see the file LICENSE.txt in the source's root directory.
|
5
|
+
*
|
6
|
+
* This file written by Ryan C. Gordon.
|
7
|
+
*/
|
8
|
+
|
9
|
+
/*
|
10
|
+
* WAV decoder for SDL_sound.
|
11
|
+
*
|
12
|
+
* This driver handles Microsoft .WAVs, in as many of the thousands of
|
13
|
+
* variations as we can.
|
14
|
+
*/
|
15
|
+
|
16
|
+
#define __SDL_SOUND_INTERNAL__
|
17
|
+
#include "SDL_sound_internal.h"
|
18
|
+
|
19
|
+
#if SOUND_SUPPORTS_WAV
|
20
|
+
|
21
|
+
/* Better than SDL_ReadLE16, since you can detect i/o errors... */
|
22
|
+
static SDL_INLINE int read_le16(SDL_RWops *rw, Uint16 *ui16)
|
23
|
+
{
|
24
|
+
int rc = SDL_RWread(rw, ui16, sizeof (Uint16), 1);
|
25
|
+
BAIL_IF_MACRO(rc != 1, ERR_IO_ERROR, 0);
|
26
|
+
*ui16 = SDL_SwapLE16(*ui16);
|
27
|
+
return 1;
|
28
|
+
} /* read_le16 */
|
29
|
+
|
30
|
+
|
31
|
+
/* Better than SDL_ReadLE32, since you can detect i/o errors... */
|
32
|
+
static SDL_INLINE int read_le32(SDL_RWops *rw, Uint32 *ui32)
|
33
|
+
{
|
34
|
+
int rc = SDL_RWread(rw, ui32, sizeof (Uint32), 1);
|
35
|
+
BAIL_IF_MACRO(rc != 1, ERR_IO_ERROR, 0);
|
36
|
+
*ui32 = SDL_SwapLE32(*ui32);
|
37
|
+
return 1;
|
38
|
+
} /* read_le32 */
|
39
|
+
|
40
|
+
static SDL_INLINE int read_le16s(SDL_RWops *rw, Sint16 *si16)
|
41
|
+
{
|
42
|
+
return read_le16(rw, (Uint16 *) si16);
|
43
|
+
} /* read_le16s */
|
44
|
+
|
45
|
+
static SDL_INLINE int read_le32s(SDL_RWops *rw, Sint32 *si32)
|
46
|
+
{
|
47
|
+
return read_le32(rw, (Uint32 *) si32);
|
48
|
+
} /* read_le32s */
|
49
|
+
|
50
|
+
|
51
|
+
/* This is just cleaner on the caller's end... */
|
52
|
+
static SDL_INLINE int read_uint8(SDL_RWops *rw, Uint8 *ui8)
|
53
|
+
{
|
54
|
+
int rc = SDL_RWread(rw, ui8, sizeof (Uint8), 1);
|
55
|
+
BAIL_IF_MACRO(rc != 1, ERR_IO_ERROR, 0);
|
56
|
+
return 1;
|
57
|
+
} /* read_uint8 */
|
58
|
+
|
59
|
+
|
60
|
+
/* Chunk management code... */
|
61
|
+
|
62
|
+
#define riffID 0x46464952 /* "RIFF", in ascii. */
|
63
|
+
#define waveID 0x45564157 /* "WAVE", in ascii. */
|
64
|
+
#define factID 0x74636166 /* "fact", in ascii. */
|
65
|
+
|
66
|
+
|
67
|
+
/*****************************************************************************
|
68
|
+
* The FORMAT chunk... *
|
69
|
+
*****************************************************************************/
|
70
|
+
|
71
|
+
#define fmtID 0x20746D66 /* "fmt ", in ascii. */
|
72
|
+
|
73
|
+
#define FMT_NORMAL 0x0001 /* Uncompressed waveform data. */
|
74
|
+
#define FMT_ADPCM 0x0002 /* ADPCM compressed waveform data. */
|
75
|
+
|
76
|
+
typedef struct
|
77
|
+
{
|
78
|
+
Sint16 iCoef1;
|
79
|
+
Sint16 iCoef2;
|
80
|
+
} ADPCMCOEFSET;
|
81
|
+
|
82
|
+
typedef struct
|
83
|
+
{
|
84
|
+
Uint8 bPredictor;
|
85
|
+
Uint16 iDelta;
|
86
|
+
Sint16 iSamp1;
|
87
|
+
Sint16 iSamp2;
|
88
|
+
} ADPCMBLOCKHEADER;
|
89
|
+
|
90
|
+
typedef struct S_WAV_FMT_T
|
91
|
+
{
|
92
|
+
Uint32 chunkID;
|
93
|
+
Sint32 chunkSize;
|
94
|
+
Sint16 wFormatTag;
|
95
|
+
Uint16 wChannels;
|
96
|
+
Uint32 dwSamplesPerSec;
|
97
|
+
Uint32 dwAvgBytesPerSec;
|
98
|
+
Uint16 wBlockAlign;
|
99
|
+
Uint16 wBitsPerSample;
|
100
|
+
|
101
|
+
Uint32 next_chunk_offset;
|
102
|
+
|
103
|
+
Uint32 sample_frame_size;
|
104
|
+
Uint32 data_starting_offset;
|
105
|
+
Uint32 total_bytes;
|
106
|
+
|
107
|
+
void (*free)(struct S_WAV_FMT_T *fmt);
|
108
|
+
Uint32 (*read_sample)(Sound_Sample *sample);
|
109
|
+
int (*rewind_sample)(Sound_Sample *sample);
|
110
|
+
int (*seek_sample)(Sound_Sample *sample, Uint32 ms);
|
111
|
+
|
112
|
+
union
|
113
|
+
{
|
114
|
+
struct
|
115
|
+
{
|
116
|
+
Uint16 cbSize;
|
117
|
+
Uint16 wSamplesPerBlock;
|
118
|
+
Uint16 wNumCoef;
|
119
|
+
ADPCMCOEFSET *aCoef;
|
120
|
+
ADPCMBLOCKHEADER *blockheaders;
|
121
|
+
Uint32 samples_left_in_block;
|
122
|
+
int nibble_state;
|
123
|
+
Sint8 nibble;
|
124
|
+
} adpcm;
|
125
|
+
|
126
|
+
/* put other format-specific data here... */
|
127
|
+
} fmt;
|
128
|
+
} fmt_t;
|
129
|
+
|
130
|
+
|
131
|
+
/*
|
132
|
+
* Read in a fmt_t from disk. This makes this process safe regardless of
|
133
|
+
* the processor's byte order or how the fmt_t structure is packed.
|
134
|
+
* Note that the union "fmt" is not read in here; that is handled as
|
135
|
+
* needed in the read_fmt_* functions.
|
136
|
+
*/
|
137
|
+
static int read_fmt_chunk(SDL_RWops *rw, fmt_t *fmt)
|
138
|
+
{
|
139
|
+
/* skip reading the chunk ID, since it was already read at this point... */
|
140
|
+
fmt->chunkID = fmtID;
|
141
|
+
|
142
|
+
BAIL_IF_MACRO(!read_le32s(rw, &fmt->chunkSize), NULL, 0);
|
143
|
+
BAIL_IF_MACRO(fmt->chunkSize < 16, "WAV: Invalid chunk size", 0);
|
144
|
+
fmt->next_chunk_offset = SDL_RWtell(rw) + fmt->chunkSize;
|
145
|
+
|
146
|
+
BAIL_IF_MACRO(!read_le16s(rw, &fmt->wFormatTag), NULL, 0);
|
147
|
+
BAIL_IF_MACRO(!read_le16(rw, &fmt->wChannels), NULL, 0);
|
148
|
+
BAIL_IF_MACRO(!read_le32(rw, &fmt->dwSamplesPerSec), NULL, 0);
|
149
|
+
BAIL_IF_MACRO(!read_le32(rw, &fmt->dwAvgBytesPerSec), NULL, 0);
|
150
|
+
BAIL_IF_MACRO(!read_le16(rw, &fmt->wBlockAlign), NULL, 0);
|
151
|
+
BAIL_IF_MACRO(!read_le16(rw, &fmt->wBitsPerSample), NULL, 0);
|
152
|
+
|
153
|
+
return 1;
|
154
|
+
} /* read_fmt_chunk */
|
155
|
+
|
156
|
+
|
157
|
+
|
158
|
+
/*****************************************************************************
|
159
|
+
* The DATA chunk... *
|
160
|
+
*****************************************************************************/
|
161
|
+
|
162
|
+
#define dataID 0x61746164 /* "data", in ascii. */
|
163
|
+
|
164
|
+
typedef struct
|
165
|
+
{
|
166
|
+
Uint32 chunkID;
|
167
|
+
Sint32 chunkSize;
|
168
|
+
/* Then, (chunkSize) bytes of waveform data... */
|
169
|
+
} data_t;
|
170
|
+
|
171
|
+
|
172
|
+
/*
|
173
|
+
* Read in a data_t from disk. This makes this process safe regardless of
|
174
|
+
* the processor's byte order or how the fmt_t structure is packed.
|
175
|
+
*/
|
176
|
+
static int read_data_chunk(SDL_RWops *rw, data_t *data)
|
177
|
+
{
|
178
|
+
/* skip reading the chunk ID, since it was already read at this point... */
|
179
|
+
data->chunkID = dataID;
|
180
|
+
BAIL_IF_MACRO(!read_le32s(rw, &data->chunkSize), NULL, 0);
|
181
|
+
return 1;
|
182
|
+
} /* read_data_chunk */
|
183
|
+
|
184
|
+
|
185
|
+
|
186
|
+
|
187
|
+
/*****************************************************************************
|
188
|
+
* this is what we store in our internal->decoder_private field... *
|
189
|
+
*****************************************************************************/
|
190
|
+
|
191
|
+
typedef struct
|
192
|
+
{
|
193
|
+
fmt_t *fmt;
|
194
|
+
Sint32 bytesLeft;
|
195
|
+
} wav_t;
|
196
|
+
|
197
|
+
|
198
|
+
|
199
|
+
|
200
|
+
/*****************************************************************************
|
201
|
+
* Normal, uncompressed waveform handler... *
|
202
|
+
*****************************************************************************/
|
203
|
+
|
204
|
+
/*
|
205
|
+
* Sound_Decode() lands here for uncompressed WAVs...
|
206
|
+
*/
|
207
|
+
static Uint32 read_sample_fmt_normal(Sound_Sample *sample)
|
208
|
+
{
|
209
|
+
Uint32 retval;
|
210
|
+
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
|
211
|
+
wav_t *w = (wav_t *) internal->decoder_private;
|
212
|
+
Uint32 max = (internal->buffer_size < (Uint32) w->bytesLeft) ?
|
213
|
+
internal->buffer_size : (Uint32) w->bytesLeft;
|
214
|
+
|
215
|
+
SDL_assert(max > 0);
|
216
|
+
|
217
|
+
/*
|
218
|
+
* We don't actually do any decoding, so we read the wav data
|
219
|
+
* directly into the internal buffer...
|
220
|
+
*/
|
221
|
+
retval = SDL_RWread(internal->rw, internal->buffer, 1, max);
|
222
|
+
|
223
|
+
w->bytesLeft -= retval;
|
224
|
+
|
225
|
+
/* Make sure the read went smoothly... */
|
226
|
+
if ((retval == 0) || (w->bytesLeft == 0))
|
227
|
+
sample->flags |= SOUND_SAMPLEFLAG_EOF;
|
228
|
+
|
229
|
+
else if (retval == -1)
|
230
|
+
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
|
231
|
+
|
232
|
+
/* (next call this EAGAIN may turn into an EOF or error.) */
|
233
|
+
else if (retval < internal->buffer_size)
|
234
|
+
sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
|
235
|
+
|
236
|
+
return retval;
|
237
|
+
} /* read_sample_fmt_normal */
|
238
|
+
|
239
|
+
|
240
|
+
static int seek_sample_fmt_normal(Sound_Sample *sample, Uint32 ms)
|
241
|
+
{
|
242
|
+
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
|
243
|
+
wav_t *w = (wav_t *) internal->decoder_private;
|
244
|
+
fmt_t *fmt = w->fmt;
|
245
|
+
int offset = __Sound_convertMsToBytePos(&sample->actual, ms);
|
246
|
+
int pos = (int) (fmt->data_starting_offset + offset);
|
247
|
+
int rc = SDL_RWseek(internal->rw, pos, SEEK_SET);
|
248
|
+
BAIL_IF_MACRO(rc != pos, ERR_IO_ERROR, 0);
|
249
|
+
w->bytesLeft = fmt->total_bytes - offset;
|
250
|
+
return 1; /* success. */
|
251
|
+
} /* seek_sample_fmt_normal */
|
252
|
+
|
253
|
+
|
254
|
+
static int rewind_sample_fmt_normal(Sound_Sample *sample)
|
255
|
+
{
|
256
|
+
/* no-op. */
|
257
|
+
return 1;
|
258
|
+
} /* rewind_sample_fmt_normal */
|
259
|
+
|
260
|
+
|
261
|
+
static int read_fmt_normal(SDL_RWops *rw, fmt_t *fmt)
|
262
|
+
{
|
263
|
+
/* (don't need to read more from the RWops...) */
|
264
|
+
fmt->free = NULL;
|
265
|
+
fmt->read_sample = read_sample_fmt_normal;
|
266
|
+
fmt->rewind_sample = rewind_sample_fmt_normal;
|
267
|
+
fmt->seek_sample = seek_sample_fmt_normal;
|
268
|
+
return 1;
|
269
|
+
} /* read_fmt_normal */
|
270
|
+
|
271
|
+
|
272
|
+
|
273
|
+
/*****************************************************************************
|
274
|
+
* ADPCM compression handler... *
|
275
|
+
*****************************************************************************/
|
276
|
+
|
277
|
+
#define FIXED_POINT_COEF_BASE 256
|
278
|
+
#define FIXED_POINT_ADAPTION_BASE 256
|
279
|
+
#define SMALLEST_ADPCM_DELTA 16
|
280
|
+
|
281
|
+
|
282
|
+
static SDL_INLINE int read_adpcm_block_headers(Sound_Sample *sample)
|
283
|
+
{
|
284
|
+
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
|
285
|
+
SDL_RWops *rw = internal->rw;
|
286
|
+
wav_t *w = (wav_t *) internal->decoder_private;
|
287
|
+
fmt_t *fmt = w->fmt;
|
288
|
+
ADPCMBLOCKHEADER *headers = fmt->fmt.adpcm.blockheaders;
|
289
|
+
int i;
|
290
|
+
int max = fmt->wChannels;
|
291
|
+
|
292
|
+
if (w->bytesLeft < fmt->wBlockAlign)
|
293
|
+
{
|
294
|
+
sample->flags |= SOUND_SAMPLEFLAG_EOF;
|
295
|
+
return 0;
|
296
|
+
} /* if */
|
297
|
+
|
298
|
+
w->bytesLeft -= fmt->wBlockAlign;
|
299
|
+
|
300
|
+
for (i = 0; i < max; i++)
|
301
|
+
BAIL_IF_MACRO(!read_uint8(rw, &headers[i].bPredictor), NULL, 0);
|
302
|
+
|
303
|
+
for (i = 0; i < max; i++)
|
304
|
+
BAIL_IF_MACRO(!read_le16(rw, &headers[i].iDelta), NULL, 0);
|
305
|
+
|
306
|
+
for (i = 0; i < max; i++)
|
307
|
+
BAIL_IF_MACRO(!read_le16s(rw, &headers[i].iSamp1), NULL, 0);
|
308
|
+
|
309
|
+
for (i = 0; i < max; i++)
|
310
|
+
BAIL_IF_MACRO(!read_le16s(rw, &headers[i].iSamp2), NULL, 0);
|
311
|
+
|
312
|
+
fmt->fmt.adpcm.samples_left_in_block = fmt->fmt.adpcm.wSamplesPerBlock;
|
313
|
+
fmt->fmt.adpcm.nibble_state = 0;
|
314
|
+
return 1;
|
315
|
+
} /* read_adpcm_block_headers */
|
316
|
+
|
317
|
+
|
318
|
+
static SDL_INLINE void do_adpcm_nibble(Uint8 nib,
|
319
|
+
ADPCMBLOCKHEADER *header,
|
320
|
+
Sint32 lPredSamp)
|
321
|
+
{
|
322
|
+
static const Sint32 max_audioval = ((1<<(16-1))-1);
|
323
|
+
static const Sint32 min_audioval = -(1<<(16-1));
|
324
|
+
static const Sint32 AdaptionTable[] =
|
325
|
+
{
|
326
|
+
230, 230, 230, 230, 307, 409, 512, 614,
|
327
|
+
768, 614, 512, 409, 307, 230, 230, 230
|
328
|
+
};
|
329
|
+
|
330
|
+
Sint32 lNewSamp;
|
331
|
+
Sint32 delta;
|
332
|
+
|
333
|
+
if (nib & 0x08)
|
334
|
+
lNewSamp = lPredSamp + (header->iDelta * (nib - 0x10));
|
335
|
+
else
|
336
|
+
lNewSamp = lPredSamp + (header->iDelta * nib);
|
337
|
+
|
338
|
+
/* clamp value... */
|
339
|
+
if (lNewSamp < min_audioval)
|
340
|
+
lNewSamp = min_audioval;
|
341
|
+
else if (lNewSamp > max_audioval)
|
342
|
+
lNewSamp = max_audioval;
|
343
|
+
|
344
|
+
delta = ((Sint32) header->iDelta * AdaptionTable[nib]) /
|
345
|
+
FIXED_POINT_ADAPTION_BASE;
|
346
|
+
|
347
|
+
if (delta < SMALLEST_ADPCM_DELTA)
|
348
|
+
delta = SMALLEST_ADPCM_DELTA;
|
349
|
+
|
350
|
+
header->iDelta = delta;
|
351
|
+
header->iSamp2 = header->iSamp1;
|
352
|
+
header->iSamp1 = lNewSamp;
|
353
|
+
} /* do_adpcm_nibble */
|
354
|
+
|
355
|
+
|
356
|
+
static SDL_INLINE int decode_adpcm_sample_frame(Sound_Sample *sample)
|
357
|
+
{
|
358
|
+
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
|
359
|
+
wav_t *w = (wav_t *) internal->decoder_private;
|
360
|
+
fmt_t *fmt = w->fmt;
|
361
|
+
ADPCMBLOCKHEADER *headers = fmt->fmt.adpcm.blockheaders;
|
362
|
+
SDL_RWops *rw = internal->rw;
|
363
|
+
int i;
|
364
|
+
int max = fmt->wChannels;
|
365
|
+
Sint32 delta;
|
366
|
+
Uint8 nib = fmt->fmt.adpcm.nibble;
|
367
|
+
|
368
|
+
for (i = 0; i < max; i++)
|
369
|
+
{
|
370
|
+
Uint8 byte;
|
371
|
+
Sint16 iCoef1 = fmt->fmt.adpcm.aCoef[headers[i].bPredictor].iCoef1;
|
372
|
+
Sint16 iCoef2 = fmt->fmt.adpcm.aCoef[headers[i].bPredictor].iCoef2;
|
373
|
+
Sint32 lPredSamp = ((headers[i].iSamp1 * iCoef1) +
|
374
|
+
(headers[i].iSamp2 * iCoef2)) /
|
375
|
+
FIXED_POINT_COEF_BASE;
|
376
|
+
|
377
|
+
if (fmt->fmt.adpcm.nibble_state == 0)
|
378
|
+
{
|
379
|
+
BAIL_IF_MACRO(!read_uint8(rw, &nib), NULL, 0);
|
380
|
+
fmt->fmt.adpcm.nibble_state = 1;
|
381
|
+
do_adpcm_nibble(nib >> 4, &headers[i], lPredSamp);
|
382
|
+
} /* if */
|
383
|
+
else
|
384
|
+
{
|
385
|
+
fmt->fmt.adpcm.nibble_state = 0;
|
386
|
+
do_adpcm_nibble(nib & 0x0F, &headers[i], lPredSamp);
|
387
|
+
} /* else */
|
388
|
+
} /* for */
|
389
|
+
|
390
|
+
fmt->fmt.adpcm.nibble = nib;
|
391
|
+
return 1;
|
392
|
+
} /* decode_adpcm_sample_frame */
|
393
|
+
|
394
|
+
|
395
|
+
static SDL_INLINE void put_adpcm_sample_frame1(void *_buf, fmt_t *fmt)
|
396
|
+
{
|
397
|
+
Uint16 *buf = (Uint16 *) _buf;
|
398
|
+
ADPCMBLOCKHEADER *headers = fmt->fmt.adpcm.blockheaders;
|
399
|
+
int i;
|
400
|
+
for (i = 0; i < fmt->wChannels; i++)
|
401
|
+
*(buf++) = headers[i].iSamp1;
|
402
|
+
} /* put_adpcm_sample_frame1 */
|
403
|
+
|
404
|
+
|
405
|
+
static SDL_INLINE void put_adpcm_sample_frame2(void *_buf, fmt_t *fmt)
|
406
|
+
{
|
407
|
+
Uint16 *buf = (Uint16 *) _buf;
|
408
|
+
ADPCMBLOCKHEADER *headers = fmt->fmt.adpcm.blockheaders;
|
409
|
+
int i;
|
410
|
+
for (i = 0; i < fmt->wChannels; i++)
|
411
|
+
*(buf++) = headers[i].iSamp2;
|
412
|
+
} /* put_adpcm_sample_frame2 */
|
413
|
+
|
414
|
+
|
415
|
+
/*
|
416
|
+
* Sound_Decode() lands here for ADPCM-encoded WAVs...
|
417
|
+
*/
|
418
|
+
static Uint32 read_sample_fmt_adpcm(Sound_Sample *sample)
|
419
|
+
{
|
420
|
+
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
|
421
|
+
wav_t *w = (wav_t *) internal->decoder_private;
|
422
|
+
fmt_t *fmt = w->fmt;
|
423
|
+
Uint32 bw = 0;
|
424
|
+
|
425
|
+
while (bw < internal->buffer_size)
|
426
|
+
{
|
427
|
+
/* write ongoing sample frame before reading more data... */
|
428
|
+
switch (fmt->fmt.adpcm.samples_left_in_block)
|
429
|
+
{
|
430
|
+
case 0: /* need to read a new block... */
|
431
|
+
if (!read_adpcm_block_headers(sample))
|
432
|
+
{
|
433
|
+
if ((sample->flags & SOUND_SAMPLEFLAG_EOF) == 0)
|
434
|
+
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
|
435
|
+
return bw;
|
436
|
+
} /* if */
|
437
|
+
|
438
|
+
/* only write first sample frame for now. */
|
439
|
+
put_adpcm_sample_frame2((Uint8 *) internal->buffer + bw, fmt);
|
440
|
+
fmt->fmt.adpcm.samples_left_in_block--;
|
441
|
+
bw += fmt->sample_frame_size;
|
442
|
+
break;
|
443
|
+
|
444
|
+
case 1: /* output last sample frame of block... */
|
445
|
+
put_adpcm_sample_frame1((Uint8 *) internal->buffer + bw, fmt);
|
446
|
+
fmt->fmt.adpcm.samples_left_in_block--;
|
447
|
+
bw += fmt->sample_frame_size;
|
448
|
+
break;
|
449
|
+
|
450
|
+
default: /* output latest sample frame and read a new one... */
|
451
|
+
put_adpcm_sample_frame1((Uint8 *) internal->buffer + bw, fmt);
|
452
|
+
fmt->fmt.adpcm.samples_left_in_block--;
|
453
|
+
bw += fmt->sample_frame_size;
|
454
|
+
|
455
|
+
if (!decode_adpcm_sample_frame(sample))
|
456
|
+
{
|
457
|
+
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
|
458
|
+
return bw;
|
459
|
+
} /* if */
|
460
|
+
} /* switch */
|
461
|
+
} /* while */
|
462
|
+
|
463
|
+
return bw;
|
464
|
+
} /* read_sample_fmt_adpcm */
|
465
|
+
|
466
|
+
|
467
|
+
/*
|
468
|
+
* Sound_FreeSample() lands here for ADPCM-encoded WAVs...
|
469
|
+
*/
|
470
|
+
static void free_fmt_adpcm(fmt_t *fmt)
|
471
|
+
{
|
472
|
+
if (fmt->fmt.adpcm.aCoef != NULL)
|
473
|
+
SDL_free(fmt->fmt.adpcm.aCoef);
|
474
|
+
|
475
|
+
if (fmt->fmt.adpcm.blockheaders != NULL)
|
476
|
+
SDL_free(fmt->fmt.adpcm.blockheaders);
|
477
|
+
} /* free_fmt_adpcm */
|
478
|
+
|
479
|
+
|
480
|
+
static int rewind_sample_fmt_adpcm(Sound_Sample *sample)
|
481
|
+
{
|
482
|
+
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
|
483
|
+
wav_t *w = (wav_t *) internal->decoder_private;
|
484
|
+
w->fmt->fmt.adpcm.samples_left_in_block = 0;
|
485
|
+
return 1;
|
486
|
+
} /* rewind_sample_fmt_adpcm */
|
487
|
+
|
488
|
+
|
489
|
+
static int seek_sample_fmt_adpcm(Sound_Sample *sample, Uint32 ms)
|
490
|
+
{
|
491
|
+
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
|
492
|
+
wav_t *w = (wav_t *) internal->decoder_private;
|
493
|
+
fmt_t *fmt = w->fmt;
|
494
|
+
Uint32 origsampsleft = fmt->fmt.adpcm.samples_left_in_block;
|
495
|
+
int origpos = SDL_RWtell(internal->rw);
|
496
|
+
int offset = __Sound_convertMsToBytePos(&sample->actual, ms);
|
497
|
+
int bpb = (fmt->fmt.adpcm.wSamplesPerBlock * fmt->sample_frame_size);
|
498
|
+
int skipsize = (offset / bpb) * fmt->wBlockAlign;
|
499
|
+
int pos = skipsize + fmt->data_starting_offset;
|
500
|
+
int rc = SDL_RWseek(internal->rw, pos, SEEK_SET);
|
501
|
+
BAIL_IF_MACRO(rc != pos, ERR_IO_ERROR, 0);
|
502
|
+
|
503
|
+
/* The offset we need is in this block, so we need to decode to there. */
|
504
|
+
skipsize += (offset % bpb);
|
505
|
+
rc = (offset % bpb); /* bytes into this block we need to decode */
|
506
|
+
if (!read_adpcm_block_headers(sample))
|
507
|
+
{
|
508
|
+
SDL_RWseek(internal->rw, origpos, SEEK_SET); /* try to make sane. */
|
509
|
+
return 0;
|
510
|
+
} /* if */
|
511
|
+
|
512
|
+
/* first sample frame of block is a freebie. :) */
|
513
|
+
fmt->fmt.adpcm.samples_left_in_block--;
|
514
|
+
rc -= fmt->sample_frame_size;
|
515
|
+
while (rc > 0)
|
516
|
+
{
|
517
|
+
if (!decode_adpcm_sample_frame(sample))
|
518
|
+
{
|
519
|
+
SDL_RWseek(internal->rw, origpos, SEEK_SET);
|
520
|
+
fmt->fmt.adpcm.samples_left_in_block = origsampsleft;
|
521
|
+
return 0;
|
522
|
+
} /* if */
|
523
|
+
|
524
|
+
fmt->fmt.adpcm.samples_left_in_block--;
|
525
|
+
rc -= fmt->sample_frame_size;
|
526
|
+
} /* while */
|
527
|
+
|
528
|
+
w->bytesLeft = fmt->total_bytes - skipsize;
|
529
|
+
return 1; /* success. */
|
530
|
+
} /* seek_sample_fmt_adpcm */
|
531
|
+
|
532
|
+
|
533
|
+
/*
|
534
|
+
* Read in the adpcm-specific info from disk. This makes this process
|
535
|
+
* safe regardless of the processor's byte order or how the fmt_t
|
536
|
+
* structure is packed.
|
537
|
+
*/
|
538
|
+
static int read_fmt_adpcm(SDL_RWops *rw, fmt_t *fmt)
|
539
|
+
{
|
540
|
+
size_t i;
|
541
|
+
|
542
|
+
SDL_memset(&fmt->fmt.adpcm, '\0', sizeof (fmt->fmt.adpcm));
|
543
|
+
fmt->free = free_fmt_adpcm;
|
544
|
+
fmt->read_sample = read_sample_fmt_adpcm;
|
545
|
+
fmt->rewind_sample = rewind_sample_fmt_adpcm;
|
546
|
+
fmt->seek_sample = seek_sample_fmt_adpcm;
|
547
|
+
|
548
|
+
BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.adpcm.cbSize), NULL, 0);
|
549
|
+
BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.adpcm.wSamplesPerBlock), NULL, 0);
|
550
|
+
BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.adpcm.wNumCoef), NULL, 0);
|
551
|
+
|
552
|
+
/* fmt->free() is always called, so these malloc()s will be cleaned up. */
|
553
|
+
|
554
|
+
i = sizeof (ADPCMCOEFSET) * fmt->fmt.adpcm.wNumCoef;
|
555
|
+
fmt->fmt.adpcm.aCoef = (ADPCMCOEFSET *) SDL_malloc(i);
|
556
|
+
BAIL_IF_MACRO(fmt->fmt.adpcm.aCoef == NULL, ERR_OUT_OF_MEMORY, 0);
|
557
|
+
|
558
|
+
for (i = 0; i < fmt->fmt.adpcm.wNumCoef; i++)
|
559
|
+
{
|
560
|
+
BAIL_IF_MACRO(!read_le16s(rw, &fmt->fmt.adpcm.aCoef[i].iCoef1), NULL, 0);
|
561
|
+
BAIL_IF_MACRO(!read_le16s(rw, &fmt->fmt.adpcm.aCoef[i].iCoef2), NULL, 0);
|
562
|
+
} /* for */
|
563
|
+
|
564
|
+
i = sizeof (ADPCMBLOCKHEADER) * fmt->wChannels;
|
565
|
+
fmt->fmt.adpcm.blockheaders = (ADPCMBLOCKHEADER *) SDL_malloc(i);
|
566
|
+
BAIL_IF_MACRO(fmt->fmt.adpcm.blockheaders == NULL, ERR_OUT_OF_MEMORY, 0);
|
567
|
+
|
568
|
+
return 1;
|
569
|
+
} /* read_fmt_adpcm */
|
570
|
+
|
571
|
+
|
572
|
+
|
573
|
+
/*****************************************************************************
|
574
|
+
* Everything else... *
|
575
|
+
*****************************************************************************/
|
576
|
+
|
577
|
+
static int WAV_init(void)
|
578
|
+
{
|
579
|
+
return 1; /* always succeeds. */
|
580
|
+
} /* WAV_init */
|
581
|
+
|
582
|
+
|
583
|
+
static void WAV_quit(void)
|
584
|
+
{
|
585
|
+
/* it's a no-op. */
|
586
|
+
} /* WAV_quit */
|
587
|
+
|
588
|
+
|
589
|
+
static int read_fmt(SDL_RWops *rw, fmt_t *fmt)
|
590
|
+
{
|
591
|
+
/* if it's in this switch statement, we support the format. */
|
592
|
+
switch (fmt->wFormatTag)
|
593
|
+
{
|
594
|
+
case FMT_NORMAL:
|
595
|
+
SNDDBG(("WAV: Appears to be uncompressed audio.\n"));
|
596
|
+
return read_fmt_normal(rw, fmt);
|
597
|
+
|
598
|
+
case FMT_ADPCM:
|
599
|
+
SNDDBG(("WAV: Appears to be ADPCM compressed audio.\n"));
|
600
|
+
return read_fmt_adpcm(rw, fmt);
|
601
|
+
|
602
|
+
/* add other types here. */
|
603
|
+
|
604
|
+
default:
|
605
|
+
SNDDBG(("WAV: Format 0x%X is unknown.\n",
|
606
|
+
(unsigned int) fmt->wFormatTag));
|
607
|
+
BAIL_MACRO("WAV: Unsupported format", 0);
|
608
|
+
} /* switch */
|
609
|
+
|
610
|
+
SDL_assert(0); /* shouldn't hit this point. */
|
611
|
+
return 0;
|
612
|
+
} /* read_fmt */
|
613
|
+
|
614
|
+
|
615
|
+
/*
|
616
|
+
* Locate a specific chunk in the WAVE file by ID...
|
617
|
+
*/
|
618
|
+
static int find_chunk(SDL_RWops *rw, Uint32 id)
|
619
|
+
{
|
620
|
+
Sint32 siz = 0;
|
621
|
+
Uint32 _id = 0;
|
622
|
+
Uint32 pos = SDL_RWtell(rw);
|
623
|
+
|
624
|
+
while (1)
|
625
|
+
{
|
626
|
+
BAIL_IF_MACRO(!read_le32(rw, &_id), NULL, 0);
|
627
|
+
if (_id == id)
|
628
|
+
return 1;
|
629
|
+
|
630
|
+
/* skip ahead and see what next chunk is... */
|
631
|
+
BAIL_IF_MACRO(!read_le32s(rw, &siz), NULL, 0);
|
632
|
+
SDL_assert(siz >= 0);
|
633
|
+
pos += (sizeof (Uint32) * 2) + siz;
|
634
|
+
if (siz > 0)
|
635
|
+
BAIL_IF_MACRO(SDL_RWseek(rw, pos, SEEK_SET) != pos, NULL, 0);
|
636
|
+
} /* while */
|
637
|
+
|
638
|
+
return 0; /* shouldn't hit this, but just in case... */
|
639
|
+
} /* find_chunk */
|
640
|
+
|
641
|
+
|
642
|
+
static int WAV_open_internal(Sound_Sample *sample, const char *ext, fmt_t *fmt)
|
643
|
+
{
|
644
|
+
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
|
645
|
+
SDL_RWops *rw = internal->rw;
|
646
|
+
data_t d;
|
647
|
+
wav_t *w;
|
648
|
+
Uint32 pos;
|
649
|
+
|
650
|
+
BAIL_IF_MACRO(SDL_ReadLE32(rw) != riffID, "WAV: Not a RIFF file.", 0);
|
651
|
+
SDL_ReadLE32(rw); /* throw the length away; we get this info later. */
|
652
|
+
BAIL_IF_MACRO(SDL_ReadLE32(rw) != waveID, "WAV: Not a WAVE file.", 0);
|
653
|
+
BAIL_IF_MACRO(!find_chunk(rw, fmtID), "WAV: No format chunk.", 0);
|
654
|
+
BAIL_IF_MACRO(!read_fmt_chunk(rw, fmt), "WAV: Can't read format chunk.", 0);
|
655
|
+
|
656
|
+
/* !!! FIXME: need float32 format stuff, since it's not just wBitsPerSample. */
|
657
|
+
|
658
|
+
sample->actual.channels = (Uint8) fmt->wChannels;
|
659
|
+
sample->actual.rate = fmt->dwSamplesPerSec;
|
660
|
+
if (fmt->wBitsPerSample == 4)
|
661
|
+
sample->actual.format = AUDIO_S16SYS;
|
662
|
+
else if (fmt->wBitsPerSample == 8)
|
663
|
+
sample->actual.format = AUDIO_U8;
|
664
|
+
else if (fmt->wBitsPerSample == 16)
|
665
|
+
sample->actual.format = AUDIO_S16LSB;
|
666
|
+
else if (fmt->wBitsPerSample == 32)
|
667
|
+
sample->actual.format = AUDIO_S32LSB;
|
668
|
+
else
|
669
|
+
{
|
670
|
+
SNDDBG(("WAV: %d bits per sample!?\n", (int) fmt->wBitsPerSample));
|
671
|
+
BAIL_MACRO("WAV: Unsupported sample size.", 0);
|
672
|
+
} /* else */
|
673
|
+
|
674
|
+
BAIL_IF_MACRO(!read_fmt(rw, fmt), NULL, 0);
|
675
|
+
SDL_RWseek(rw, fmt->next_chunk_offset, SEEK_SET);
|
676
|
+
BAIL_IF_MACRO(!find_chunk(rw, dataID), "WAV: No data chunk.", 0);
|
677
|
+
BAIL_IF_MACRO(!read_data_chunk(rw, &d), "WAV: Can't read data chunk.", 0);
|
678
|
+
|
679
|
+
w = (wav_t *) SDL_malloc(sizeof(wav_t));
|
680
|
+
BAIL_IF_MACRO(w == NULL, ERR_OUT_OF_MEMORY, 0);
|
681
|
+
w->fmt = fmt;
|
682
|
+
fmt->total_bytes = w->bytesLeft = d.chunkSize;
|
683
|
+
fmt->data_starting_offset = SDL_RWtell(rw);
|
684
|
+
fmt->sample_frame_size = ( ((sample->actual.format & 0xFF) / 8) *
|
685
|
+
sample->actual.channels );
|
686
|
+
internal->decoder_private = (void *) w;
|
687
|
+
|
688
|
+
internal->total_time = (fmt->total_bytes / fmt->dwAvgBytesPerSec) * 1000;
|
689
|
+
internal->total_time += (fmt->total_bytes % fmt->dwAvgBytesPerSec)
|
690
|
+
* 1000 / fmt->dwAvgBytesPerSec;
|
691
|
+
|
692
|
+
sample->flags = SOUND_SAMPLEFLAG_NONE;
|
693
|
+
if (fmt->seek_sample != NULL)
|
694
|
+
sample->flags |= SOUND_SAMPLEFLAG_CANSEEK;
|
695
|
+
|
696
|
+
SNDDBG(("WAV: Accepting data stream.\n"));
|
697
|
+
return 1; /* we'll handle this data. */
|
698
|
+
} /* WAV_open_internal */
|
699
|
+
|
700
|
+
|
701
|
+
static int WAV_open(Sound_Sample *sample, const char *ext)
|
702
|
+
{
|
703
|
+
int rc;
|
704
|
+
|
705
|
+
fmt_t *fmt = (fmt_t *) SDL_calloc(1, sizeof (fmt_t));
|
706
|
+
BAIL_IF_MACRO(fmt == NULL, ERR_OUT_OF_MEMORY, 0);
|
707
|
+
|
708
|
+
rc = WAV_open_internal(sample, ext, fmt);
|
709
|
+
if (!rc)
|
710
|
+
{
|
711
|
+
if (fmt->free != NULL)
|
712
|
+
fmt->free(fmt);
|
713
|
+
SDL_free(fmt);
|
714
|
+
} /* if */
|
715
|
+
|
716
|
+
return rc;
|
717
|
+
} /* WAV_open */
|
718
|
+
|
719
|
+
|
720
|
+
static void WAV_close(Sound_Sample *sample)
|
721
|
+
{
|
722
|
+
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
|
723
|
+
wav_t *w = (wav_t *) internal->decoder_private;
|
724
|
+
|
725
|
+
if (w->fmt->free != NULL)
|
726
|
+
w->fmt->free(w->fmt);
|
727
|
+
|
728
|
+
SDL_free(w->fmt);
|
729
|
+
SDL_free(w);
|
730
|
+
} /* WAV_close */
|
731
|
+
|
732
|
+
|
733
|
+
static Uint32 WAV_read(Sound_Sample *sample)
|
734
|
+
{
|
735
|
+
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
|
736
|
+
wav_t *w = (wav_t *) internal->decoder_private;
|
737
|
+
return w->fmt->read_sample(sample);
|
738
|
+
} /* WAV_read */
|
739
|
+
|
740
|
+
|
741
|
+
static int WAV_rewind(Sound_Sample *sample)
|
742
|
+
{
|
743
|
+
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
|
744
|
+
wav_t *w = (wav_t *) internal->decoder_private;
|
745
|
+
fmt_t *fmt = w->fmt;
|
746
|
+
int rc = SDL_RWseek(internal->rw, fmt->data_starting_offset, SEEK_SET);
|
747
|
+
BAIL_IF_MACRO(rc != fmt->data_starting_offset, ERR_IO_ERROR, 0);
|
748
|
+
w->bytesLeft = fmt->total_bytes;
|
749
|
+
return fmt->rewind_sample(sample);
|
750
|
+
} /* WAV_rewind */
|
751
|
+
|
752
|
+
|
753
|
+
static int WAV_seek(Sound_Sample *sample, Uint32 ms)
|
754
|
+
{
|
755
|
+
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
|
756
|
+
wav_t *w = (wav_t *) internal->decoder_private;
|
757
|
+
return w->fmt->seek_sample(sample, ms);
|
758
|
+
} /* WAV_seek */
|
759
|
+
|
760
|
+
|
761
|
+
static const char *extensions_wav[] = { "WAV", NULL };
|
762
|
+
const Sound_DecoderFunctions __Sound_DecoderFunctions_WAV =
|
763
|
+
{
|
764
|
+
{
|
765
|
+
extensions_wav,
|
766
|
+
"Microsoft WAVE audio format",
|
767
|
+
"Ryan C. Gordon <icculus@icculus.org>",
|
768
|
+
"https://icculus.org/SDL_sound/"
|
769
|
+
},
|
770
|
+
|
771
|
+
WAV_init, /* init() method */
|
772
|
+
WAV_quit, /* quit() method */
|
773
|
+
WAV_open, /* open() method */
|
774
|
+
WAV_close, /* close() method */
|
775
|
+
WAV_read, /* read() method */
|
776
|
+
WAV_rewind, /* rewind() method */
|
777
|
+
WAV_seek /* seek() method */
|
778
|
+
};
|
779
|
+
|
780
|
+
#endif /* SOUND_SUPPORTS_WAV */
|
781
|
+
|
782
|
+
/* end of SDL_sound_wav.c ... */
|
783
|
+
|