1 /*******************************************************************************
2 * Goggles Audio Player Library *
3 ********************************************************************************
4 * Copyright (C) 2010-2021 by Sander Jansen. All Rights Reserved *
5 * --- *
6 * This program is free software: you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see http://www.gnu.org/licenses. *
18 ********************************************************************************/
19 #include "ap_defs.h"
20 #include "ap_format.h"
21 #include "ap_common.h"
22
23
24 namespace ap {
25
26 static const FXchar * const channelnames[]={
27 "NA","MONO","FL","FR","FC","BL","BR","BC","SL","SR","LFE"
28 };
29
30 static const FXchar * const codecs[]={
31 "Invalid",
32 "PCM",
33 "FLAC",
34 "Vorbis",
35 "MPEG",
36 "AAC",
37 "Opus",
38 "ALAC",
39 "DCA",
40 "A52"
41 };
42
43 static const FXchar * const byteorders[]={
44 "le",
45 "be"
46 };
47
48 static const FXchar * const formats[]={
49 "s",
50 "u",
51 "f",
52 "iec958_frame"
53 "Reserved1"
54 "Reserved2"
55 "Reserved3"
56 "Reserved4"
57 };
58
59
60 static const FXchar * const formatnames[]={
61 "unknown",
62 "wav",
63 "ogg",
64 "flac",
65 "mp3",
66 "mp4",
67 "aac",
68 "m3u",
69 "pls",
70 "xspf",
71 "aiff",
72 "matroska"
73 };
74
75
name(FXuchar c)76 const FXchar * Codec::name(FXuchar c){
77 return codecs[c];
78 }
79
80
81
82
83 #if defined(HAVE_OPUS) || defined(HAVE_VORBIS) || defined(HAVE_TREMOR)
84
85 // http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html
86 extern const FXuint vorbis_channel_map[]={
87 AP_CHANNELMAP_MONO,
88
89 AP_CHANNELMAP_STEREO,
90
91 AP_CMAP3(Channel::FrontLeft,
92 Channel::FrontCenter,
93 Channel::FrontRight),
94
95 AP_CMAP4(Channel::FrontLeft,
96 Channel::FrontRight,
97 Channel::BackLeft,
98 Channel::BackRight),
99
100 AP_CMAP5(Channel::FrontLeft,
101 Channel::FrontCenter,
102 Channel::FrontRight,
103 Channel::BackLeft,
104 Channel::BackRight),
105
106 AP_CMAP6(Channel::FrontLeft,
107 Channel::FrontCenter,
108 Channel::FrontRight,
109 Channel::BackLeft,
110 Channel::BackRight,
111 Channel::LFE),
112
113 AP_CMAP7(Channel::FrontLeft,
114 Channel::FrontCenter,
115 Channel::FrontRight,
116 Channel::SideLeft,
117 Channel::SideRight,
118 Channel::BackCenter,
119 Channel::LFE),
120
121 AP_CMAP8(Channel::FrontLeft,
122 Channel::FrontCenter,
123 Channel::FrontRight,
124 Channel::SideLeft,
125 Channel::SideRight,
126 Channel::BackLeft,
127 Channel::BackRight,
128 Channel::LFE)
129 };
130
131 #endif
132
133
reset()134 void AudioFormat::reset() {
135 format=0;
136 rate=0;
137 channels=0;
138 channelmap=0;
139 }
140
setBits(FXushort bits)141 void AudioFormat::setBits(FXushort bits) {
142 if (bits>0 && bits<=32) {
143 format|=(bits-1)<<Format::Bits_Shift|(((bits/8)-1)<<Format::Pack_Shift);
144 }
145 }
146
setChannels(FXuchar ch)147 void AudioFormat::setChannels(FXuchar ch) {
148 if (ch>0 && ch<=8) {
149 channels=ch;
150 switch(channels) {
151 case 1: channelmap = AP_CHANNELMAP_MONO; break;
152 case 2: channelmap = AP_CHANNELMAP_STEREO; break;
153 default: channelmap = 0; break;
154 }
155 }
156 }
157
158
set(FXushort dt,FXushort bits,FXushort pack,FXuint r,FXuchar nc,FXuint map)159 void AudioFormat::set(FXushort dt,FXushort bits,FXushort pack,FXuint r,FXuchar nc,FXuint map) {
160 format=dt|((bits-1)<<Format::Bits_Shift)|((pack-1)<<Format::Pack_Shift);
161 rate=r;
162 channels=nc;
163 channelmap=map;
164 if (channelmap==0) {
165 switch(channels) {
166 case 1: channelmap = AP_CHANNELMAP_MONO; break;
167 case 2: channelmap = AP_CHANNELMAP_STEREO; break;
168 default: channelmap = 0; break;
169 };
170 }
171 }
172
set(FXushort fmt,FXuint r,FXuchar nc,FXuint map)173 void AudioFormat::set(FXushort fmt,FXuint r,FXuchar nc,FXuint map) {
174 format=fmt;
175 rate=r;
176 channels=nc;
177 channelmap=map;
178 if (channelmap==0) {
179 switch(channels) {
180 case 1: channelmap = AP_CHANNELMAP_MONO; break;
181 case 2: channelmap = AP_CHANNELMAP_STEREO; break;
182 default: channelmap = 0; break;
183 };
184 }
185 }
186
187
swap()188 FXbool AudioFormat::swap() {
189 if (packing()>Format::Pack_1) {
190 format^=(1<<Format::Order_Shift);
191 return true;
192 }
193 else {
194 return false;
195 }
196 }
197
198
199 /*
200 24 -> 32 -> 16
201 flt -> 32 -> 16
202 */
203
compatible()204 FXbool AudioFormat::compatible() {
205 switch(format){
206 case AP_FORMAT_S24_3BE : format=AP_FORMAT_S24_BE; break;
207 case AP_FORMAT_S24_3LE : format=AP_FORMAT_S24_LE; break;
208 case AP_FORMAT_S24_LE : format=AP_FORMAT_S32_LE; break;
209 case AP_FORMAT_S24_BE : format=AP_FORMAT_S32_BE; break;
210 case AP_FORMAT_S32_LE : format=AP_FORMAT_S16_LE; break;
211 case AP_FORMAT_S32_BE : format=AP_FORMAT_S16_BE; break;
212 case AP_FORMAT_FLOAT_LE : format=AP_FORMAT_S32_LE; break;
213 case AP_FORMAT_FLOAT_BE : format=AP_FORMAT_S32_BE; break;
214 default : return false; break;
215 }
216 return true;
217 }
218
219
debug_format() const220 FXString AudioFormat::debug_format() const {
221 return FXString::value("%s%2d%s%d",formats[datatype()],bps(),byteorders[byteorder()],packing());
222 }
223
debug() const224 void AudioFormat::debug() const {
225 fxmessage("format: %6dHz, %dch, %s%2d%s%d",rate,channels,formats[datatype()],bps(),byteorders[byteorder()],packing());
226 if (channels) {
227 fxmessage(", (%s",channelnames[channeltype(0)]);
228 for (FXuint i=1;i<channels;i++) {
229 fxmessage(",%s",channelnames[channeltype(i)]);
230 }
231 fxmessage(")\n");
232 }
233 else {
234 fxmessage("\n");
235 }
236 }
237
238
operator !=(const AudioFormat & af1,const AudioFormat & af2)239 FXbool operator!=(const AudioFormat& af1,const AudioFormat& af2){
240 if ( (af1.format!=af2.format) ||
241 (af1.rate!=af2.rate) ||
242 (af1.channels!=af2.channels) ||
243 (af1.channelmap!=af2.channelmap) )
244 return true;
245 else
246 return false;
247 }
248
operator ==(const AudioFormat & af1,const AudioFormat & af2)249 FXbool operator==(const AudioFormat& af1,const AudioFormat& af2){
250 if ( (af1.format!=af2.format) ||
251 (af1.rate!=af2.rate) ||
252 (af1.channels!=af2.channels) ||
253 (af1.channelmap!=af2.channelmap) )
254 return false;
255 else
256 return true;
257 }
258
259
ap_format_from_mime(const FXString & mime)260 extern FXuint ap_format_from_mime(const FXString & mime) {
261 if (comparecase(mime,"audio/mpeg")==0) {
262 return Format::MP3;
263 }
264 else if (comparecase(mime,"audio/ogg")==0 ||
265 comparecase(mime,"application/ogg")==0 ||
266 comparecase(mime,"audio/opus")==0){
267 return Format::OGG;
268 }
269 else if (comparecase(mime,"audio/aacp")==0 ||
270 comparecase(mime,"audio/aac")==0) {
271 return Format::AAC;
272 }
273 else if (comparecase(mime,"audio/x-mpegurl")==0 ||
274 comparecase(mime,"audio/mpegurl")==0) {
275 return Format::M3U;
276 }
277 else if ((comparecase(mime,"application/pls+xml")==0) || /// wrong mimetype, but NPR actually returns this: http://www.npr.org/streams/mp3/nprlive24.pls
278 (comparecase(mime,"audio/x-scpls")==0)){
279 return Format::PLS;
280 }
281 else if (comparecase(mime,"application/xspf+xml")==0){
282 return Format::XSPF;
283 }
284 else if (comparecase(mime,"audio/x-aiff")==0 ||
285 comparecase(mime,"audio/aiff")==0) {
286 return Format::AIFF;
287 }
288 else if (comparecase(mime,"video/webm")==0){
289 return Format::Matroska;
290 }
291
292 else {
293 return Format::Unknown;
294 }
295 }
296
ap_format_from_extension(const FXString & extension)297 extern FXuint ap_format_from_extension(const FXString & extension) {
298 if (comparecase(extension,"wav")==0)
299 return Format::WAV;
300 else if (comparecase(extension,"flac")==0)
301 return Format::FLAC;
302 else if (comparecase(extension,"ogg")==0 || comparecase(extension,"oga")==0 || comparecase(extension,"opus")==0)
303 return Format::OGG;
304 else if (comparecase(extension,"mp3")==0)
305 return Format::MP3;
306 else if (comparecase(extension,"mp4")==0 ||
307 comparecase(extension,"m4a")==0 ||
308 comparecase(extension,"m4p")==0 ||
309 comparecase(extension,"mov")==0 ||
310 comparecase(extension,"m4b")==0 )
311 return Format::MP4;
312 else if (comparecase(extension,"aac")==0)
313 return Format::AAC;
314 else if (comparecase(extension,"aiff")==0 || comparecase(extension,"aif")==0)
315 return Format::AIFF;
316 else if (comparecase(extension,"m3u")==0)
317 return Format::M3U;
318 else if (comparecase(extension,"pls")==0)
319 return Format::PLS;
320 else if (comparecase(extension,"xspf")==0)
321 return Format::XSPF;
322 else if (comparecase(extension,"mkv")==0 || comparecase(extension,"webm")==0)
323 return Format::Matroska;
324 else
325 return Format::Unknown;
326 }
327
328
ap_format_from_buffer(const FXchar *,FXival)329 extern FXuint ap_format_from_buffer(const FXchar * /*buffer*/,FXival /*size*/) {
330 return Format::Unknown;
331 }
332
ap_format_name(FXuint format)333 extern const FXchar * ap_format_name(FXuint format){
334 return formatnames[format];
335 }
336
337
ap_get_gogglesmm_all_supported_files()338 extern FXString ap_get_gogglesmm_all_supported_files() {
339 const FXchar * const supported = "*.("
340 #if defined(HAVE_OPUS)
341 "opus,"
342 #endif
343 #if defined(HAVE_FLAC)
344 "flac,oga,"
345 #endif
346 #if defined(HAVE_VORBIS) || defined(HAVE_TREMOR)
347 "ogg,"
348 #endif
349 #if defined(HAVE_MAD)
350 "mp3,"
351 #endif
352 #if defined(HAVE_MP4)
353 "mp4,m4a,m4b,m4p,mov,"
354 #endif
355 #if defined(HAVE_FAAD)
356 "aac,"
357 #endif
358 #if defined(HAVE_MATROSKA)
359 "mkv,mka,webm,"
360 #endif
361 "wav,aiff)"
362 ;
363 return supported;
364 }
365
366
ap_get_gogglesmm_supported_files()367 extern FXString ap_get_gogglesmm_supported_files() {
368 FXString pattern;
369 const FXchar * const supported = "*.("
370 #if defined(HAVE_OPUS)
371 "opus,"
372 #endif
373 #if defined(HAVE_FLAC)
374 "flac,oga,"
375 #endif
376 #if defined(HAVE_VORBIS) || defined(HAVE_TREMOR)
377 "ogg,"
378 #endif
379 #if defined(HAVE_MAD)
380 "mp3,"
381 #endif
382 #if defined(HAVE_MP4)
383 "mp4,m4a,m4b,m4p,mov,"
384 #endif
385 #if defined(HAVE_FAAD)
386 "aac,"
387 #endif
388 ;
389
390 if (strlen(supported)==3)
391 return FXString::null;
392
393 pattern = supported;
394 pattern.tail() = ')';
395 return pattern;
396 }
397
398
ap_get_gogglesmm_filepatterns()399 extern FXString ap_get_gogglesmm_filepatterns() {
400 const FXchar * const patterns =
401
402 "All Music ("
403 #if defined(HAVE_OPUS)
404 "*.opus,"
405 #endif
406 #if defined(HAVE_FLAC)
407 "*.flac,*.oga,"
408 #endif
409 #if defined(HAVE_VORBIS) || defined(HAVE_TREMOR)
410 "*.ogg,"
411 #endif
412 #if defined(HAVE_MAD)
413 "*.mp3,"
414 #endif
415 #if defined(HAVE_MP4)
416 "*.mp4,*.m4a,*.m4b,*.m4p,*.mov,"
417 #endif
418 #if defined(HAVE_FAAD)
419 "*.aac,"
420 #endif
421 #if defined(HAVE_MATROSKA)
422 "*.mka,*.webm"
423 #endif
424 "*.wav,*.aiff)\n"
425
426 // All Media
427
428 "All Media ("
429 #if defined(HAVE_OPUS)
430 "*.opus,"
431 #endif
432 #if defined(HAVE_FLAC)
433 "*.flac,*.oga,"
434 #endif
435 #if defined(HAVE_VORBIS) || defined(HAVE_TREMOR)
436 "*.ogg,"
437 #endif
438 #if defined(HAVE_MAD)
439 "*.mp3,"
440 #endif
441 #if defined(HAVE_MP4)
442 "*.mp4,*.m4a,*.m4b,*.m4p,*.mov,"
443 #endif
444 #if defined(HAVE_FAAD)
445 "*.aac,"
446 #endif
447 #if defined(HAVE_MATROSKA)
448 "*.mkv,*.mka,*.webm"
449 #endif
450 "*.wav,*.aiff)\n"
451
452 #if defined(HAVE_OPUS)
453 "Opus (*.opus)\n"
454 #endif
455 #if defined(HAVE_FLAC)
456 "Free Lossless Audio Codec (*.flac,*.oga)\n"
457 #endif
458 #if defined(HAVE_VORBIS) || defined(HAVE_TREMOR)
459 "Ogg Vorbis (*.ogg)\n"
460 #endif
461 #if defined(HAVE_MAD)
462 "MPEG-1 Audio Layer 3 (*.mp3)\n"
463 #endif
464 #if defined(HAVE_MP4)
465 "MPEG-4 Part 14 (*.mp4,*.m4a,*.m4p,*.m4b,*.mov)\n"
466 #endif
467 #if defined(HAVE_FAAD)
468 "Advanced Audio Coding (*.aac)\n"
469 #endif
470 #if defined(HAVE_MATROSKA)
471 "Matroska (*.mka,*.webm)"
472 #endif
473 "Wav (*.wav,*.aiff)\n";
474
475 return patterns;
476 }
477
478
479
480
481
482
483
484 }
485