aboutsummaryrefslogtreecommitdiff
path: root/src/libmpg123/format.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libmpg123/format.c')
-rw-r--r--src/libmpg123/format.c395
1 files changed, 395 insertions, 0 deletions
diff --git a/src/libmpg123/format.c b/src/libmpg123/format.c
new file mode 100644
index 0000000..0b37bfa
--- /dev/null
+++ b/src/libmpg123/format.c
@@ -0,0 +1,395 @@
+/*
+ format:routines to deal with audio (output) format
+
+ copyright 2008-9 by the mpg123 project - free software under the terms of the LGPL 2.1
+ see COPYING and AUTHORS files in distribution or http://mpg123.org
+ initially written by Thomas Orgis, starting with parts of the old audio.c, with only faintly manage to show now
+*/
+
+#include "mpg123lib_intern.h"
+#include "debug.h"
+
+/* static int chans[NUM_CHANNELS] = { 1 , 2 }; */
+static const long my_rates[MPG123_RATES] = /* only the standard rates */
+{
+ 8000, 11025, 12000,
+ 16000, 22050, 24000,
+ 32000, 44100, 48000,
+};
+
+static const int my_encodings[MPG123_ENCODINGS] =
+{
+ MPG123_ENC_SIGNED_16,
+ MPG123_ENC_UNSIGNED_16,
+ MPG123_ENC_SIGNED_32,
+ MPG123_ENC_UNSIGNED_32,
+ MPG123_ENC_FLOAT_32,
+ MPG123_ENC_FLOAT_64,
+ MPG123_ENC_SIGNED_8,
+ MPG123_ENC_UNSIGNED_8,
+ MPG123_ENC_ULAW_8,
+ MPG123_ENC_ALAW_8
+};
+
+/* Only one type of float is supported. */
+# ifdef REAL_IS_FLOAT
+# define MPG123_FLOAT_ENC MPG123_ENC_FLOAT_32
+# else
+# define MPG123_FLOAT_ENC MPG123_ENC_FLOAT_64
+# endif
+
+/* The list of actually possible encodings. */
+static const int good_encodings[] =
+{
+#ifndef NO_16BIT
+ MPG123_ENC_SIGNED_16,
+ MPG123_ENC_UNSIGNED_16,
+#endif
+#ifndef NO_32BIT
+ MPG123_ENC_SIGNED_32,
+ MPG123_ENC_UNSIGNED_32,
+#endif
+#ifndef NO_REAL
+ MPG123_FLOAT_ENC,
+#endif
+#ifndef NO_8BIT
+ MPG123_ENC_SIGNED_8,
+ MPG123_ENC_UNSIGNED_8,
+ MPG123_ENC_ULAW_8,
+ MPG123_ENC_ALAW_8
+#endif
+};
+
+/* Check if encoding is a valid one in this build.
+ ...lazy programming: linear search. */
+static int good_enc(const int enc)
+{
+ size_t i;
+ for(i=0; i<sizeof(good_encodings)/sizeof(int); ++i)
+ if(enc == good_encodings[i]) return TRUE;
+
+ return FALSE;
+}
+
+void attribute_align_arg mpg123_rates(const long **list, size_t *number)
+{
+ if(list != NULL) *list = my_rates;
+ if(number != NULL) *number = sizeof(my_rates)/sizeof(long);
+}
+
+/* Now that's a bit tricky... One build of the library knows only a subset of the encodings. */
+void attribute_align_arg mpg123_encodings(const int **list, size_t *number)
+{
+ if(list != NULL) *list = good_encodings;
+ if(number != NULL) *number = sizeof(good_encodings)/sizeof(int);
+}
+
+/* char audio_caps[NUM_CHANNELS][MPG123_RATES+1][MPG123_ENCODINGS]; */
+
+static int rate2num(mpg123_pars *mp, long r)
+{
+ int i;
+ for(i=0;i<MPG123_RATES;i++) if(my_rates[i] == r) return i;
+#ifndef NO_NTOM
+ if(mp && mp->force_rate != 0 && mp->force_rate == r) return MPG123_RATES;
+#endif
+
+ return -1;
+}
+
+static int enc2num(int encoding)
+{
+ int i;
+ for(i=0;i<MPG123_ENCODINGS;++i)
+ if(my_encodings[i] == encoding) return i;
+
+ return -1;
+}
+
+static int cap_fit(mpg123_handle *fr, struct audioformat *nf, int f0, int f2)
+{
+ int i;
+ int c = nf->channels-1;
+ int rn = rate2num(&fr->p, nf->rate);
+ if(rn >= 0) for(i=f0;i<f2;i++)
+ {
+ if(fr->p.audio_caps[c][rn][i])
+ {
+ nf->encoding = my_encodings[i];
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int freq_fit(mpg123_handle *fr, struct audioformat *nf, int f0, int f2)
+{
+ nf->rate = frame_freq(fr)>>fr->p.down_sample;
+ if(cap_fit(fr,nf,f0,f2)) return 1;
+ nf->rate>>=1;
+ if(cap_fit(fr,nf,f0,f2)) return 1;
+ nf->rate>>=1;
+ if(cap_fit(fr,nf,f0,f2)) return 1;
+#ifndef NO_NTOM
+ /* If nothing worked, try the other rates, only without constrains from user.
+ In case you didn't guess: We enable flexible resampling if we find a working rate. */
+ if(!fr->p.force_rate && fr->p.down_sample == 0)
+ {
+ int i;
+ int c = nf->channels-1;
+ int rn = rate2num(&fr->p, frame_freq(fr));
+ int rrn;
+ if(rn < 0) return 0;
+ /* Try higher rates first. */
+ for(i=f0;i<f2;i++) for(rrn=rn+1; rrn<MPG123_RATES; ++rrn)
+ if(fr->p.audio_caps[c][rrn][i])
+ {
+ nf->rate = my_rates[rrn];
+ nf->encoding = my_encodings[i];
+ return 1;
+ }
+ /* Then lower rates. */
+ for(i=f0;i<f2;i++) for(rrn=rn-1; rrn>=0; --rrn)
+ if(fr->p.audio_caps[c][rrn][i])
+ {
+ nf->rate = my_rates[rrn];
+ nf->encoding = my_encodings[i];
+ return 1;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+/* match constraints against supported audio formats, store possible setup in frame
+ return: -1: error; 0: no format change; 1: format change */
+int frame_output_format(mpg123_handle *fr)
+{
+ struct audioformat nf;
+ int f0=0;
+ int f2=MPG123_ENCODINGS; /* Omit the 32bit and float encodings. */
+ mpg123_pars *p = &fr->p;
+ /* initialize new format, encoding comes later */
+ nf.channels = fr->stereo;
+
+ /* All this forcing should be removed in favour of the capabilities table... */
+ if(p->flags & MPG123_FORCE_8BIT)
+ {
+ f0 = 6;
+ f2 = 10;
+ }
+ if(p->flags & MPG123_FORCE_FLOAT)
+ {
+ f0 = 4;
+ f2 = 6;
+ }
+
+ /* force stereo is stronger */
+ if(p->flags & MPG123_FORCE_MONO) nf.channels = 1;
+ if(p->flags & MPG123_FORCE_STEREO) nf.channels = 2;
+
+#ifndef NO_NTOM
+ if(p->force_rate)
+ {
+ nf.rate = p->force_rate;
+ if(cap_fit(fr,&nf,f0,2)) goto end; /* 16bit encodings */
+ if(cap_fit(fr,&nf,f0<=2 ? 2 : f0,f2)) goto end; /* 8bit encodings */
+
+ /* try again with different stereoness */
+ if(nf.channels == 2 && !(p->flags & MPG123_FORCE_STEREO)) nf.channels = 1;
+ else if(nf.channels == 1 && !(p->flags & MPG123_FORCE_MONO)) nf.channels = 2;
+
+ if(cap_fit(fr,&nf,f0,2)) goto end; /* 16bit encodings */
+ if(cap_fit(fr,&nf,f0<=2 ? 2 : f0,f2)) goto end; /* 8bit encodings */
+
+ if(NOQUIET)
+ error3( "Unable to set up output format! Constraints: %s%s%liHz.",
+ ( p->flags & MPG123_FORCE_STEREO ? "stereo, " :
+ (p->flags & MPG123_FORCE_MONO ? "mono, " : "") ),
+ (p->flags & MPG123_FORCE_8BIT ? "8bit, " : ""),
+ p->force_rate );
+/* if(NOQUIET && p->verbose <= 1) print_capabilities(fr); */
+
+ fr->err = MPG123_BAD_OUTFORMAT;
+ return -1;
+ }
+#endif
+
+ if(freq_fit(fr, &nf, f0, 2)) goto end; /* try rates with 16bit */
+ if(freq_fit(fr, &nf, f0<=2 ? 2 : f0, f2)) goto end; /* ... 8bit */
+
+ /* try again with different stereoness */
+ if(nf.channels == 2 && !(p->flags & MPG123_FORCE_STEREO)) nf.channels = 1;
+ else if(nf.channels == 1 && !(p->flags & MPG123_FORCE_MONO)) nf.channels = 2;
+
+ if(freq_fit(fr, &nf, f0, 2)) goto end; /* try rates with 16bit */
+ if(freq_fit(fr, &nf, f0<=2 ? 2 : f0, f2)) goto end; /* ... 8bit */
+
+ /* Here is the _bad_ end. */
+ if(NOQUIET)
+ {
+ error5( "Unable to set up output format! Constraints: %s%s%li, %li or %liHz.",
+ ( p->flags & MPG123_FORCE_STEREO ? "stereo, " :
+ (p->flags & MPG123_FORCE_MONO ? "mono, " : "") ),
+ (p->flags & MPG123_FORCE_8BIT ? "8bit, " : ""),
+ frame_freq(fr), frame_freq(fr)>>1, frame_freq(fr)>>2 );
+ }
+/* if(NOQUIET && p->verbose <= 1) print_capabilities(fr); */
+
+ fr->err = MPG123_BAD_OUTFORMAT;
+ return -1;
+
+end: /* Here is the _good_ end. */
+ /* we had a successful match, now see if there's a change */
+ if(nf.rate == fr->af.rate && nf.channels == fr->af.channels && nf.encoding == fr->af.encoding)
+ {
+ debug2("Old format with %i channels, and FORCE_MONO=%li", nf.channels, p->flags & MPG123_FORCE_MONO);
+ return 0; /* the same format as before */
+ }
+ else /* a new format */
+ {
+ debug1("New format with %i channels!", nf.channels);
+ fr->af.rate = nf.rate;
+ fr->af.channels = nf.channels;
+ fr->af.encoding = nf.encoding;
+ /* Cache the size of one sample in bytes, for ease of use. */
+ if(fr->af.encoding & MPG123_ENC_8)
+ fr->af.encsize = 1;
+ else if(fr->af.encoding & MPG123_ENC_16)
+ fr->af.encsize = 2;
+ else if(fr->af.encoding & MPG123_ENC_32 || fr->af.encoding == MPG123_ENC_FLOAT_32)
+ fr->af.encsize = 4;
+ else if(fr->af.encoding == MPG123_ENC_FLOAT_64)
+ fr->af.encsize = 8;
+ else
+ {
+ if(NOQUIET) error1("Some unknown encoding??? (%i)", fr->af.encoding);
+
+ fr->err = MPG123_BAD_OUTFORMAT;
+ return -1;
+ }
+ return 1;
+ }
+}
+
+int attribute_align_arg mpg123_format_none(mpg123_handle *mh)
+{
+ int r;
+ if(mh == NULL) return MPG123_ERR;
+
+ r = mpg123_fmt_none(&mh->p);
+ if(r != MPG123_OK){ mh->err = r; r = MPG123_ERR; }
+
+ return r;
+}
+
+int attribute_align_arg mpg123_fmt_none(mpg123_pars *mp)
+{
+ if(mp == NULL) return MPG123_BAD_PARS;
+
+ if(PVERB(mp,3)) fprintf(stderr, "Note: Disabling all formats.\n");
+
+ memset(mp->audio_caps,0,sizeof(mp->audio_caps));
+ return MPG123_OK;
+}
+
+int attribute_align_arg mpg123_format_all(mpg123_handle *mh)
+{
+ int r;
+ if(mh == NULL) return MPG123_ERR;
+
+ r = mpg123_fmt_all(&mh->p);
+ if(r != MPG123_OK){ mh->err = r; r = MPG123_ERR; }
+
+ return r;
+}
+
+int attribute_align_arg mpg123_fmt_all(mpg123_pars *mp)
+{
+ size_t rate, ch, enc;
+ if(mp == NULL) return MPG123_BAD_PARS;
+
+ if(PVERB(mp,3)) fprintf(stderr, "Note: Enabling all formats.\n");
+
+ for(ch=0; ch < NUM_CHANNELS; ++ch)
+ for(rate=0; rate < MPG123_RATES+1; ++rate)
+ for(enc=0; enc < MPG123_ENCODINGS; ++enc)
+ mp->audio_caps[ch][rate][enc] = good_enc(my_encodings[enc]) ? 1 : 0;
+
+ return MPG123_OK;
+}
+
+int attribute_align_arg mpg123_format(mpg123_handle *mh, long rate, int channels, int encodings)
+{
+ int r;
+ if(mh == NULL) return MPG123_ERR;
+ r = mpg123_fmt(&mh->p, rate, channels, encodings);
+ if(r != MPG123_OK){ mh->err = r; r = MPG123_ERR; }
+
+ return r;
+}
+
+int attribute_align_arg mpg123_fmt(mpg123_pars *mp, long rate, int channels, int encodings)
+{
+ int ie, ic, ratei;
+ int ch[2] = {0, 1};
+ if(mp == NULL) return MPG123_BAD_PARS;
+ if(!(channels & (MPG123_MONO|MPG123_STEREO))) return MPG123_BAD_CHANNEL;
+
+ if(PVERB(mp,3)) fprintf(stderr, "Note: Want to enable format %li/%i for encodings 0x%x.\n", rate, channels, encodings);
+
+ if(!(channels & MPG123_STEREO)) ch[1] = 0; /* {0,0} */
+ else if(!(channels & MPG123_MONO)) ch[0] = 1; /* {1,1} */
+ ratei = rate2num(mp, rate);
+ if(ratei < 0) return MPG123_BAD_RATE;
+
+ /* now match the encodings */
+ for(ic = 0; ic < 2; ++ic)
+ {
+ for(ie = 0; ie < MPG123_ENCODINGS; ++ie)
+ if(good_enc(my_encodings[ie]) && ((my_encodings[ie] & encodings) == my_encodings[ie]))
+ mp->audio_caps[ch[ic]][ratei][ie] = 1;
+
+ if(ch[0] == ch[1]) break; /* no need to do it again */
+ }
+
+ return MPG123_OK;
+}
+
+int attribute_align_arg mpg123_format_support(mpg123_handle *mh, long rate, int encoding)
+{
+ if(mh == NULL) return 0;
+ else return mpg123_fmt_support(&mh->p, rate, encoding);
+}
+
+int attribute_align_arg mpg123_fmt_support(mpg123_pars *mp, long rate, int encoding)
+{
+ int ch = 0;
+ int ratei, enci;
+ ratei = rate2num(mp, rate);
+ enci = enc2num(encoding);
+ if(mp == NULL || ratei < 0 || enci < 0) return 0;
+ if(mp->audio_caps[0][ratei][enci]) ch |= MPG123_MONO;
+ if(mp->audio_caps[1][ratei][enci]) ch |= MPG123_STEREO;
+ return ch;
+}
+
+/* Call this one to ensure that any valid format will be something different than this. */
+void invalidate_format(struct audioformat *af)
+{
+ af->encoding = 0;
+ af->rate = 0;
+ af->channels = 0;
+}
+
+/* take into account: channels, bytes per sample -- NOT resampling!*/
+off_t samples_to_bytes(mpg123_handle *fr , off_t s)
+{
+ return s * fr->af.encsize * fr->af.channels;
+}
+
+off_t bytes_to_samples(mpg123_handle *fr , off_t b)
+{
+ return b / fr->af.encsize / fr->af.channels;
+}