xash3d-fwgs/engine/common/soundlib/libmpg/format.c
Gleb Mazovetskiy 5e0a0765ce Trim all trailing whitespace
The `.editorconfig` file in this repo is configured to trim all trailing
whitespace regardless of whether the line is modified.

Trims all trailing whitespace in the repository to make the codebase easier
to work with in editors that respect `.editorconfig`.

`git blame` becomes less useful on these lines but it already isn't very useful.

Commands:

```
find . -type f -name '*.h' -exec sed --in-place 's/[[:space:]]\+$//' {} \+
find . -type f -name '*.c' -exec sed --in-place 's/[[:space:]]\+$//' {} \+
```
2021-01-04 20:55:10 +03:00

436 lines
8.7 KiB
C

/*
frame.c - compact version of famous library mpg123
Copyright (C) 2017 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "mpg123.h"
enum mpg123_channelcount
{
MPG123_MONO = 1,
MPG123_STEREO = 2
};
// only the standard rates
static const long my_rates[MPG123_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,
};
// the list of actually possible encodings.
static const int good_encodings[] =
{
MPG123_ENC_SIGNED_16,
MPG123_ENC_UNSIGNED_16,
};
// check if encoding is a valid one in this build.
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 mpg123_rates( const long **list, size_t *number )
{
if( number != NULL ) *number = sizeof( my_rates ) / sizeof( long );
if( list != NULL ) *list = my_rates;
}
// now that's a bit tricky... One build of the library knows only a subset of the encodings.
void mpg123_encodings( const int **list, size_t *number )
{
if( number != NULL ) *number = sizeof( good_encodings ) / sizeof( int );
if( list != NULL ) *list = good_encodings;
}
int mpg123_encsize( int encoding )
{
return sizeof( short );
}
static int rate2num( long r )
{
int i;
for( i = 0; i < MPG123_RATES; i++ )
{
if( my_rates[i] == r )
return i;
}
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_t *fr, audioformat_t *nf, int f0, int f2)
{
int i;
int c = nf->channels - 1;
int rn = rate2num( 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_t *fr, audioformat_t *nf, int f0, int f2 )
{
nf->rate = frame_freq( fr ) >> fr->p.down_sample;
if( cap_fit( fr, nf, f0, f2 ))
return 1;
if( fr->p.flags & MPG123_AUTO_RESAMPLE )
{
nf->rate >>= 1;
if( cap_fit( fr, nf, f0, f2 ))
return 1;
nf->rate >>= 1;
if( cap_fit( fr, nf, f0, f2 ))
return 1;
}
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_t *fr )
{
int f0 = 0;
int f2 = MPG123_ENCODINGS;
mpg123_parm_t *p = &fr->p;
audioformat_t nf;
// initialize new format, encoding comes later
nf.channels = fr->stereo;
// force stereo is stronger
if( p->flags & MPG123_FORCE_MONO )
nf.channels = 1;
if( p->flags & MPG123_FORCE_STEREO )
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
// 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
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 )
{
return 0; // the same format as before
}
else
{ // a new format
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.
fr->af.encsize = mpg123_encsize( fr->af.encoding );
if( fr->af.encsize < 1 )
{
fr->err = MPG123_BAD_OUTFORMAT;
return -1;
}
// set up the decoder synth format. Might differ.
// without high-precision synths, 16 bit signed is the basis for
// everything higher than 8 bit.
if( fr->af.encsize > 2 )
{
fr->af.dec_enc = MPG123_ENC_SIGNED_16;
}
else
{
switch( fr->af.encoding )
{
case MPG123_ENC_UNSIGNED_16:
fr->af.dec_enc = MPG123_ENC_SIGNED_16;
break;
default:
fr->af.dec_enc = fr->af.encoding;
break;
}
}
fr->af.dec_encsize = mpg123_encsize( fr->af.dec_enc );
return 1;
}
}
static int mpg123_fmt_none( mpg123_parm_t *mp )
{
if( mp == NULL )
return MPG123_BAD_PARS;
memset( mp->audio_caps, 0, sizeof( mp->audio_caps ));
return MPG123_OK;
}
int mpg123_fmt_all( mpg123_parm_t *mp )
{
size_t rate, ch, enc;
if( mp == NULL )
return MPG123_BAD_PARS;
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] );
}
}
return MPG123_OK;
}
static int mpg123_fmt( mpg123_parm_t *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(!( channels & MPG123_STEREO ))
ch[1] = 0;
else if(!( channels & MPG123_MONO ))
ch[0] = 1;
ratei = rate2num( 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;
}
static int mpg123_fmt_support( mpg123_parm_t *mp, long rate, int encoding )
{
int ratei, enci;
int ch = 0;
ratei = rate2num( 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;
}
int mpg123_format_none( mpg123_handle_t *mh )
{
int r;
if( mh == NULL )
return MPG123_BAD_HANDLE;
r = mpg123_fmt_none( &mh->p );
if( r != MPG123_OK )
{
mh->err = r;
return MPG123_ERR;
}
return r;
}
int mpg123_format_all( mpg123_handle_t *mh )
{
int r;
if( mh == NULL )
return MPG123_BAD_HANDLE;
r = mpg123_fmt_all( &mh->p );
if( r != MPG123_OK )
{
mh->err = r;
return MPG123_ERR;
}
return r;
}
int mpg123_format( mpg123_handle_t *mh, long rate, int channels, int encodings )
{
int r;
if( mh == NULL )
return MPG123_BAD_HANDLE;
r = mpg123_fmt( &mh->p, rate, channels, encodings );
if( r != MPG123_OK )
{
mh->err = r;
return MPG123_ERR;
}
return r;
}
int mpg123_format_support( mpg123_handle_t *mh, long rate, int encoding )
{
if( mh == NULL )
return 0;
return mpg123_fmt_support( &mh->p, rate, encoding );
}
// call this one to ensure that any valid format will be something different than this.
void invalidate_format( audioformat_t *af )
{
af->encoding = 0;
af->channels = 0;
af->rate = 0;
}
// number of bytes the decoder produces.
mpg_off_t decoder_synth_bytes( mpg123_handle_t *fr, mpg_off_t s )
{
return s * fr->af.dec_encsize * fr->af.channels;
}
// samples/bytes for output buffer after post-processing.
// take into account: channels, bytes per sample -- NOT resampling!
mpg_off_t samples_to_bytes( mpg123_handle_t *fr, mpg_off_t s )
{
return s * fr->af.encsize * fr->af.channels;
}
mpg_off_t bytes_to_samples( mpg123_handle_t *fr, mpg_off_t b )
{
return b / fr->af.encsize / fr->af.channels;
}
// number of bytes needed for decoding _and_ post-processing.
mpg_off_t outblock_bytes( mpg123_handle_t *fr, mpg_off_t s )
{
int encsize = (fr->af.encsize > fr->af.dec_encsize ? fr->af.encsize : fr->af.dec_encsize);
return s * encsize * fr->af.channels;
}
static void conv_s16_to_u16( outbuffer_t *buf )
{
int16_t *ssamples = (int16_t *)buf->data;
uint16_t *usamples = (uint16_t *)buf->data;
size_t count = buf->fill / sizeof( int16_t );
size_t i;
for( i = 0; i < count; ++i )
{
long tmp = (long)ssamples[i] + 32768;
usamples[i] = (uint16_t)tmp;
}
}
void postprocess_buffer( mpg123_handle_t *fr )
{
switch( fr->af.dec_enc )
{
case MPG123_ENC_SIGNED_16:
switch( fr->af.encoding )
{
case MPG123_ENC_UNSIGNED_16:
conv_s16_to_u16(&fr->buffer);
break;
}
break;
}
}