1 /*
2  *  SPDX-License-Identifier: GPL-2.0-or-later
3  *
4  *  Copyright (C) 2020-2021  The DOSBox Staging Team
5  *  Copyright (C) 2018-2021  kcgen <kcgen@users.noreply.github.com>
6  *  Copyright (C) 2001-2017  Ryan C. Gordon <icculus@icculus.org>
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License along
19  *  with this program; if not, write to the Free Software Foundation, Inc.,
20  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  */
22 
23 /*
24  *  DOSBox Vorbis decoder API implementation
25  *  -------------------------------------
26  *  It makes use of the stand-alone STB Vorbis library:
27  *   - STB: https://github.com/nothings/stb (source)
28  *   - STB: https://twitter.com/nothings (website/author info)
29  */
30 
31 #if HAVE_CONFIG_H
32 #  include <config.h>
33 #endif
34 
35 #ifdef memcpy
36 #  undef memcpy
37 #endif
38 
39 #include <string.h> /* memcpy */
40 #include <math.h> /* lroundf */
41 
42 #include "SDL_sound.h"
43 #define __SDL_SOUND_INTERNAL__
44 #include "SDL_sound_internal.h"
45 
46 #ifdef asset
47 #  undef assert
48 #  define assert SDL_assert
49 #endif
50 
51 #ifdef memset
52 #  undef memset
53 #  define memset SDL_memset
54 #endif
55 
56 #define free         SDL_free
57 #define qsort        SDL_qsort
58 #define memcmp       SDL_memcmp
59 #define malloc       SDL_malloc
60 #define realloc      SDL_realloc
61 #define dealloca(x)  SDL_stack_free((x))
62 
63 /* Configure and include stb_vorbis for compiling... */
64 #define STB_VORBIS_NO_STDIO 1
65 #define STB_VORBIS_NO_CRT 1
66 #define STB_VORBIS_NO_PUSHDATA_API 1
67 #define STB_VORBIS_MAX_CHANNELS 2
68 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
69 #define STB_VORBIS_BIG_ENDIAN 1
70 #endif
71 
72 #include "stb_vorbis.h"
73 
74 #ifdef DEBUG_CHATTER
vorbis_error_string(const int err)75 static const char *vorbis_error_string(const int err)
76 {
77     switch (err)
78     {
79         case VORBIS__no_error: return NULL;
80         case VORBIS_need_more_data: return "VORBIS: need more data";
81         case VORBIS_invalid_api_mixing: return "VORBIS: can't mix API modes";
82         case VORBIS_outofmem: return "VORBIS: out of memory";
83         case VORBIS_feature_not_supported: return "VORBIS: feature not supported";
84         case VORBIS_too_many_channels: return "VORBIS: too many channels";
85         case VORBIS_file_open_failure: return "VORBIS: failed opening the file";
86         case VORBIS_seek_without_length: return "VORBIS: can't seek in unknown length stream";
87         case VORBIS_unexpected_eof: return "VORBIS: unexpected eof";
88         case VORBIS_seek_invalid: return "VORBIS: invalid seek";
89         case VORBIS_invalid_setup: return "VORBIS: invalid setup";
90         case VORBIS_invalid_stream: return "VORBIS: invalid stream";
91         case VORBIS_missing_capture_pattern: return "VORBIS: missing capture pattern";
92         case VORBIS_invalid_stream_structure_version: return "VORBIS: invalid stream structure version";
93         case VORBIS_continued_packet_flag_invalid: return "VORBIS: continued packet flag invalid";
94         case VORBIS_incorrect_stream_serial_number: return "VORBIS: incorrect stream serial number";
95         case VORBIS_invalid_first_page: return "VORBIS: invalid first page";
96         case VORBIS_bad_packet_type: return "VORBIS: bad packet type";
97         case VORBIS_cant_find_last_page: return "VORBIS: can't find last page";
98         case VORBIS_seek_failed: return "VORBIS: seek failed";
99         case VORBIS_ogg_skeleton_not_supported: return "VORBIS: multi-track streams are not supported; "
100                                                        "consider re-encoding without the Ogg Skeleton bitstream";
101         default: break;
102     } /* switch */
103 
104     return "VORBIS: unknown error";
105 } /* vorbis_error_string */
106 #endif
107 
VORBIS_init(void)108 static int VORBIS_init(void)
109 {
110     return 1;  /* always succeeds. */
111 } /* VORBIS_init */
112 
VORBIS_quit(void)113 static void VORBIS_quit(void)
114 {
115     /* it's a no-op. */
116 } /* VORBIS_quit */
117 
VORBIS_open(Sound_Sample * sample,const char * ext)118 static int VORBIS_open(Sound_Sample *sample, const char *ext)
119 {
120     (void) ext; // deliberately unused, but present for API compliance
121     Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
122     SDL_RWops *rw = internal->rw;
123     int err = 0;
124     stb_vorbis *stb = stb_vorbis_open_rwops(rw, 0, &err, NULL);
125 
126 	if (stb == NULL) {
127 		SNDDBG(("%s (error code: %d)\n", vorbis_error_string(err), err));
128         return 0;
129 	}
130     internal->decoder_private = stb;
131     sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
132     sample->actual.format = AUDIO_S16SYS; // returns byte-order native to the running architecture
133     sample->actual.channels = stb->channels;
134     sample->actual.rate = stb->sample_rate;
135     const unsigned int num_frames = stb_vorbis_stream_length_in_samples(stb);
136     if (!num_frames) {
137         internal->total_time = -1;
138     }
139     else {
140         const unsigned int rate = stb->sample_rate;
141         internal->total_time = (num_frames / rate) * 1000;
142         internal->total_time += (num_frames % rate) * 1000 / rate;
143     } /* else */
144 
145     return 1; /* we'll handle this data. */
146 } /* VORBIS_open */
147 
148 
VORBIS_close(Sound_Sample * sample)149 static void VORBIS_close(Sound_Sample *sample)
150 {
151     Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
152     stb_vorbis *stb = (stb_vorbis *) internal->decoder_private;
153     stb_vorbis_close(stb);
154 } /* VORBIS_close */
155 
156 
VORBIS_read(Sound_Sample * sample,void * buffer,Uint32 desired_frames)157 static Uint32 VORBIS_read(Sound_Sample *sample, void* buffer, Uint32 desired_frames)
158 {
159     Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
160     stb_vorbis *stb = (stb_vorbis *) internal->decoder_private;
161     const int channels = (int) sample->actual.channels;
162     const int desired_samples = desired_frames * channels;
163 
164     // Note that for interleaved data, you pass in the number of shorts (the
165     // size of your array), but the return value is the number of samples per
166     // channel, not the total number of samples.
167 
168     stb_vorbis_get_error(stb);  /* clear any error state */
169     const int decoded_frames = stb_vorbis_get_samples_short_interleaved(stb, channels, (int16_t *) buffer, desired_samples);
170     const int err = stb_vorbis_get_error(stb);
171 
172     if (decoded_frames == 0) {
173         sample->flags |= (err ? SOUND_SAMPLEFLAG_ERROR : SOUND_SAMPLEFLAG_EOF);
174     }
175     else if (decoded_frames < (int) desired_frames) {
176         sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
177     }
178     return decoded_frames;
179 } /* VORBIS_read */
180 
181 
VORBIS_rewind(Sound_Sample * sample)182 static int VORBIS_rewind(Sound_Sample *sample)
183 {
184     Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
185     stb_vorbis *stb = (stb_vorbis *) internal->decoder_private;
186 
187     if (!stb_vorbis_seek_start(stb)) {
188         SNDDBG(("%s\n", vorbis_error_string(stb_vorbis_get_error(stb))));
189         return 0;
190     }
191 
192     return 1;
193 } /* VORBIS_rewind */
194 
195 
VORBIS_seek(Sound_Sample * sample,Uint32 ms)196 static int VORBIS_seek(Sound_Sample *sample, Uint32 ms)
197 {
198     Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
199     stb_vorbis *stb = (stb_vorbis *) internal->decoder_private;
200     const float frames_per_ms = ((float) sample->actual.rate) / 1000.0f;
201     const Uint32 frame_offset = lroundf(frames_per_ms * ms);
202     const unsigned int sampnum = (unsigned int) frame_offset;
203 
204     if (!stb_vorbis_seek(stb, sampnum)) {
205         SNDDBG(("%s\n", vorbis_error_string(stb_vorbis_get_error(stb))));
206         return 0;
207     }
208     return 1;
209 } /* VORBIS_seek */
210 
211 
212 static const char *extensions_vorbis[] = { "OGG", "OGA", "VORBIS", NULL };
213 const Sound_DecoderFunctions __Sound_DecoderFunctions_VORBIS =
214 {
215     {
216         extensions_vorbis,
217         "Ogg Vorbis audio",
218         "The DOSBox Staging Team"
219     },
220 
221     VORBIS_init,       /*   init() method */
222     VORBIS_quit,       /*   quit() method */
223     VORBIS_open,       /*   open() method */
224     VORBIS_close,      /*  close() method */
225     VORBIS_read,       /*   read() method */
226     VORBIS_rewind,     /* rewind() method */
227     VORBIS_seek        /*   seek() method */
228 };
229 
230 /* end of SDL_sound_vorbis.c ... */
231