2 * \file audio_decoder_vorbis.cpp
3 * \brief CAudioDecoderVorbis
4 * \date 2012-04-11 09:35GMT
5 * \author Jan Boon (Kaetemi)
9 // NeL - MMORPG Framework <https://wiki.ryzom.dev/>
10 // Copyright (C) 2008-2012 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
12 // This source file has been modified by the following contributors:
13 // Copyright (C) 2016 Winch Gate Property Limited
15 // This program is free software: you can redistribute it and/or modify
16 // it under the terms of the GNU Affero General Public License as
17 // published by the Free Software Foundation, either version 3 of the
18 // License, or (at your option) any later version.
20 // This program is distributed in the hope that it will be useful,
21 // but WITHOUT ANY WARRANTY; without even the implied warranty of
22 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 // GNU Affero General Public License for more details.
25 // You should have received a copy of the GNU Affero General Public License
26 // along with this program. If not, see <http://www.gnu.org/licenses/>.
29 #include <nel/sound/audio_decoder_vorbis.h>
34 #include <nel/misc/debug.h>
39 using namespace NLMISC
;
43 size_t vorbisReadFunc(void *ptr
, size_t size
, size_t nmemb
, void *datasource
)
45 CAudioDecoderVorbis
*audio_decoder_vorbis
= (CAudioDecoderVorbis
*)datasource
;
46 NLMISC::IStream
*stream
= audio_decoder_vorbis
->getStream();
47 nlassert(stream
->isReading());
48 sint32 length
= (sint32
)(size
* nmemb
);
49 if (length
> audio_decoder_vorbis
->getStreamSize() - stream
->getPos())
50 length
= audio_decoder_vorbis
->getStreamSize() - stream
->getPos();
51 stream
->serialBuffer((uint8
*)ptr
, length
);
55 int vorbisSeekFunc(void *datasource
, ogg_int64_t offset
, int whence
)
57 if (whence
== SEEK_CUR
&& offset
== 0)
59 // nlwarning(NLSOUND_XAUDIO2_PREFIX "This seek call doesn't do a damn thing, wtf.");
60 return 0; // ooookkaaaaaayyy
63 CAudioDecoderVorbis
*audio_decoder_vorbis
= (CAudioDecoderVorbis
*)datasource
;
65 NLMISC::IStream::TSeekOrigin origin
;
69 origin
= NLMISC::IStream::begin
;
72 origin
= NLMISC::IStream::current
;
75 origin
= NLMISC::IStream::end
;
78 // nlwarning(NLSOUND_XAUDIO2_PREFIX "Seeking to fake origin.");
82 if (audio_decoder_vorbis
->getStream()->seek(SEEK_SET
? audio_decoder_vorbis
->getStreamOffset() + (sint32
)offset
: (sint32
)offset
, origin
)) return 0;
86 //int vorbisCloseFunc(void *datasource)
88 // //CAudioDecoderVorbis *audio_decoder_vorbis = (CAudioDecoderVorbis *)datasource;
91 long vorbisTellFunc(void *datasource
)
93 CAudioDecoderVorbis
*audio_decoder_vorbis
= (CAudioDecoderVorbis
*)datasource
;
94 return (long)(audio_decoder_vorbis
->getStream()->getPos() - audio_decoder_vorbis
->getStreamOffset());
97 static ov_callbacks OV_CALLBACKS_NLMISC_STREAM
= {
98 (size_t (*)(void *, size_t, size_t, void *)) vorbisReadFunc
,
99 (int (*)(void *, ogg_int64_t
, int)) vorbisSeekFunc
,
100 (int (*)(void *)) NULL
, //vorbisCloseFunc,
101 (long (*)(void *)) vorbisTellFunc
104 CAudioDecoderVorbis::CAudioDecoderVorbis(NLMISC::IStream
*stream
, bool loop
)
105 : _Stream(stream
), _Loop(loop
), _IsMusicEnded(false), _StreamSize(0)
107 _StreamOffset
= stream
->getPos();
108 stream
->seek(0, NLMISC::IStream::end
);
109 _StreamSize
= stream
->getPos();
110 stream
->seek(_StreamOffset
, NLMISC::IStream::begin
);
111 ov_open_callbacks(this, &_OggVorbisFile
, NULL
, 0, OV_CALLBACKS_NLMISC_STREAM
);
114 CAudioDecoderVorbis::~CAudioDecoderVorbis()
116 ov_clear(&_OggVorbisFile
);
119 /// Get information on a music file (only artist and title at the moment).
120 bool CAudioDecoderVorbis::getInfo(NLMISC::IStream
*stream
, std::string
&artist
, std::string
&title
, float &length
)
122 CAudioDecoderVorbis
mbv(stream
, false); // just opens and closes the oggvorbisfile thing :)
123 vorbis_comment
*vc
= ov_comment(&mbv
._OggVorbisFile
, -1);
124 char *title_c
= vorbis_comment_query(vc
, "title", 0);
125 if (title_c
) title
= title_c
; else title
.clear();
126 char *artist_c
= vorbis_comment_query(vc
, "artist", 0);
127 if (artist_c
) artist
= artist_c
; else artist
.clear();
128 length
= (float)ov_time_total(&mbv
._OggVorbisFile
, -1);
132 uint32
CAudioDecoderVorbis::getRequiredBytes()
134 return 0; // no minimum requirement of bytes to buffer out
137 uint32
CAudioDecoderVorbis::getNextBytes(uint8
*buffer
, uint32 minimum
, uint32 maximum
)
139 sint current_section
= 0; // ???
140 if (_IsMusicEnded
) return 0;
141 nlassert(minimum
<= maximum
); // can't have this..
142 uint32 bytes_read
= 0;
150 // signed 16-bit or unsigned 8-bit little-endian samples
151 sint br
= ov_read(&_OggVorbisFile
, (char *)&buffer
[bytes_read
], maximum
- bytes_read
,
152 endianness
, // Specifies big or little endian byte packing. 0 for little endian, 1 for b ig endian. Typical value is 0.
153 getBitsPerSample() == 8 ? 1 : 2,
154 getBitsPerSample() == 8 ? 0 : 1, // Signed or unsigned data. 0 for unsigned, 1 for signed. Typically 1.
156 // nlinfo(NLSOUND_XAUDIO2_PREFIX "current_section: %i", current_section);
159 bytes_read
+= (uint32
)br
;
161 else if (br
== 0) // EOF
165 ov_pcm_seek(&_OggVorbisFile
, 0);
166 //_Stream->seek(0, NLMISC::IStream::begin);
170 _IsMusicEnded
= true;
180 nlwarning("ov_read returned OV_HOLE");
183 nlwarning("ov_read returned OV_EINVAL");
186 nlwarning("ov_read returned OV_EBADLINK");
189 nlwarning("ov_read returned %d", br
);
192 } while (bytes_read
< minimum
);
196 uint8
CAudioDecoderVorbis::getChannels()
198 vorbis_info
*vi
= ov_info(&_OggVorbisFile
, -1);
199 if (vi
) return (uint8
)vi
->channels
;
200 nlwarning("ov_info returned NULL");
204 uint
CAudioDecoderVorbis::getSamplesPerSec()
206 vorbis_info
*vi
= ov_info(&_OggVorbisFile
, -1);
207 if (vi
) return (uint
)vi
->rate
;
208 nlwarning("ov_info returned NULL");
212 uint8
CAudioDecoderVorbis::getBitsPerSample()
217 bool CAudioDecoderVorbis::isMusicEnded()
219 return _IsMusicEnded
;
222 float CAudioDecoderVorbis::getLength()
224 return (float)ov_time_total(&_OggVorbisFile
, -1);
227 void CAudioDecoderVorbis::setLooping(bool loop
)
232 } /* namespace NLSOUND */