1 //**************************************************************************
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
10 //** Copyright (C) 1999-2006 Jānis Legzdiņš
11 //** Copyright (C) 2018-2020 Ketmar Dark
13 //** This program is free software: you can redistribute it and/or modify
14 //** it under the terms of the GNU General Public License as published by
15 //** the Free Software Foundation, version 3 of the License ONLY.
17 //** This program is distributed in the hope that it will be useful,
18 //** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 //** GNU General Public License for more details.
22 //** You should have received a copy of the GNU General Public License
23 //** along with this program. If not, see <http://www.gnu.org/licenses/>.
25 //**************************************************************************
26 /*#define STB_VORBIS_NO_PUSHDATA_API*/
27 #define STB_VORBIS_NO_PULLDATA_API
28 #define STB_VORBIS_NO_STDIO
29 #define STB_VORBIS_NO_FAST_SCALED_FLOAT
31 #include "stbdr/stb_vorbis.c"
34 #include "snd_local.h"
37 class VVorbisAudioCodec
: public VAudioCodec
{
48 vint16
*outbuf
; // stereo
49 int outbufSize
; // in shorts
50 int outbufUsed
; // in shorts
51 int outbufFilled
; // in shorts
54 VVorbisAudioCodec (VStream
*AStrm
, bool AFreeStream
);
55 virtual ~VVorbisAudioCodec () override
;
58 virtual int Decode (short *Data
, int NumSamples
) override
;
59 virtual bool Finished () override
;
60 virtual void Restart () override
;
62 static VAudioCodec
*Create (VStream
*);
65 void stopFeeding (bool setEOS
=false);
66 // returns `false` on error or eof
68 // returns `false` on error or eof
73 class VVorbisSampleLoader
: public VSampleLoader
{
75 virtual void Load (sfxinfo_t
&, VStream
&) override
;
78 IMPLEMENT_AUDIO_CODEC(VVorbisAudioCodec
, "Vorbis(stb)");
80 VVorbisSampleLoader VorbisSampleLoader
;
83 //==========================================================================
85 // VVorbisAudioCodec::VVorbisAudioCodec
87 //==========================================================================
88 VVorbisAudioCodec::VVorbisAudioCodec (VStream
*AStrm
, bool AFreeStream
)
90 , FreeStream(AFreeStream
)
103 BytesLeft
= Strm
->TotalSize();
105 inbuf
= (vuint8
*)Z_Malloc(inbufSize
);
109 //==========================================================================
111 // VVorbisAudioCodec::~VVorbisAudioCodec
113 //==========================================================================
114 VVorbisAudioCodec::~VVorbisAudioCodec () {
123 if (inbuf
) Z_Free(inbuf
);
124 if (outbuf
) Z_Free(outbuf
);
128 //==========================================================================
130 // VVorbisAudioCodec::Cleanup
132 //==========================================================================
133 void VVorbisAudioCodec::Cleanup () {
134 if (decoder
) { stb_vorbis_close(decoder
); decoder
= nullptr; }
135 inbufUsed
= inbufFilled
= 0;
136 outbufUsed
= outbufFilled
= 0;
140 //==========================================================================
142 // VVorbisAudioCodec::stopFeeding
144 //==========================================================================
145 void VVorbisAudioCodec::stopFeeding (bool setEOS
) {
146 if (setEOS
) eos
= true;
148 inbufUsed
= inbufFilled
= 0;
152 //==========================================================================
154 // VVorbisAudioCodec::fillInBuffer
156 // returns `false` on error or eof
158 //==========================================================================
159 bool VVorbisAudioCodec::fillInBuffer () {
160 if (BytesLeft
== 0 || eos
) {
161 if (inbufUsed
>= inbufFilled
) stopFeeding();
162 return (inbufUsed
< inbufFilled
);
165 if (inbufUsed
< inbufFilled
) {
166 memmove(inbuf
, inbuf
+inbufUsed
, inbufFilled
-inbufUsed
);
167 inbufFilled
-= inbufUsed
;
173 vassert(inbufUsed
== 0);
174 int rd
= min2(BytesLeft
, inbufSize
-inbufFilled
);
177 if (inbufFilled
> 0) return true;
178 if (BytesLeft
> 0) GCon
->Logf(NAME_Error
, "stb_vorbis decoder glitched at '%s'", *Strm
->GetName());
182 Strm
->Serialise(inbuf
+inbufFilled
, rd
);
183 if (Strm
->IsError()) { stopFeeding(true); return false; }
190 //==========================================================================
194 //==========================================================================
195 static inline void floatbuf2short (vint16
*dest
, const float *src
, unsigned length
, bool mono2stereo
=false) noexcept
{
198 *dest
= (vint16
)(clampval(*src
, -1.0f
, 1.0f
)*32767.0f
);
204 dest
[0] = dest
[1] = (vint16
)(clampval(*src
, -1.0f
, 1.0f
)*32767.0f
);
212 //==========================================================================
214 // VVorbisAudioCodec::decodeFrame
216 // returns `false` on error or eof
218 //==========================================================================
219 bool VVorbisAudioCodec::decodeFrame () {
220 if (outbufUsed
< outbufFilled
) return true;
221 if (eos
|| !decoder
|| !Strm
|| Strm
->IsError()) { stopFeeding(true); return false; }
222 //float *fltpcm[STB_VORBIS_MAX_CHANNELS];
224 //GCon->Logf(NAME_Debug, "...decodeFrame: '%s' (used=%d; filled=%d; size=%d); oused=%d; ofilled=%d; osize=%d", *Strm->GetName(), inbufUsed, inbufFilled, inbufSize, outbufUsed, outbufFilled, outbufSize);
226 if (inbufUsed
>= inbufFilled
) {
228 //GCon->Logf(NAME_Debug, "...read new buffer from '%s' (used=%d; filled=%d; size=%d)", *Strm->GetName(), inbufUsed, inbufFilled, inbufSize);
230 //GCon->Logf(NAME_Debug, "...decoding frame from '%s' (used=%d; filled=%d; size=%d)", *Strm->GetName(), inbufUsed, inbufFilled, inbufSize);
233 int res
= stb_vorbis_decode_frame_pushdata(decoder
, (const unsigned char *)(inbuf
+inbufUsed
), inbufFilled
-inbufUsed
, &chans
, &fltpcm
, &samples
);
234 //GCon->Logf(NAME_Debug, "...decoded frame from '%s' (res=%d; chans=%d; samples=%d)", *Strm->GetName(), res, chans, samples);
235 if (res
< 0) { stopFeeding(true); return false; } // something's strange in the neighbourhood
237 // check samples first
239 if (chans
< 1 || chans
> 2) { stopFeeding(true); return false; } // why is that?
240 // alloc samples for two channels
241 if (outbufSize
< samples
*2) {
242 outbufSize
= samples
*2;
243 outbuf
= (vint16
*)Z_Realloc(outbuf
, outbufSize
*2);
245 vassert(outbufSize
>= samples
*2);
248 // mono, expand to stereo
249 floatbuf2short(outbuf
, fltpcm
[0], (unsigned)samples
, true);
252 floatbuf2short(outbuf
, fltpcm
[0], (unsigned)samples
);
253 floatbuf2short(outbuf
+1, fltpcm
[1], (unsigned)samples
);
255 outbufFilled
= samples
*2;
256 //GCon->Logf(NAME_Debug, "...DECODED: '%s' (used=%d; filled=%d; size=%d); oused=%d; ofilled=%d; osize=%d", *Strm->GetName(), inbufUsed, inbufFilled, inbufSize, outbufUsed, outbufFilled, outbufSize);
259 // ok, no samples, we may need more data
261 //GCon->Logf(NAME_Debug, "...needs more data from '%s'", *Strm->GetName());
262 // just need more data
263 int oldInbufAvail
= inbufFilled
-inbufUsed
;
265 if (inbufFilled
-inbufUsed
== oldInbufAvail
) {
266 // cannot get more data, set "end of stream" flag
267 //GCon->Logf(NAME_Debug, "cannot get more data from '%s'", *Strm->GetName());
271 //GCon->Logf(NAME_Debug, "...Decoding frame from '%s' (used=%d; filled=%d; size=%d)", *Strm->GetName(), inbufUsed, inbufFilled, inbufSize);
277 //==========================================================================
279 // VVorbisAudioCodec::Init
281 //==========================================================================
282 bool VVorbisAudioCodec::Init () {
286 if (!fillInBuffer()) {
287 //GCon->Logf(NAME_Debug, "oops (%s)", *Strm->GetName());
291 //GCon->Logf(NAME_Debug, "buffer filled (%s) (%d/%d/%d)", *Strm->GetName(), inbufUsed, inbufFilled, inbufSize);
294 decoder
= stb_vorbis_open_pushdata((const unsigned char *)inbuf
, inbufFilled
-inbufUsed
, &usedData
, &error
, nullptr);
295 if (!decoder
|| error
!= 0) {
296 //GCon->Logf(NAME_Debug, "stb_vorbis error: %d", error);
300 inbufUsed
+= usedData
;
302 stb_vorbis_info info
= stb_vorbis_get_info(decoder
);
304 if (info
.sample_rate
< 64 || info
.sample_rate
> 96000*2 || info
.channels
< 1 || info
.channels
> 2) {
305 //GCon->Logf(NAME_Debug, "stb_vorbis cannot get info (%d : %d)", (int)info.sample_rate, (int)info.channels);
310 SampleRate
= info
.sample_rate
;
312 NumChannels
= 2; // always
313 //GCon->Logf(NAME_Debug, "stb_vorbis created (%s); rate=%d; chans=%d", *Strm->GetName(), SampleRate, NumChannels);
314 //GCon->Logf(NAME_Debug, "buffer filled (%s) (%d/%d/%d)", *Strm->GetName(), inbufUsed, inbufFilled, inbufSize);
320 //==========================================================================
322 // VVorbisAudioCodec::Decode
324 //==========================================================================
325 int VVorbisAudioCodec::Decode (short *Data
, int NumSamples
) {
328 while (CurSample
< NumSamples
) {
329 if (outbufUsed
>= outbufFilled
) {
330 if (!decodeFrame()) break;
332 while (CurSample
< NumSamples
&& outbufUsed
+2 <= outbufFilled
) {
333 *dest
++ = outbuf
[outbufUsed
++];
334 *dest
++ = outbuf
[outbufUsed
++];
337 if (outbufUsed
+2 > outbufFilled
) outbufUsed
= outbufFilled
; // just in case
343 //==========================================================================
345 // VVorbisAudioCodec::Finished
347 //==========================================================================
348 bool VVorbisAudioCodec::Finished () {
349 return (eos
&& outbufUsed
>= outbufFilled
);
353 //==========================================================================
355 // VVorbisAudioCodec::Restart
357 //==========================================================================
358 void VVorbisAudioCodec::Restart () {
361 BytesLeft
= Strm
->TotalSize();
366 //==========================================================================
368 // VVorbisAudioCodec::Create
370 //==========================================================================
371 VAudioCodec
*VVorbisAudioCodec::Create (VStream
*InStrm
) {
372 VVorbisAudioCodec
*Codec
= new VVorbisAudioCodec(InStrm
, true);
373 if (!Codec
->Init()) {
382 //==========================================================================
384 // VVorbisAudioCodec::Create
386 //==========================================================================
387 void VVorbisSampleLoader::Load (sfxinfo_t
&Sfx
, VStream
&Stream
) {
388 VVorbisAudioCodec
*Codec
= new VVorbisAudioCodec(&Stream
, false);
389 //GCon->Logf(NAME_Debug, "trying sfx '%s' (VVorbisSampleLoader)", *Stream.GetName());
390 if (!Codec
->Init()) {
393 LoadFromAudioCodec(Sfx
, Codec
);