aboutsummaryrefslogtreecommitdiffhomepage
path: root/audio/filter
diff options
context:
space:
mode:
Diffstat (limited to 'audio/filter')
-rw-r--r--audio/filter/af.c700
-rw-r--r--audio/filter/af.h349
-rw-r--r--audio/filter/af_bs2b.c274
-rw-r--r--audio/filter/af_center.c129
-rw-r--r--audio/filter/af_channels.c306
-rw-r--r--audio/filter/af_delay.c200
-rw-r--r--audio/filter/af_dummy.c76
-rw-r--r--audio/filter/af_equalizer.c248
-rw-r--r--audio/filter/af_export.c273
-rw-r--r--audio/filter/af_extrastereo.c157
-rw-r--r--audio/filter/af_format.c519
-rw-r--r--audio/filter/af_format_alaw.h324
-rw-r--r--audio/filter/af_format_ulaw.h837
-rw-r--r--audio/filter/af_hrtf.c670
-rw-r--r--audio/filter/af_hrtf.h511
-rw-r--r--audio/filter/af_karaoke.c98
-rw-r--r--audio/filter/af_ladspa.c915
-rw-r--r--audio/filter/af_lavcac3enc.c332
-rw-r--r--audio/filter/af_lavcresample.c213
-rw-r--r--audio/filter/af_pan.c210
-rw-r--r--audio/filter/af_resample.c394
-rw-r--r--audio/filter/af_resample_template.c171
-rw-r--r--audio/filter/af_scaletempo.c581
-rw-r--r--audio/filter/af_sinesuppress.c184
-rw-r--r--audio/filter/af_sub.c188
-rw-r--r--audio/filter/af_surround.c273
-rw-r--r--audio/filter/af_sweep.c103
-rw-r--r--audio/filter/af_tools.c110
-rw-r--r--audio/filter/af_volnorm.c353
-rw-r--r--audio/filter/af_volume.c226
-rw-r--r--audio/filter/control.h257
-rw-r--r--audio/filter/dsp.h32
-rw-r--r--audio/filter/equalizer.h48
-rw-r--r--audio/filter/filter.c360
-rw-r--r--audio/filter/filter.h75
-rw-r--r--audio/filter/window.c213
-rw-r--r--audio/filter/window.h43
37 files changed, 10952 insertions, 0 deletions
diff --git a/audio/filter/af.c b/audio/filter/af.c
new file mode 100644
index 0000000000..1f3e446821
--- /dev/null
+++ b/audio/filter/af.c
@@ -0,0 +1,700 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "osdep/strsep.h"
+
+#include "af.h"
+
+// Static list of filters
+extern struct af_info af_info_dummy;
+extern struct af_info af_info_delay;
+extern struct af_info af_info_channels;
+extern struct af_info af_info_format;
+extern struct af_info af_info_resample;
+extern struct af_info af_info_volume;
+extern struct af_info af_info_equalizer;
+extern struct af_info af_info_pan;
+extern struct af_info af_info_surround;
+extern struct af_info af_info_sub;
+extern struct af_info af_info_export;
+extern struct af_info af_info_volnorm;
+extern struct af_info af_info_extrastereo;
+extern struct af_info af_info_lavcac3enc;
+extern struct af_info af_info_lavcresample;
+extern struct af_info af_info_sweep;
+extern struct af_info af_info_hrtf;
+extern struct af_info af_info_ladspa;
+extern struct af_info af_info_center;
+extern struct af_info af_info_sinesuppress;
+extern struct af_info af_info_karaoke;
+extern struct af_info af_info_scaletempo;
+extern struct af_info af_info_bs2b;
+
+static struct af_info* filter_list[]={
+ &af_info_dummy,
+ &af_info_delay,
+ &af_info_channels,
+ &af_info_format,
+ &af_info_resample,
+ &af_info_volume,
+ &af_info_equalizer,
+ &af_info_pan,
+ &af_info_surround,
+ &af_info_sub,
+#ifdef HAVE_SYS_MMAN_H
+ &af_info_export,
+#endif
+ &af_info_volnorm,
+ &af_info_extrastereo,
+ &af_info_lavcac3enc,
+ &af_info_lavcresample,
+ &af_info_sweep,
+ &af_info_hrtf,
+#ifdef CONFIG_LADSPA
+ &af_info_ladspa,
+#endif
+ &af_info_center,
+ &af_info_sinesuppress,
+ &af_info_karaoke,
+ &af_info_scaletempo,
+#ifdef CONFIG_LIBBS2B
+ &af_info_bs2b,
+#endif
+ NULL
+};
+
+// CPU speed
+int* af_cpu_speed = NULL;
+
+/* Find a filter in the static list of filters using it's name. This
+ function is used internally */
+static struct af_info* af_find(char*name)
+{
+ int i=0;
+ while(filter_list[i]){
+ if(!strcmp(filter_list[i]->name,name))
+ return filter_list[i];
+ i++;
+ }
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "Couldn't find audio filter '%s'\n",name);
+ return NULL;
+}
+
+/* Find filter in the dynamic filter list using it's name This
+ function is used for finding already initialized filters */
+struct af_instance* af_get(struct af_stream* s, char* name)
+{
+ struct af_instance* af=s->first;
+ // Find the filter
+ while(af != NULL){
+ if(!strcmp(af->info->name,name))
+ return af;
+ af=af->next;
+ }
+ return NULL;
+}
+
+/*/ Function for creating a new filter of type name. The name may
+ contain the commandline parameters for the filter */
+static struct af_instance* af_create(struct af_stream* s, const char* name_with_cmd)
+{
+ char* name = strdup(name_with_cmd);
+ char* cmdline = name;
+
+ // Allocate space for the new filter and reset all pointers
+ struct af_instance* new=malloc(sizeof(struct af_instance));
+ if (!name || !new) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[libaf] Could not allocate memory\n");
+ goto err_out;
+ }
+ memset(new,0,sizeof(struct af_instance));
+
+ // Check for commandline parameters
+ strsep(&cmdline, "=");
+
+ // Find filter from name
+ if(NULL == (new->info=af_find(name)))
+ goto err_out;
+
+ /* Make sure that the filter is not already in the list if it is
+ non-reentrant */
+ if(new->info->flags & AF_FLAGS_NOT_REENTRANT){
+ if(af_get(s,name)){
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[libaf] There can only be one instance of"
+ " the filter '%s' in each stream\n",name);
+ goto err_out;
+ }
+ }
+
+ mp_msg(MSGT_AFILTER, MSGL_V, "[libaf] Adding filter %s \n",name);
+
+ // Initialize the new filter
+ if(AF_OK == new->info->open(new) &&
+ AF_ERROR < new->control(new,AF_CONTROL_POST_CREATE,&s->cfg)){
+ if(cmdline){
+ if(AF_ERROR>=new->control(new,AF_CONTROL_COMMAND_LINE,cmdline))
+ goto err_out;
+ }
+ free(name);
+ return new;
+ }
+
+err_out:
+ free(new);
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[libaf] Couldn't create or open audio filter '%s'\n",
+ name);
+ free(name);
+ return NULL;
+}
+
+/* Create and insert a new filter of type name before the filter in the
+ argument. This function can be called during runtime, the return
+ value is the new filter */
+static struct af_instance* af_prepend(struct af_stream* s, struct af_instance* af, const char* name)
+{
+ // Create the new filter and make sure it is OK
+ struct af_instance* new=af_create(s,name);
+ if(!new)
+ return NULL;
+ // Update pointers
+ new->next=af;
+ if(af){
+ new->prev=af->prev;
+ af->prev=new;
+ }
+ else
+ s->last=new;
+ if(new->prev)
+ new->prev->next=new;
+ else
+ s->first=new;
+ return new;
+}
+
+/* Create and insert a new filter of type name after the filter in the
+ argument. This function can be called during runtime, the return
+ value is the new filter */
+static struct af_instance* af_append(struct af_stream* s, struct af_instance* af, const char* name)
+{
+ // Create the new filter and make sure it is OK
+ struct af_instance* new=af_create(s,name);
+ if(!new)
+ return NULL;
+ // Update pointers
+ new->prev=af;
+ if(af){
+ new->next=af->next;
+ af->next=new;
+ }
+ else
+ s->first=new;
+ if(new->next)
+ new->next->prev=new;
+ else
+ s->last=new;
+ return new;
+}
+
+// Uninit and remove the filter "af"
+void af_remove(struct af_stream* s, struct af_instance* af)
+{
+ if(!af) return;
+
+ // Print friendly message
+ mp_msg(MSGT_AFILTER, MSGL_V, "[libaf] Removing filter %s \n",af->info->name);
+
+ // Notify filter before changing anything
+ af->control(af,AF_CONTROL_PRE_DESTROY,0);
+
+ // Detach pointers
+ if(af->prev)
+ af->prev->next=af->next;
+ else
+ s->first=af->next;
+ if(af->next)
+ af->next->prev=af->prev;
+ else
+ s->last=af->prev;
+
+ // Uninitialize af and free memory
+ af->uninit(af);
+ free(af);
+}
+
+static void print_fmt(struct mp_audio *d)
+{
+ if (d) {
+ mp_msg(MSGT_AFILTER, MSGL_V, "%dHz/%dch/%s", d->rate, d->nch,
+ af_fmt2str_short(d->format));
+ } else {
+ mp_msg(MSGT_AFILTER, MSGL_V, "(?)");
+ }
+}
+
+static void af_print_filter_chain(struct af_stream* s)
+{
+ mp_msg(MSGT_AFILTER, MSGL_V, "Audio filter chain:\n");
+
+ mp_msg(MSGT_AFILTER, MSGL_V, " [in] ");
+ print_fmt(&s->input);
+ mp_msg(MSGT_AFILTER, MSGL_V, "\n");
+
+ struct af_instance *af = s->first;
+ while (af) {
+ mp_msg(MSGT_AFILTER, MSGL_V, " [%s] ", af->info->name);
+ print_fmt(af->data);
+ mp_msg(MSGT_AFILTER, MSGL_V, "\n");
+
+ af = af->next;
+ }
+
+ mp_msg(MSGT_AFILTER, MSGL_V, " [out] ");
+ print_fmt(&s->output);
+ mp_msg(MSGT_AFILTER, MSGL_V, "\n");
+}
+
+// Warning:
+// A failed af_reinit() leaves the audio chain behind in a useless, broken
+// state (for example, format filters that were tentatively inserted stay
+// inserted).
+// In that case, you should always rebuild the filter chain, or abort.
+int af_reinit(struct af_stream* s, struct af_instance* af)
+{
+ do{
+ struct mp_audio in; // Format of the input to current filter
+ int rv=0; // Return value
+
+ // Check if there are any filters left in the list
+ if(NULL == af){
+ if(!(af=af_append(s,s->first,"dummy")))
+ return AF_UNKNOWN;
+ else
+ return AF_ERROR;
+ }
+
+ // Check if this is the first filter
+ if(!af->prev)
+ memcpy(&in,&(s->input),sizeof(struct mp_audio));
+ else
+ memcpy(&in,af->prev->data,sizeof(struct mp_audio));
+ // Reset just in case...
+ in.audio=NULL;
+ in.len=0;
+
+ rv = af->control(af,AF_CONTROL_REINIT,&in);
+ switch(rv){
+ case AF_OK:
+ af = af->next;
+ break;
+ case AF_FALSE:{ // Configuration filter is needed
+ // Do auto insertion only if force is not specified
+ if((AF_INIT_TYPE_MASK & s->cfg.force) != AF_INIT_FORCE){
+ struct af_instance* new = NULL;
+ // Insert channels filter
+ if((af->prev?af->prev->data->nch:s->input.nch) != in.nch){
+ // Create channels filter
+ if(NULL == (new = af_prepend(s,af,"channels")))
+ return AF_ERROR;
+ // Set number of output channels
+ if(AF_OK != (rv = new->control(new,AF_CONTROL_CHANNELS,&in.nch)))
+ return rv;
+ // Initialize channels filter
+ if(!new->prev)
+ memcpy(&in,&(s->input),sizeof(struct mp_audio));
+ else
+ memcpy(&in,new->prev->data,sizeof(struct mp_audio));
+ if(AF_OK != (rv = new->control(new,AF_CONTROL_REINIT,&in)))
+ return rv;
+ }
+ // Insert format filter
+ if((af->prev?af->prev->data->format:s->input.format) != in.format){
+ // Create format filter
+ if(NULL == (new = af_prepend(s,af,"format")))
+ return AF_ERROR;
+ // Set output bits per sample
+ in.format |= af_bits2fmt(in.bps*8);
+ if(AF_OK != (rv = new->control(new,AF_CONTROL_FORMAT_FMT,&in.format)))
+ return rv;
+ // Initialize format filter
+ if(!new->prev)
+ memcpy(&in,&(s->input),sizeof(struct mp_audio));
+ else
+ memcpy(&in,new->prev->data,sizeof(struct mp_audio));
+ if(AF_OK != (rv = new->control(new,AF_CONTROL_REINIT,&in)))
+ return rv;
+ }
+ if(!new){ // Should _never_ happen
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[libaf] Unable to correct audio format. "
+ "This error should never occur, please send a bug report.\n");
+ return AF_ERROR;
+ }
+ af=new->next;
+ }
+ else {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[libaf] Automatic filter insertion disabled "
+ "but formats do not match. Giving up.\n");
+ return AF_ERROR;
+ }
+ break;
+ }
+ case AF_DETACH:{ // Filter is redundant and wants to be unloaded
+ // Do auto remove only if force is not specified
+ if((AF_INIT_TYPE_MASK & s->cfg.force) != AF_INIT_FORCE){
+ struct af_instance* aft=af->prev;
+ af_remove(s,af);
+ if(aft)
+ af=aft->next;
+ else
+ af=s->first; // Restart configuration
+ }
+ break;
+ }
+ default:
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[libaf] Reinitialization did not work, audio"
+ " filter '%s' returned error code %i\n",af->info->name,rv);
+ return AF_ERROR;
+ }
+ }while(af);
+
+ af_print_filter_chain(s);
+
+ return AF_OK;
+}
+
+// Uninit and remove all filters
+void af_uninit(struct af_stream* s)
+{
+ while(s->first)
+ af_remove(s,s->first);
+}
+
+/**
+ * Extend the filter chain so we get the required output format at the end.
+ * \return AF_ERROR on error, AF_OK if successful.
+ */
+static int fixup_output_format(struct af_stream* s)
+{
+ struct af_instance* af = NULL;
+ // Check number of output channels fix if not OK
+ // If needed always inserted last -> easy to screw up other filters
+ if(s->output.nch && s->last->data->nch!=s->output.nch){
+ if(!strcmp(s->last->info->name,"format"))
+ af = af_prepend(s,s->last,"channels");
+ else
+ af = af_append(s,s->last,"channels");
+ // Init the new filter
+ if(!af || (AF_OK != af->control(af,AF_CONTROL_CHANNELS,&(s->output.nch))))
+ return AF_ERROR;
+ if(AF_OK != af_reinit(s,af))
+ return AF_ERROR;
+ }
+
+ // Check output format fix if not OK
+ if(s->output.format != AF_FORMAT_UNKNOWN &&
+ s->last->data->format != s->output.format){
+ if(strcmp(s->last->info->name,"format"))
+ af = af_append(s,s->last,"format");
+ else
+ af = s->last;
+ // Init the new filter
+ s->output.format |= af_bits2fmt(s->output.bps*8);
+ if(!af || (AF_OK != af->control(af,AF_CONTROL_FORMAT_FMT,&(s->output.format))))
+ return AF_ERROR;
+ if(AF_OK != af_reinit(s,af))
+ return AF_ERROR;
+ }
+
+ // Re init again just in case
+ if(AF_OK != af_reinit(s,s->first))
+ return AF_ERROR;
+
+ if (s->output.format == AF_FORMAT_UNKNOWN)
+ s->output.format = s->last->data->format;
+ if (!s->output.nch) s->output.nch = s->last->data->nch;
+ if (!s->output.rate) s->output.rate = s->last->data->rate;
+ if((s->last->data->format != s->output.format) ||
+ (s->last->data->nch != s->output.nch) ||
+ (s->last->data->rate != s->output.rate)) {
+ return AF_ERROR;
+ }
+ return AF_OK;
+}
+
+/**
+ * Automatic downmix to stereo in case the codec does not implement it.
+ */
+static void af_downmix(struct af_stream* s)
+{
+ static const char * const downmix_strs[AF_NCH + 1] = {
+ /* FL FR RL RR FC LF AL AR */
+ [3] = "pan=2:" "0.6:0:" "0:0.6:" "0.4:0.4",
+ [4] = "pan=2:" "0.6:0:" "0:0.6:" "0.4:0:" "0:0.4",
+ [5] = "pan=2:" "0.5:0:" "0:0.5:" "0.2:0:" "0:0.2:" "0.3:0.3",
+ [6] = "pan=2:" "0.4:0:" "0:0.4:" "0.2:0:" "0:0.2:" "0.3:0.3:" "0.1:0.1",
+ [7] = "pan=2:" "0.4:0:" "0:0.4:" "0.2:0:" "0:0.2:" "0.3:0.3:" "0.1:0:" "0:0.1",
+ [8] = "pan=2:" "0.4:0:" "0:0.4:" "0.15:0:" "0:0.15:" "0.25:0.25:" "0.1:0.1:" "0.1:0:" "0:0.1",
+ };
+ const char *af_pan_str = downmix_strs[s->input.nch];
+
+ if (af_pan_str)
+ af_append(s, s->first, af_pan_str);
+}
+
+/* Initialize the stream "s". This function creates a new filter list
+ if necessary according to the values set in input and output. Input
+ and output should contain the format of the current movie and the
+ formate of the preferred output respectively. The function is
+ reentrant i.e. if called with an already initialized stream the
+ stream will be reinitialized.
+ If one of the prefered output parameters is 0 the one that needs
+ no conversion is used (i.e. the output format in the last filter).
+ The return value is 0 if success and -1 if failure */
+int af_init(struct af_stream* s)
+{
+ struct MPOpts *opts = s->opts;
+ int i=0;
+
+ // Sanity check
+ if(!s) return -1;
+
+ // Precaution in case caller is misbehaving
+ s->input.audio = s->output.audio = NULL;
+ s->input.len = s->output.len = 0;
+
+ // Figure out how fast the machine is
+ if(AF_INIT_AUTO == (AF_INIT_TYPE_MASK & s->cfg.force))
+ s->cfg.force = (s->cfg.force & ~AF_INIT_TYPE_MASK) | AF_INIT_TYPE;
+
+ // Check if this is the first call
+ if(!s->first){
+ // Append a downmix pan filter at the beginning of the chain if needed
+ if (s->input.nch != opts->audio_output_channels
+ && opts->audio_output_channels == 2)
+ af_downmix(s);
+ // Add all filters in the list (if there are any)
+ if (s->cfg.list) {
+ while(s->cfg.list[i]){
+ if(!af_append(s,s->last,s->cfg.list[i++]))
+ return -1;
+ }
+ }
+ }
+
+ // If we do not have any filters otherwise
+ // add dummy to make automatic format conversion work
+ if (!s->first && !af_append(s, s->first, "dummy"))
+ return -1;
+
+ // Init filters
+ if(AF_OK != af_reinit(s,s->first))
+ return -1;
+
+ // make sure the chain is not empty and valid (e.g. because of AF_DETACH)
+ if (!s->first)
+ if (!af_append(s,s->first,"dummy") || AF_OK != af_reinit(s,s->first))
+ return -1;
+
+ // Check output format
+ if((AF_INIT_TYPE_MASK & s->cfg.force) != AF_INIT_FORCE){
+ struct af_instance* af = NULL; // New filter
+ // Check output frequency if not OK fix with resample
+ if(s->output.rate && s->last->data->rate!=s->output.rate){
+ // try to find a filter that can change samplrate
+ af = af_control_any_rev(s, AF_CONTROL_RESAMPLE_RATE | AF_CONTROL_SET,
+ &(s->output.rate));
+ if (!af) {
+ char *resampler = "resample";
+ if ((AF_INIT_TYPE_MASK & s->cfg.force) == AF_INIT_SLOW)
+ resampler = "lavcresample";
+ if((AF_INIT_TYPE_MASK & s->cfg.force) == AF_INIT_SLOW){
+ if(!strcmp(s->first->info->name,"format"))
+ af = af_append(s,s->first,resampler);
+ else
+ af = af_prepend(s,s->first,resampler);
+ }
+ else{
+ if(!strcmp(s->last->info->name,"format"))
+ af = af_prepend(s,s->last,resampler);
+ else
+ af = af_append(s,s->last,resampler);
+ }
+ // Init the new filter
+ if(!af || (AF_OK != af->control(af,AF_CONTROL_RESAMPLE_RATE | AF_CONTROL_SET,
+ &(s->output.rate))))
+ return -1;
+ // Use lin int if the user wants fast
+ if ((AF_INIT_TYPE_MASK & s->cfg.force) == AF_INIT_FAST) {
+ char args[32];
+ sprintf(args, "%d", s->output.rate);
+ if (strcmp(resampler, "lavcresample") == 0)
+ strcat(args, ":1");
+ else
+ strcat(args, ":0:0");
+ af->control(af, AF_CONTROL_COMMAND_LINE, args);
+ }
+ }
+ if(AF_OK != af_reinit(s,af))
+ return -1;
+ }
+ if (AF_OK != fixup_output_format(s)) {
+ // Something is stuffed audio out will not work
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[libaf] Unable to setup filter system can not"
+ " meet sound-card demands, please send a bug report. \n");
+ af_uninit(s);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/* Add filter during execution. This function adds the filter "name"
+ to the stream s. The filter will be inserted somewhere nice in the
+ list of filters. The return value is a pointer to the new filter,
+ If the filter couldn't be added the return value is NULL. */
+struct af_instance* af_add(struct af_stream* s, char* name){
+ struct af_instance* new;
+ // Sanity check
+ if(!s || !s->first || !name)
+ return NULL;
+ // Insert the filter somewhere nice
+ if(!strcmp(s->first->info->name,"format"))
+ new = af_append(s, s->first, name);
+ else
+ new = af_prepend(s, s->first, name);
+ if(!new)
+ return NULL;
+
+ // Reinitalize the filter list
+ if(AF_OK != af_reinit(s, s->first) ||
+ AF_OK != fixup_output_format(s)){
+ while (s->first)
+ af_remove(s, s->first);
+ af_init(s);
+ return NULL;
+ }
+ return new;
+}
+
+// Filter data chunk through the filters in the list
+struct mp_audio* af_play(struct af_stream* s, struct mp_audio* data)
+{
+ struct af_instance* af=s->first;
+ // Iterate through all filters
+ do{
+ if (data->len <= 0) break;
+ data=af->play(af,data);
+ af=af->next;
+ }while(af && data);
+ return data;
+}
+
+/* Calculate the minimum output buffer size for given input data d
+ * when using the RESIZE_LOCAL_BUFFER macro. The +t+1 part ensures the
+ * value is >= len*mul rounded upwards to whole samples even if the
+ * double 'mul' is inexact. */
+int af_lencalc(double mul, struct mp_audio* d)
+{
+ int t = d->bps * d->nch;
+ return d->len * mul + t + 1;
+}
+
+// Calculate average ratio of filter output size to input size
+double af_calc_filter_multiplier(struct af_stream* s)
+{
+ struct af_instance* af=s->first;
+ double mul = 1;
+ // Iterate through all filters and calculate total multiplication factor
+ do{
+ mul *= af->mul;
+ af=af->next;
+ }while(af);
+
+ return mul;
+}
+
+/* Calculate the total delay [bytes output] caused by the filters */
+double af_calc_delay(struct af_stream* s)
+{
+ struct af_instance* af=s->first;
+ register double delay = 0.0;
+ // Iterate through all filters
+ while(af){
+ delay += af->delay;
+ delay *= af->mul;
+ af=af->next;
+ }
+ return delay;
+}
+
+/* Helper function called by the macro with the same name this
+ function should not be called directly */
+int af_resize_local_buffer(struct af_instance* af, struct mp_audio* data)
+{
+ // Calculate new length
+ register int len = af_lencalc(af->mul,data);
+ mp_msg(MSGT_AFILTER, MSGL_V, "[libaf] Reallocating memory in module %s, "
+ "old len = %i, new len = %i\n",af->info->name,af->data->len,len);
+ // If there is a buffer free it
+ free(af->data->audio);
+ // Create new buffer and check that it is OK
+ af->data->audio = malloc(len);
+ if(!af->data->audio){
+ mp_msg(MSGT_AFILTER, MSGL_FATAL, "[libaf] Could not allocate memory \n");
+ return AF_ERROR;
+ }
+ af->data->len=len;
+ return AF_OK;
+}
+
+// documentation in af.h
+struct af_instance *af_control_any_rev (struct af_stream* s, int cmd, void* arg) {
+ int res = AF_UNKNOWN;
+ struct af_instance* filt = s->last;
+ while (filt) {
+ res = filt->control(filt, cmd, arg);
+ if (res == AF_OK)
+ return filt;
+ filt = filt->prev;
+ }
+ return NULL;
+}
+
+void af_help (void) {
+ int i = 0;
+ mp_msg(MSGT_AFILTER, MSGL_INFO, "Available audio filters:\n");
+ while (filter_list[i]) {
+ if (filter_list[i]->comment && filter_list[i]->comment[0])
+ mp_msg(MSGT_AFILTER, MSGL_INFO, " %-15s: %s (%s)\n", filter_list[i]->name, filter_list[i]->info, filter_list[i]->comment);
+ else
+ mp_msg(MSGT_AFILTER, MSGL_INFO, " %-15s: %s\n", filter_list[i]->name, filter_list[i]->info);
+ i++;
+ }
+}
+
+void af_fix_parameters(struct mp_audio *data)
+{
+ if (data->nch < 0 || data->nch > AF_NCH) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "Invalid number of channels %i, assuming 2.\n", data->nch);
+ data->nch = 2;
+ }
+ data->bps = af_fmt2bits(data->format)/8;
+}
diff --git a/audio/filter/af.h b/audio/filter/af.h
new file mode 100644
index 0000000000..edce49a978
--- /dev/null
+++ b/audio/filter/af.h
@@ -0,0 +1,349 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPLAYER_AF_H
+#define MPLAYER_AF_H
+
+#include <stdio.h>
+
+#include "config.h"
+
+#include "options.h"
+#include "libaf/format.h"
+#include "control.h"
+#include "cpudetect.h"
+#include "mp_msg.h"
+
+struct af_instance;
+
+// Number of channels
+#ifndef AF_NCH
+#define AF_NCH 8
+#endif
+
+// Audio data chunk
+struct mp_audio {
+ void *audio; // data buffer
+ int len; // buffer length
+ int rate; // sample rate
+ int nch; // number of channels
+ int format; // format
+ int bps; // bytes per sample
+};
+
+
+// Flags used for defining the behavior of an audio filter
+#define AF_FLAGS_REENTRANT 0x00000000
+#define AF_FLAGS_NOT_REENTRANT 0x00000001
+
+/* Audio filter information not specific for current instance, but for
+ a specific filter */
+struct af_info {
+ const char *info;
+ const char *name;
+ const char *author;
+ const char *comment;
+ const int flags;
+ int (*open)(struct af_instance *vf);
+};
+
+// Linked list of audio filters
+struct af_instance {
+ struct af_info *info;
+ int (*control)(struct af_instance *af, int cmd, void *arg);
+ void (*uninit)(struct af_instance *af);
+ struct mp_audio * (*play)(struct af_instance *af, struct mp_audio *data);
+ void *setup; // setup data for this specific instance and filter
+ struct mp_audio *data; // configuration for outgoing data stream
+ struct af_instance *next;
+ struct af_instance *prev;
+ double delay; /* Delay caused by the filter, in units of bytes read without
+ * corresponding output */
+ double mul; /* length multiplier: how much does this instance change
+ the length of the buffer. */
+};
+
+// Initialization flags
+extern int *af_cpu_speed;
+
+#define AF_INIT_AUTO 0x00000000
+#define AF_INIT_SLOW 0x00000001
+#define AF_INIT_FAST 0x00000002
+#define AF_INIT_FORCE 0x00000003
+#define AF_INIT_TYPE_MASK 0x00000003
+
+#define AF_INIT_INT 0x00000000
+#define AF_INIT_FLOAT 0x00000004
+#define AF_INIT_FORMAT_MASK 0x00000004
+
+// Default init type
+#ifndef AF_INIT_TYPE
+#define AF_INIT_TYPE (af_cpu_speed ? *af_cpu_speed : AF_INIT_SLOW)
+#endif
+
+// Configuration switches
+struct af_cfg {
+ int force; // Initialization type
+ char **list; /* list of names of filters that are added to filter
+ list during first initialization of stream */
+};
+
+// Current audio stream
+struct af_stream {
+ // The first and last filter in the list
+ struct af_instance *first;
+ struct af_instance *last;
+ // Storage for input and output data formats
+ struct mp_audio input;
+ struct mp_audio output;
+ // Configuration for this stream
+ struct af_cfg cfg;
+ struct MPOpts *opts;
+};
+
+/*********************************************
+ // Return values
+ */
+
+#define AF_DETACH 2
+#define AF_OK 1
+#define AF_TRUE 1
+#define AF_FALSE 0
+#define AF_UNKNOWN -1
+#define AF_ERROR -2
+#define AF_FATAL -3
+
+
+
+/*********************************************
+ // Export functions
+ */
+
+/**
+ * \defgroup af_chain Audio filter chain functions
+ * \{
+ * \param s filter chain
+ */
+
+/**
+ * \brief Initialize the stream "s".
+ * \return 0 on success, -1 on failure
+ *
+ * This function creates a new filter list if necessary, according
+ * to the values set in input and output. Input and output should contain
+ * the format of the current movie and the format of the preferred output
+ * respectively.
+ * Filters to convert to the preferred output format are inserted
+ * automatically, except when they are set to 0.
+ * The function is reentrant i.e. if called with an already initialized
+ * stream the stream will be reinitialized.
+ */
+int af_init(struct af_stream *s);
+
+/**
+ * \brief Uninit and remove all filters from audio filter chain
+ */
+void af_uninit(struct af_stream *s);
+
+/**
+ * \brief Reinit the filter list from the given filter on downwards
+ * \param Filter instance to begin the reinit from
+ * \return AF_OK on success or AF_ERROR on failure
+ */
+int af_reinit(struct af_stream *s, struct af_instance *af);
+
+/**
+ * \brief This function adds the filter "name" to the stream s.
+ * \param name name of filter to add
+ * \return pointer to the new filter, NULL if insert failed
+ *
+ * The filter will be inserted somewhere nice in the
+ * list of filters (i.e. at the beginning unless the
+ * first filter is the format filter (why??).
+ */
+struct af_instance *af_add(struct af_stream *s, char *name);
+
+/**
+ * \brief Uninit and remove the filter "af"
+ * \param af filter to remove
+ */
+void af_remove(struct af_stream *s, struct af_instance *af);
+
+/**
+ * \brief find filter in chain by name
+ * \param name name of the filter to find
+ * \return first filter with right name or NULL if not found
+ *
+ * This function is used for finding already initialized filters
+ */
+struct af_instance *af_get(struct af_stream *s, char *name);
+
+/**
+ * \brief filter data chunk through the filters in the list
+ * \param data data to play
+ * \return resulting data
+ * \ingroup af_chain
+ */
+struct mp_audio *af_play(struct af_stream *s, struct mp_audio *data);
+
+/**
+ * \brief send control to all filters, starting with the last until
+ * one accepts the command with AF_OK.
+ * \param cmd filter control command
+ * \param arg argument for filter command
+ * \return the accepting filter or NULL if none was found
+ */
+struct af_instance *af_control_any_rev(struct af_stream *s, int cmd, void *arg);
+
+/**
+ * \brief calculate average ratio of filter output lenth to input length
+ * \return the ratio
+ */
+double af_calc_filter_multiplier(struct af_stream *s);
+
+/**
+ * \brief Calculate the total delay caused by the filters
+ * \return delay in bytes of "missing" output
+ */
+double af_calc_delay(struct af_stream *s);
+
+/** \} */ // end of af_chain group
+
+// Helper functions and macros used inside the audio filters
+
+/**
+ * \defgroup af_filter Audio filter helper functions
+ * \{
+ */
+
+/* Helper function called by the macro with the same name only to be
+ called from inside filters */
+int af_resize_local_buffer(struct af_instance *af, struct mp_audio *data);
+
+/* Helper function used to calculate the exact buffer length needed
+ when buffers are resized. The returned length is >= than what is
+ needed */
+int af_lencalc(double mul, struct mp_audio *data);
+
+/**
+ * \brief convert dB to gain value
+ * \param n number of values to convert
+ * \param in [in] values in dB, <= -200 will become 0 gain
+ * \param out [out] gain values
+ * \param k input values are divided by this
+ * \param mi minimum dB value, input will be clamped to this
+ * \param ma maximum dB value, input will be clamped to this
+ * \return AF_ERROR on error, AF_OK otherwise
+ */
+int af_from_dB(int n, float *in, float *out, float k, float mi, float ma);
+
+/**
+ * \brief convert gain value to dB
+ * \param n number of values to convert
+ * \param in [in] gain values, 0 wil become -200 dB
+ * \param out [out] values in dB
+ * \param k output values will be multiplied by this
+ * \return AF_ERROR on error, AF_OK otherwise
+ */
+int af_to_dB(int n, float *in, float *out, float k);
+
+/**
+ * \brief convert milliseconds to sample time
+ * \param n number of values to convert
+ * \param in [in] values in milliseconds
+ * \param out [out] sample time values
+ * \param rate sample rate
+ * \param mi minimum ms value, input will be clamped to this
+ * \param ma maximum ms value, input will be clamped to this
+ * \return AF_ERROR on error, AF_OK otherwise
+ */
+int af_from_ms(int n, float *in, int *out, int rate, float mi, float ma);
+
+/**
+ * \brief convert sample time to milliseconds
+ * \param n number of values to convert
+ * \param in [in] sample time values
+ * \param out [out] values in milliseconds
+ * \param rate sample rate
+ * \return AF_ERROR on error, AF_OK otherwise
+ */
+int af_to_ms(int n, int *in, float *out, int rate);
+
+/**
+ * \brief test if output format matches
+ * \param af audio filter
+ * \param out needed format, will be overwritten by available
+ * format if they do not match
+ * \return AF_FALSE if formats do not match, AF_OK if they match
+ *
+ * compares the format, bps, rate and nch values of af->data with out
+ */
+int af_test_output(struct af_instance *af, struct mp_audio *out);
+
+/**
+ * \brief soft clipping function using sin()
+ * \param a input value
+ * \return clipped value
+ */
+float af_softclip(float a);
+
+/** \} */ // end of af_filter group, but more functions of this group below
+
+/** Print a list of all available audio filters */
+void af_help(void);
+
+/**
+ * \brief fill the missing parameters in the struct mp_audio structure
+ * \param data structure to fill
+ * \ingroup af_filter
+ *
+ * Currently only sets bps based on format
+ */
+void af_fix_parameters(struct mp_audio *data);
+
+/** Memory reallocation macro: if a local buffer is used (i.e. if the
+ filter doesn't operate on the incoming buffer this macro must be
+ called to ensure the buffer is big enough.
+ * \ingroup af_filter
+ */
+#define RESIZE_LOCAL_BUFFER(a, d) \
+ ((a->data->len < \
+ af_lencalc(a->mul, d)) ? af_resize_local_buffer(a, d) : AF_OK)
+
+/* Some other useful macro definitions*/
+#ifndef min
+#define min(a, b)(((a) > (b)) ? (b) : (a))
+#endif
+
+#ifndef max
+#define max(a, b)(((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef clamp
+#define clamp(a, min, max) (((a) > (max)) ? (max) : (((a) < (min)) ? (min) : (a)))
+#endif
+
+#ifndef sign
+#define sign(a) (((a) > 0) ? (1) : (-1))
+#endif
+
+#ifndef lrnd
+#define lrnd(a, b) ((b)((a) >= 0.0 ? (a) + 0.5 : (a) - 0.5))
+#endif
+
+#endif /* MPLAYER_AF_H */
diff --git a/audio/filter/af_bs2b.c b/audio/filter/af_bs2b.c
new file mode 100644
index 0000000000..ccbf3794c5
--- /dev/null
+++ b/audio/filter/af_bs2b.c
@@ -0,0 +1,274 @@
+/*
+ * The Bauer stereophonic-to-binaural DSP using bs2b library:
+ * http://bs2b.sourceforge.net/
+ *
+ * Copyright (c) 2009 Andrew Savchenko
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <bs2b.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "af.h"
+#include "subopt-helper.h"
+
+/// Internal specific data of the filter
+struct af_bs2b {
+ int fcut; ///< cut frequency in Hz
+ int feed; ///< feed level for low frequencies in 0.1*dB
+ char *profile; ///< profile (available crossfeed presets)
+ t_bs2bdp filter; ///< instance of a library filter
+};
+
+#define PLAY(name, type) \
+static struct mp_audio *play_##name(struct af_instance *af, struct mp_audio *data) \
+{ \
+ /* filter is called for all pairs of samples available in the buffer */ \
+ bs2b_cross_feed_##name(((struct af_bs2b*)(af->setup))->filter, \
+ (type*)(data->audio), data->len/data->bps/2); \
+\
+ return data; \
+}
+
+PLAY(f, float)
+PLAY(fbe, float)
+PLAY(fle, float)
+PLAY(s32be, int32_t)
+PLAY(u32be, uint32_t)
+PLAY(s32le, int32_t)
+PLAY(u32le, uint32_t)
+PLAY(s24be, bs2b_int24_t)
+PLAY(u24be, bs2b_uint24_t)
+PLAY(s24le, bs2b_int24_t)
+PLAY(u24le, bs2b_uint24_t)
+PLAY(s16be, int16_t)
+PLAY(u16be, uint16_t)
+PLAY(s16le, int16_t)
+PLAY(u16le, uint16_t)
+PLAY(s8, int8_t)
+PLAY(u8, uint8_t)
+
+/// Sanity check for fcut value
+static int test_fcut(void *par)
+{
+ const int val = *(int*)par;
+ if (val >= BS2B_MINFCUT && val <= BS2B_MAXFCUT)
+ return 1;
+
+ mp_msg(MSGT_AFILTER, MSGL_ERR,
+ "[bs2b] Cut frequency must be in range [%d..%d], but current value is %d.\n",
+ BS2B_MINFCUT, BS2B_MAXFCUT, val);
+ return 0;
+}
+
+/// Sanity check for feed value
+static int test_feed(void *par)
+{
+ const int val = *(int*)par;
+ if (val >= BS2B_MINFEED && val <= BS2B_MAXFEED)
+ return 1;
+
+ mp_msg(MSGT_AFILTER, MSGL_ERR,
+ "[bs2b] Feed level must be in range [%d..%d], but current value is %d.\n",
+ BS2B_MINFEED, BS2B_MAXFEED, val);
+ return 0;
+}
+
+/// Initialization and runtime control
+static int control(struct af_instance *af, int cmd, void *arg)
+{
+ struct af_bs2b *s = af->setup;
+
+ switch (cmd) {
+ case AF_CONTROL_REINIT: {
+ int format;
+ char buf[256];
+ // Sanity check
+ if (!arg) return AF_ERROR;
+
+ format = ((struct mp_audio*)arg)->format;
+ af->data->rate = ((struct mp_audio*)arg)->rate;
+ af->data->nch = 2; // bs2b is useful only for 2ch audio
+ af->data->bps = ((struct mp_audio*)arg)->bps;
+ af->data->format = format;
+
+ /* check for formats supported by libbs2b
+ and assign corresponding handlers */
+ switch (format) {
+ case AF_FORMAT_FLOAT_BE:
+ af->play = play_fbe;
+ break;
+ case AF_FORMAT_FLOAT_LE:
+ af->play = play_fle;
+ break;
+ case AF_FORMAT_S32_BE:
+ af->play = play_s32be;
+ break;
+ case AF_FORMAT_U32_BE:
+ af->play = play_u32be;
+ break;
+ case AF_FORMAT_S32_LE:
+ af->play = play_s32le;
+ break;
+ case AF_FORMAT_U32_LE:
+ af->play = play_u32le;
+ break;
+ case AF_FORMAT_S24_BE:
+ af->play = play_s24be;
+ break;
+ case AF_FORMAT_U24_BE:
+ af->play = play_u24be;
+ break;
+ case AF_FORMAT_S24_LE:
+ af->play = play_s24le;
+ break;
+ case AF_FORMAT_U24_LE:
+ af->play = play_u24le;
+ break;
+ case AF_FORMAT_S16_BE:
+ af->play = play_s16be;
+ break;
+ case AF_FORMAT_U16_BE:
+ af->play = play_u16be;
+ break;
+ case AF_FORMAT_S16_LE:
+ af->play = play_s16le;
+ break;
+ case AF_FORMAT_U16_LE:
+ af->play = play_u16le;
+ break;
+ case AF_FORMAT_S8:
+ af->play = play_s8;
+ break;
+ case AF_FORMAT_U8:
+ af->play = play_u8;
+ break;
+ default:
+ af->play = play_f;
+ af->data->format = AF_FORMAT_FLOAT_NE;
+ af->data->bps = 4;
+ break;
+ }
+
+ // bs2b have srate limits, try to resample if needed
+ if (af->data->rate > BS2B_MAXSRATE || af->data->rate < BS2B_MINSRATE) {
+ af->data->rate = BS2B_DEFAULT_SRATE;
+ mp_msg(MSGT_AFILTER, MSGL_WARN,
+ "[bs2b] Requested sample rate %d Hz is out of bounds [%d..%d] Hz.\n"
+ "[bs2b] Trying to resample to %d Hz.\n",
+ af->data->rate, BS2B_MINSRATE, BS2B_MAXSRATE, BS2B_DEFAULT_SRATE);
+ }
+ bs2b_set_srate(s->filter, (long)af->data->rate);
+ mp_msg(MSGT_AFILTER, MSGL_V, "[bs2b] using format %s\n",
+ af_fmt2str(af->data->format,buf,256));
+
+ return af_test_output(af,(struct mp_audio*)arg);
+ }
+ case AF_CONTROL_COMMAND_LINE: {
+ const opt_t subopts[] = {
+ {"fcut", OPT_ARG_INT, &s->fcut, test_fcut},
+ {"feed", OPT_ARG_INT, &s->feed, test_feed},
+ {"profile", OPT_ARG_MSTRZ, &s->profile, NULL},
+ {NULL}
+ };
+ if (subopt_parse(arg, subopts) != 0) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[bs2b] Invalid option specified.\n");
+ free(s->profile);
+ return AF_ERROR;
+ }
+ // parse profile if specified
+ if (s->profile) {
+ if (!strcmp(s->profile, "default"))
+ bs2b_set_level(s->filter, BS2B_DEFAULT_CLEVEL);
+ else if (!strcmp(s->profile, "cmoy"))
+ bs2b_set_level(s->filter, BS2B_CMOY_CLEVEL);
+ else if (!strcmp(s->profile, "jmeier"))
+ bs2b_set_level(s->filter, BS2B_JMEIER_CLEVEL);
+ else {
+ mp_msg(MSGT_AFILTER, MSGL_ERR,
+ "[bs2b] Invalid profile specified: %s.\n"
+ "[bs2b] Available profiles are: default, cmoy, jmeier.\n",
+ s->profile);
+ free(s->profile);
+ return AF_ERROR;
+ }
+ }
+ // set fcut and feed only if specified, otherwise defaults will be used
+ if (s->fcut)
+ bs2b_set_level_fcut(s->filter, s->fcut);
+ if (s->feed)
+ bs2b_set_level_feed(s->filter, s->feed);
+
+ mp_msg(MSGT_AFILTER, MSGL_V,
+ "[bs2b] using cut frequency %d, LF feed level %d\n",
+ bs2b_get_level_fcut(s->filter), bs2b_get_level_feed(s->filter));
+ free(s->profile);
+ return AF_OK;
+ }
+ }
+ return AF_UNKNOWN;
+}
+
+/// Deallocate memory and close library
+static void uninit(struct af_instance *af)
+{
+ struct af_bs2b *s = af->setup;
+ free(af->data);
+ if (s && s->filter)
+ bs2b_close(s->filter);
+ free(s);
+}
+
+/// Allocate memory, set function pointers and init library
+static int af_open(struct af_instance *af)
+{
+ struct af_bs2b *s;
+ af->control = control;
+ af->uninit = uninit;
+ af->mul = 1;
+ if (!(af->data = calloc(1, sizeof(struct mp_audio))))
+ return AF_ERROR;
+ if (!(af->setup = s = calloc(1, sizeof(struct af_bs2b)))) {
+ free(af->data);
+ return AF_ERROR;
+ }
+
+ // NULL means failed initialization
+ if (!(s->filter = bs2b_open())) {
+ free(af->data);
+ free(af->setup);
+ return AF_ERROR;
+ }
+ // Set zero defaults indicating no option was specified.
+ s->profile = NULL;
+ s->fcut = 0;
+ s->feed = 0;
+ return AF_OK;
+}
+
+/// Description of this filter
+struct af_info af_info_bs2b = {
+ "Bauer stereophonic-to-binaural audio filter",
+ "bs2b",
+ "Andrew Savchenko",
+ "",
+ AF_FLAGS_REENTRANT,
+ af_open
+};
diff --git a/audio/filter/af_center.c b/audio/filter/af_center.c
new file mode 100644
index 0000000000..aa9aae8514
--- /dev/null
+++ b/audio/filter/af_center.c
@@ -0,0 +1,129 @@
+/*
+ * This filter adds a center channel to the audio stream by
+ * averaging the left and right channel.
+ * There are two runtime controls one for setting which channel
+ * to insert the center-audio into called AF_CONTROL_SUB_CH.
+ *
+ * FIXME: implement a high-pass filter for better results.
+ *
+ * copyright (c) 2005 Alex Beregszaszi
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "af.h"
+
+// Data for specific instances of this filter
+typedef struct af_center_s
+{
+ int ch; // Channel number which to insert the filtered data
+}af_center_t;
+
+// Initialization and runtime control
+static int control(struct af_instance* af, int cmd, void* arg)
+{
+ af_center_t* s = af->setup;
+
+ switch(cmd){
+ case AF_CONTROL_REINIT:{
+ // Sanity check
+ if(!arg) return AF_ERROR;
+
+ af->data->rate = ((struct mp_audio*)arg)->rate;
+ af->data->nch = max(s->ch+1,((struct mp_audio*)arg)->nch);
+ af->data->format = AF_FORMAT_FLOAT_NE;
+ af->data->bps = 4;
+
+ return af_test_output(af,(struct mp_audio*)arg);
+ }
+ case AF_CONTROL_COMMAND_LINE:{
+ int ch=1;
+ sscanf(arg,"%i", &ch);
+ return control(af,AF_CONTROL_CENTER_CH | AF_CONTROL_SET, &ch);
+ }
+ case AF_CONTROL_CENTER_CH | AF_CONTROL_SET: // Requires reinit
+ // Sanity check
+ if((*(int*)arg >= AF_NCH) || (*(int*)arg < 0)){
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[sub] Center channel number must be between "
+ " 0 and %i current value is %i\n", AF_NCH-1, *(int*)arg);
+ return AF_ERROR;
+ }
+ s->ch = *(int*)arg;
+ return AF_OK;
+ case AF_CONTROL_CENTER_CH | AF_CONTROL_GET:
+ *(int*)arg = s->ch;
+ return AF_OK;
+ }
+ return AF_UNKNOWN;
+}
+
+// Deallocate memory
+static void uninit(struct af_instance* af)
+{
+ free(af->data);
+ free(af->setup);
+}
+
+// Filter data through filter
+static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
+{
+ struct mp_audio* c = data; // Current working data
+ af_center_t* s = af->setup; // Setup for this instance
+ float* a = c->audio; // Audio data
+ int len = c->len/4; // Number of samples in current audio block
+ int nch = c->nch; // Number of channels
+ int ch = s->ch; // Channel in which to insert the center audio
+ register int i;
+
+ // Run filter
+ for(i=0;i<len;i+=nch){
+ // Average left and right
+ a[i+ch] = (a[i]/2) + (a[i+1]/2);
+ }
+
+ return c;
+}
+
+// Allocate memory and set function pointers
+static int af_open(struct af_instance* af){
+ af_center_t* s;
+ af->control=control;
+ af->uninit=uninit;
+ af->play=play;
+ af->mul=1;
+ af->data=calloc(1,sizeof(struct mp_audio));
+ af->setup=s=calloc(1,sizeof(af_center_t));
+ if(af->data == NULL || af->setup == NULL)
+ return AF_ERROR;
+ // Set default values
+ s->ch = 1; // Channel nr 2
+ return AF_OK;
+}
+
+// Description of this filter
+struct af_info af_info_center = {
+ "Audio filter for adding a center channel",
+ "center",
+ "Alex Beregszaszi",
+ "",
+ AF_FLAGS_NOT_REENTRANT,
+ af_open
+};
diff --git a/audio/filter/af_channels.c b/audio/filter/af_channels.c
new file mode 100644
index 0000000000..8f676d8cfd
--- /dev/null
+++ b/audio/filter/af_channels.c
@@ -0,0 +1,306 @@
+/*
+ * Audio filter that adds and removes channels, according to the
+ * command line parameter channels. It is stupid and can only add
+ * silence or copy channels, not mix or filter.
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "af.h"
+
+#define FR 0
+#define TO 1
+
+typedef struct af_channels_s{
+ int route[AF_NCH][2];
+ int nr;
+ int router;
+}af_channels_t;
+
+// Local function for copying data
+static void copy(void* in, void* out, int ins, int inos,int outs, int outos, int len, int bps)
+{
+ switch(bps){
+ case 1:{
+ int8_t* tin = (int8_t*)in;
+ int8_t* tout = (int8_t*)out;
+ tin += inos;
+ tout += outos;
+ len = len/ins;
+ while(len--){
+ *tout=*tin;
+ tin +=ins;
+ tout+=outs;
+ }
+ break;
+ }
+ case 2:{
+ int16_t* tin = (int16_t*)in;
+ int16_t* tout = (int16_t*)out;
+ tin += inos;
+ tout += outos;
+ len = len/(2*ins);
+ while(len--){
+ *tout=*tin;
+ tin +=ins;
+ tout+=outs;
+ }
+ break;
+ }
+ case 3:{
+ int8_t* tin = (int8_t*)in;
+ int8_t* tout = (int8_t*)out;
+ tin += 3 * inos;
+ tout += 3 * outos;
+ len = len / ( 3 * ins);
+ while (len--) {
+ tout[0] = tin[0];
+ tout[1] = tin[1];
+ tout[2] = tin[2];
+ tin += 3 * ins;
+ tout += 3 * outs;
+ }
+ break;
+ }
+ case 4:{
+ int32_t* tin = (int32_t*)in;
+ int32_t* tout = (int32_t*)out;
+ tin += inos;
+ tout += outos;
+ len = len/(4*ins);
+ while(len--){
+ *tout=*tin;
+ tin +=ins;
+ tout+=outs;
+ }
+ break;
+ }
+ case 8:{
+ int64_t* tin = (int64_t*)in;
+ int64_t* tout = (int64_t*)out;
+ tin += inos;
+ tout += outos;
+ len = len/(8*ins);
+ while(len--){
+ *tout=*tin;
+ tin +=ins;
+ tout+=outs;
+ }
+ break;
+ }
+ default:
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[channels] Unsupported number of bytes/sample: %i"
+ " please report this error on the MPlayer mailing list. \n",bps);
+ }
+}
+
+// Make sure the routes are sane
+static int check_routes(af_channels_t* s, int nin, int nout)
+{
+ int i;
+ if((s->nr < 1) || (s->nr > AF_NCH)){
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[channels] The number of routing pairs must be"
+ " between 1 and %i. Current value is %i\n",AF_NCH,s->nr);
+ return AF_ERROR;
+ }
+
+ for(i=0;i<s->nr;i++){
+ if((s->route[i][FR] >= nin) || (s->route[i][TO] >= nout)){
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[channels] Invalid routing in pair nr. %i.\n", i);
+ return AF_ERROR;
+ }
+ }
+ return AF_OK;
+}
+
+// Initialization and runtime control
+static int control(struct af_instance* af, int cmd, void* arg)
+{
+ af_channels_t* s = af->setup;
+ switch(cmd){
+ case AF_CONTROL_REINIT:
+
+ // Set default channel assignment
+ if(!s->router){
+ int i;
+ // Make sure this filter isn't redundant
+ if(af->data->nch == ((struct mp_audio*)arg)->nch)
+ return AF_DETACH;
+
+ // If mono: fake stereo
+ if(((struct mp_audio*)arg)->nch == 1){
+ s->nr = min(af->data->nch,2);
+ for(i=0;i<s->nr;i++){
+ s->route[i][FR] = 0;
+ s->route[i][TO] = i;
+ }
+ }
+ else{
+ s->nr = min(af->data->nch, ((struct mp_audio*)arg)->nch);
+ for(i=0;i<s->nr;i++){
+ s->route[i][FR] = i;
+ s->route[i][TO] = i;
+ }
+ }
+ }
+
+ af->data->rate = ((struct mp_audio*)arg)->rate;
+ af->data->format = ((struct mp_audio*)arg)->format;
+ af->data->bps = ((struct mp_audio*)arg)->bps;
+ af->mul = (double)af->data->nch / ((struct mp_audio*)arg)->nch;
+ return check_routes(s,((struct mp_audio*)arg)->nch,af->data->nch);
+ case AF_CONTROL_COMMAND_LINE:{
+ int nch = 0;
+ int n = 0;
+ // Check number of channels and number of routing pairs
+ sscanf(arg, "%i:%i%n", &nch, &s->nr, &n);
+
+ // If router scan commandline for routing pairs
+ if(s->nr){
+ char* cp = &((char*)arg)[n];
+ int ch = 0;
+ // Sanity check
+ if((s->nr < 1) || (s->nr > AF_NCH)){
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[channels] The number of routing pairs must be"
+ " between 1 and %i. Current value is %i\n",AF_NCH,s->nr);
+ }
+ s->router = 1;
+ // Scan for pairs on commandline
+ while((*cp == ':') && (ch < s->nr)){
+ sscanf(cp, ":%i:%i%n" ,&s->route[ch][FR], &s->route[ch][TO], &n);
+ mp_msg(MSGT_AFILTER, MSGL_V, "[channels] Routing from channel %i to"
+ " channel %i\n",s->route[ch][FR],s->route[ch][TO]);
+ cp = &cp[n];
+ ch++;
+ }
+ }
+
+ if(AF_OK != af->control(af,AF_CONTROL_CHANNELS | AF_CONTROL_SET ,&nch))
+ return AF_ERROR;
+ return AF_OK;
+ }
+ case AF_CONTROL_CHANNELS | AF_CONTROL_SET:
+ // Reinit must be called after this function has been called
+
+ // Sanity check
+ if(((int*)arg)[0] <= 0 || ((int*)arg)[0] > AF_NCH){
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[channels] The number of output channels must be"
+ " between 1 and %i. Current value is %i\n",AF_NCH,((int*)arg)[0]);
+ return AF_ERROR;
+ }
+
+ af->data->nch=((int*)arg)[0];
+ if(!s->router)
+ mp_msg(MSGT_AFILTER, MSGL_V, "[channels] Changing number of channels"
+ " to %i\n",af->data->nch);
+ return AF_OK;
+ case AF_CONTROL_CHANNELS | AF_CONTROL_GET:
+ *(int*)arg = af->data->nch;
+ return AF_OK;
+ case AF_CONTROL_CHANNELS_ROUTING | AF_CONTROL_SET:{
+ int ch = ((af_control_ext_t*)arg)->ch;
+ int* route = ((af_control_ext_t*)arg)->arg;
+ s->route[ch][FR] = route[FR];
+ s->route[ch][TO] = route[TO];
+ return AF_OK;
+ }
+ case AF_CONTROL_CHANNELS_ROUTING | AF_CONTROL_GET:{
+ int ch = ((af_control_ext_t*)arg)->ch;
+ int* route = ((af_control_ext_t*)arg)->arg;
+ route[FR] = s->route[ch][FR];
+ route[TO] = s->route[ch][TO];
+ return AF_OK;
+ }
+ case AF_CONTROL_CHANNELS_NR | AF_CONTROL_SET:
+ s->nr = *(int*)arg;
+ return AF_OK;
+ case AF_CONTROL_CHANNELS_NR | AF_CONTROL_GET:
+ *(int*)arg = s->nr;
+ return AF_OK;
+ case AF_CONTROL_CHANNELS_ROUTER | AF_CONTROL_SET:
+ s->router = *(int*)arg;
+ return AF_OK;
+ case AF_CONTROL_CHANNELS_ROUTER | AF_CONTROL_GET:
+ *(int*)arg = s->router;
+ return AF_OK;
+ }
+ return AF_UNKNOWN;
+}
+
+// Deallocate memory
+static void uninit(struct af_instance* af)
+{
+ free(af->setup);
+ if (af->data)
+ free(af->data->audio);
+ free(af->data);
+}
+
+// Filter data through filter
+static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
+{
+ struct mp_audio* c = data; // Current working data
+ struct mp_audio* l = af->data; // Local data
+ af_channels_t* s = af->setup;
+ int i;
+
+ if(AF_OK != RESIZE_LOCAL_BUFFER(af,data))
+ return NULL;
+
+ // Reset unused channels
+ memset(l->audio,0,c->len / c->nch * l->nch);
+
+ if(AF_OK == check_routes(s,c->nch,l->nch))
+ for(i=0;i<s->nr;i++)
+ copy(c->audio,l->audio,c->nch,s->route[i][FR],
+ l->nch,s->route[i][TO],c->len,c->bps);
+
+ // Set output data
+ c->audio = l->audio;
+ c->len = c->len / c->nch * l->nch;
+ c->nch = l->nch;
+
+ return c;
+}
+
+// Allocate memory and set function pointers
+static int af_open(struct af_instance* af){
+ af->control=control;
+ af->uninit=uninit;
+ af->play=play;
+ af->mul=1;
+ af->data=calloc(1,sizeof(struct mp_audio));
+ af->setup=calloc(1,sizeof(af_channels_t));
+ if((af->data == NULL) || (af->setup == NULL))
+ return AF_ERROR;
+ return AF_OK;
+}
+
+// Description of this filter
+struct af_info af_info_channels = {
+ "Insert or remove channels",
+ "channels",
+ "Anders",
+ "",
+ AF_FLAGS_REENTRANT,
+ af_open
+};
diff --git a/audio/filter/af_delay.c b/audio/filter/af_delay.c
new file mode 100644
index 0000000000..ce8d71980b
--- /dev/null
+++ b/audio/filter/af_delay.c
@@ -0,0 +1,200 @@
+/*
+ * This audio filter delays the output signal for the different
+ * channels and can be used for simple position panning.
+ * An extension for this filter would be a reverb.
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "af.h"
+
+#define L 65536
+
+#define UPDATEQI(qi) qi=(qi+1)&(L-1)
+
+// Data for specific instances of this filter
+typedef struct af_delay_s
+{
+ void* q[AF_NCH]; // Circular queues used for delaying audio signal
+ int wi[AF_NCH]; // Write index
+ int ri; // Read index
+ float d[AF_NCH]; // Delay [ms]
+}af_delay_t;
+
+// Initialization and runtime control
+static int control(struct af_instance* af, int cmd, void* arg)
+{
+ af_delay_t* s = af->setup;
+ switch(cmd){
+ case AF_CONTROL_REINIT:{
+ int i;
+
+ // Free prevous delay queues
+ for(i=0;i<af->data->nch;i++)
+ free(s->q[i]);
+
+ af->data->rate = ((struct mp_audio*)arg)->rate;
+ af->data->nch = ((struct mp_audio*)arg)->nch;
+ af->data->format = ((struct mp_audio*)arg)->format;
+ af->data->bps = ((struct mp_audio*)arg)->bps;
+
+ // Allocate new delay queues
+ for(i=0;i<af->data->nch;i++){
+ s->q[i] = calloc(L,af->data->bps);
+ if(NULL == s->q[i])
+ mp_msg(MSGT_AFILTER, MSGL_FATAL, "[delay] Out of memory\n");
+ }
+
+ return control(af,AF_CONTROL_DELAY_LEN | AF_CONTROL_SET,s->d);
+ }
+ case AF_CONTROL_COMMAND_LINE:{
+ int n = 1;
+ int i = 0;
+ char* cl = arg;
+ while(n && i < AF_NCH ){
+ sscanf(cl,"%f:%n",&s->d[i],&n);
+ if(n==0 || cl[n-1] == '\0')
+ break;
+ cl=&cl[n];
+ i++;
+ }
+ return AF_OK;
+ }
+ case AF_CONTROL_DELAY_LEN | AF_CONTROL_SET:{
+ int i;
+ if(AF_OK != af_from_ms(AF_NCH, arg, s->wi, af->data->rate, 0.0, 1000.0))
+ return AF_ERROR;
+ s->ri = 0;
+ for(i=0;i<AF_NCH;i++){
+ mp_msg(MSGT_AFILTER, MSGL_DBG2, "[delay] Channel %i delayed by %0.3fms\n",
+ i,clamp(s->d[i],0.0,1000.0));
+ mp_msg(MSGT_AFILTER, MSGL_DBG3, "[delay] Channel %i delayed by %i samples\n",
+ i,s->wi[i]);
+ }
+ return AF_OK;
+ }
+ case AF_CONTROL_DELAY_LEN | AF_CONTROL_GET:{
+ int i;
+ for(i=0;i<AF_NCH;i++){
+ if(s->ri > s->wi[i])
+ s->wi[i] = L - (s->ri - s->wi[i]);
+ else
+ s->wi[i] = s->wi[i] - s->ri;
+ }
+ return af_to_ms(AF_NCH, s->wi, arg, af->data->rate);
+ }
+ }
+ return AF_UNKNOWN;
+}
+
+// Deallocate memory
+static void uninit(struct af_instance* af)
+{
+ int i;
+
+ free(af->data);
+ for(i=0;i<AF_NCH;i++)
+ free(((af_delay_t*)(af->setup))->q[i]);
+ free(af->setup);
+}
+
+// Filter data through filter
+static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
+{
+ struct mp_audio* c = data; // Current working data
+ af_delay_t* s = af->setup; // Setup for this instance
+ int nch = c->nch; // Number of channels
+ int len = c->len/c->bps; // Number of sample in data chunk
+ int ri = 0;
+ int ch,i;
+ for(ch=0;ch<nch;ch++){
+ switch(c->bps){
+ case 1:{
+ int8_t* a = c->audio;
+ int8_t* q = s->q[ch];
+ int wi = s->wi[ch];
+ ri = s->ri;
+ for(i=ch;i<len;i+=nch){
+ q[wi] = a[i];
+ a[i] = q[ri];
+ UPDATEQI(wi);
+ UPDATEQI(ri);
+ }
+ s->wi[ch] = wi;
+ break;
+ }
+ case 2:{
+ int16_t* a = c->audio;
+ int16_t* q = s->q[ch];
+ int wi = s->wi[ch];
+ ri = s->ri;
+ for(i=ch;i<len;i+=nch){
+ q[wi] = a[i];
+ a[i] = q[ri];
+ UPDATEQI(wi);
+ UPDATEQI(ri);
+ }
+ s->wi[ch] = wi;
+ break;
+ }
+ case 4:{
+ int32_t* a = c->audio;
+ int32_t* q = s->q[ch];
+ int wi = s->wi[ch];
+ ri = s->ri;
+ for(i=ch;i<len;i+=nch){
+ q[wi] = a[i];
+ a[i] = q[ri];
+ UPDATEQI(wi);
+ UPDATEQI(ri);
+ }
+ s->wi[ch] = wi;
+ break;
+ }
+ }
+ }
+ s->ri = ri;
+ return c;
+}
+
+// Allocate memory and set function pointers
+static int af_open(struct af_instance* af){
+ af->control=control;
+ af->uninit=uninit;
+ af->play=play;
+ af->mul=1;
+ af->data=calloc(1,sizeof(struct mp_audio));
+ af->setup=calloc(1,sizeof(af_delay_t));
+ if(af->data == NULL || af->setup == NULL)
+ return AF_ERROR;
+ return AF_OK;
+}
+
+// Description of this filter
+struct af_info af_info_delay = {
+ "Delay audio filter",
+ "delay",
+ "Anders",
+ "",
+ AF_FLAGS_REENTRANT,
+ af_open
+};
diff --git a/audio/filter/af_dummy.c b/audio/filter/af_dummy.c
new file mode 100644
index 0000000000..29a5b3d4b8
--- /dev/null
+++ b/audio/filter/af_dummy.c
@@ -0,0 +1,76 @@
+/*
+ * The name speaks for itself. This filter is a dummy and will
+ * not blow up regardless of what you do with it.
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "af.h"
+
+// Initialization and runtime control
+static int control(struct af_instance* af, int cmd, void* arg)
+{
+ switch(cmd){
+ case AF_CONTROL_REINIT:
+ memcpy(af->data,(struct mp_audio*)arg,sizeof(struct mp_audio));
+ mp_msg(MSGT_AFILTER, MSGL_V, "[dummy] Was reinitialized: %iHz/%ich/%s\n",
+ af->data->rate,af->data->nch,af_fmt2str_short(af->data->format));
+ return AF_OK;
+ }
+ return AF_UNKNOWN;
+}
+
+// Deallocate memory
+static void uninit(struct af_instance* af)
+{
+ free(af->data);
+}
+
+// Filter data through filter
+static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
+{
+ // Do something necessary to get rid of annoying warning during compile
+ if(!af)
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "EEEK: Argument af == NULL in af_dummy.c play().");
+ return data;
+}
+
+// Allocate memory and set function pointers
+static int af_open(struct af_instance* af){
+ af->control=control;
+ af->uninit=uninit;
+ af->play=play;
+ af->mul=1;
+ af->data=malloc(sizeof(struct mp_audio));
+ if(af->data == NULL)
+ return AF_ERROR;
+ return AF_OK;
+}
+
+// Description of this filter
+struct af_info af_info_dummy = {
+ "dummy",
+ "dummy",
+ "Anders",
+ "",
+ AF_FLAGS_REENTRANT,
+ af_open
+};
diff --git a/audio/filter/af_equalizer.c b/audio/filter/af_equalizer.c
new file mode 100644
index 0000000000..c488ffaeaf
--- /dev/null
+++ b/audio/filter/af_equalizer.c
@@ -0,0 +1,248 @@
+/*
+ * Equalizer filter, implementation of a 10 band time domain graphic
+ * equalizer using IIR filters. The IIR filters are implemented using a
+ * Direct Form II approach, but has been modified (b1 == 0 always) to
+ * save computation.
+ *
+ * Copyright (C) 2001 Anders Johansson ajh@atri.curtin.edu.au
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <inttypes.h>
+#include <math.h>
+
+#include "af.h"
+
+#define L 2 // Storage for filter taps
+#define KM 10 // Max number of bands
+
+#define Q 1.2247449 /* Q value for band-pass filters 1.2247=(3/2)^(1/2)
+ gives 4dB suppression @ Fc*2 and Fc/2 */
+
+/* Center frequencies for band-pass filters
+ The different frequency bands are:
+ nr. center frequency
+ 0 31.25 Hz
+ 1 62.50 Hz
+ 2 125.0 Hz
+ 3 250.0 Hz
+ 4 500.0 Hz
+ 5 1.000 kHz
+ 6 2.000 kHz
+ 7 4.000 kHz
+ 8 8.000 kHz
+ 9 16.00 kHz
+*/
+#define CF {31.25,62.5,125,250,500,1000,2000,4000,8000,16000}
+
+// Maximum and minimum gain for the bands
+#define G_MAX +12.0
+#define G_MIN -12.0
+
+// Data for specific instances of this filter
+typedef struct af_equalizer_s
+{
+ float a[KM][L]; // A weights
+ float b[KM][L]; // B weights
+ float wq[AF_NCH][KM][L]; // Circular buffer for W data
+ float g[AF_NCH][KM]; // Gain factor for each channel and band
+ int K; // Number of used eq bands
+ int channels; // Number of channels
+ float gain_factor; // applied at output to avoid clipping
+} af_equalizer_t;
+
+// 2nd order Band-pass Filter design
+static void bp2(float* a, float* b, float fc, float q){
+ double th= 2.0 * M_PI * fc;
+ double C = (1.0 - tan(th*q/2.0))/(1.0 + tan(th*q/2.0));
+
+ a[0] = (1.0 + C) * cos(th);
+ a[1] = -1 * C;
+
+ b[0] = (1.0 - C)/2.0;
+ b[1] = -1.0050;
+}
+
+// Initialization and runtime control
+static int control(struct af_instance* af, int cmd, void* arg)
+{
+ af_equalizer_t* s = (af_equalizer_t*)af->setup;
+
+ switch(cmd){
+ case AF_CONTROL_REINIT:{
+ int k =0, i =0;
+ float F[KM] = CF;
+
+ s->gain_factor=0.0;
+
+ // Sanity check
+ if(!arg) return AF_ERROR;
+
+ af->data->rate = ((struct mp_audio*)arg)->rate;
+ af->data->nch = ((struct mp_audio*)arg)->nch;
+ af->data->format = AF_FORMAT_FLOAT_NE;
+ af->data->bps = 4;
+
+ // Calculate number of active filters
+ s->K=KM;
+ while(F[s->K-1] > (float)af->data->rate/2.2)
+ s->K--;
+
+ if(s->K != KM)
+ mp_msg(MSGT_AFILTER, MSGL_INFO, "[equalizer] Limiting the number of filters to"
+ " %i due to low sample rate.\n",s->K);
+
+ // Generate filter taps
+ for(k=0;k<s->K;k++)
+ bp2(s->a[k],s->b[k],F[k]/((float)af->data->rate),Q);
+
+ // Calculate how much this plugin adds to the overall time delay
+ af->delay = 2 * af->data->nch * af->data->bps;
+
+ // Calculate gain factor to prevent clipping at output
+ for(k=0;k<AF_NCH;k++)
+ {
+ for(i=0;i<KM;i++)
+ {
+ if(s->gain_factor < s->g[k][i]) s->gain_factor=s->g[k][i];
+ }
+ }
+
+ s->gain_factor=log10(s->gain_factor + 1.0) * 20.0;
+
+ if(s->gain_factor > 0.0)
+ {
+ s->gain_factor=0.1+(s->gain_factor/12.0);
+ }else{
+ s->gain_factor=1;
+ }
+
+ return af_test_output(af,arg);
+ }
+ case AF_CONTROL_COMMAND_LINE:{
+ float g[10]={0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0};
+ int i,j;
+ sscanf((char*)arg,"%f:%f:%f:%f:%f:%f:%f:%f:%f:%f", &g[0], &g[1],
+ &g[2], &g[3], &g[4], &g[5], &g[6], &g[7], &g[8] ,&g[9]);
+ for(i=0;i<AF_NCH;i++){
+ for(j=0;j<KM;j++){
+ ((af_equalizer_t*)af->setup)->g[i][j] =
+ pow(10.0,clamp(g[j],G_MIN,G_MAX)/20.0)-1.0;
+ }
+ }
+ return AF_OK;
+ }
+ case AF_CONTROL_EQUALIZER_GAIN | AF_CONTROL_SET:{
+ float* gain = ((af_control_ext_t*)arg)->arg;
+ int ch = ((af_control_ext_t*)arg)->ch;
+ int k;
+ if(ch >= AF_NCH || ch < 0)
+ return AF_ERROR;
+
+ for(k = 0 ; k<KM ; k++)
+ s->g[ch][k] = pow(10.0,clamp(gain[k],G_MIN,G_MAX)/20.0)-1.0;
+
+ return AF_OK;
+ }
+ case AF_CONTROL_EQUALIZER_GAIN | AF_CONTROL_GET:{
+ float* gain = ((af_control_ext_t*)arg)->arg;
+ int ch = ((af_control_ext_t*)arg)->ch;
+ int k;
+ if(ch >= AF_NCH || ch < 0)
+ return AF_ERROR;
+
+ for(k = 0 ; k<KM ; k++)
+ gain[k] = log10(s->g[ch][k]+1.0) * 20.0;
+
+ return AF_OK;
+ }
+ }
+ return AF_UNKNOWN;
+}
+
+// Deallocate memory
+static void uninit(struct af_instance* af)
+{
+ free(af->data);
+ free(af->setup);
+}
+
+// Filter data through filter
+static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
+{
+ struct mp_audio* c = data; // Current working data
+ af_equalizer_t* s = (af_equalizer_t*)af->setup; // Setup
+ uint32_t ci = af->data->nch; // Index for channels
+ uint32_t nch = af->data->nch; // Number of channels
+
+ while(ci--){
+ float* g = s->g[ci]; // Gain factor
+ float* in = ((float*)c->audio)+ci;
+ float* out = ((float*)c->audio)+ci;
+ float* end = in + c->len/4; // Block loop end
+
+ while(in < end){
+ register int k = 0; // Frequency band index
+ register float yt = *in; // Current input sample
+ in+=nch;
+
+ // Run the filters
+ for(;k<s->K;k++){
+ // Pointer to circular buffer wq
+ register float* wq = s->wq[ci][k];
+ // Calculate output from AR part of current filter
+ register float w=yt*s->b[k][0] + wq[0]*s->a[k][0] + wq[1]*s->a[k][1];
+ // Calculate output form MA part of current filter
+ yt+=(w + wq[1]*s->b[k][1])*g[k];
+ // Update circular buffer
+ wq[1] = wq[0];
+ wq[0] = w;
+ }
+ // Calculate output
+ *out=yt*s->gain_factor;
+ out+=nch;
+ }
+ }
+ return c;
+}
+
+// Allocate memory and set function pointers
+static int af_open(struct af_instance* af){
+ af->control=control;
+ af->uninit=uninit;
+ af->play=play;
+ af->mul=1;
+ af->data=calloc(1,sizeof(struct mp_audio));
+ af->setup=calloc(1,sizeof(af_equalizer_t));
+ if(af->data == NULL || af->setup == NULL)
+ return AF_ERROR;
+ return AF_OK;
+}
+
+// Description of this filter
+struct af_info af_info_equalizer = {
+ "Equalizer audio filter",
+ "equalizer",
+ "Anders",
+ "",
+ AF_FLAGS_NOT_REENTRANT,
+ af_open
+};
diff --git a/audio/filter/af_export.c b/audio/filter/af_export.c
new file mode 100644
index 0000000000..441ec31ac3
--- /dev/null
+++ b/audio/filter/af_export.c
@@ -0,0 +1,273 @@
+/*
+ * This audio filter exports the incoming signal to other processes
+ * using memory mapping. The memory mapped area contains a header:
+ * int nch,
+ * int size,
+ * unsigned long long counter (updated every time the contents of
+ * the area changes),
+ * the rest is payload (non-interleaved).
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "af.h"
+#include "path.h"
+
+#define DEF_SZ 512 // default buffer size (in samples)
+#define SHARED_FILE "mpv-af_export" /* default file name
+ (relative to ~/.mpv/ */
+
+#define SIZE_HEADER (2 * sizeof(int) + sizeof(unsigned long long))
+
+// Data for specific instances of this filter
+typedef struct af_export_s
+{
+ unsigned long long count; // Used for sync
+ void* buf[AF_NCH]; // Buffers for storing the data before it is exported
+ int sz; // Size of buffer in samples
+ int wi; // Write index
+ int fd; // File descriptor to shared memory area
+ char* filename; // File to export data
+ uint8_t *mmap_area; // MMap shared area
+} af_export_t;
+
+
+/* Initialization and runtime control
+ af audio filter instance
+ cmd control command
+ arg argument
+*/
+static int control(struct af_instance* af, int cmd, void* arg)
+{
+ af_export_t* s = af->setup;
+ switch (cmd){
+ case AF_CONTROL_REINIT:{
+ int i=0;
+ int mapsize;
+
+ // Free previous buffers
+ if (s->buf)
+ free(s->buf[0]);
+
+ // unmap previous area
+ if(s->mmap_area)
+ munmap(s->mmap_area, SIZE_HEADER + (af->data->bps*s->sz*af->data->nch));
+ // close previous file descriptor
+ if(s->fd)
+ close(s->fd);
+
+ // Accept only int16_t as input format (which sucks)
+ af->data->rate = ((struct mp_audio*)arg)->rate;
+ af->data->nch = ((struct mp_audio*)arg)->nch;
+ af->data->format = AF_FORMAT_S16_NE;
+ af->data->bps = 2;
+
+ // If buffer length isn't set, set it to the default value
+ if(s->sz == 0)
+ s->sz = DEF_SZ;
+
+ // Allocate new buffers (as one continuous block)
+ s->buf[0] = calloc(s->sz*af->data->nch, af->data->bps);
+ if(NULL == s->buf[0])
+ mp_msg(MSGT_AFILTER, MSGL_FATAL, "[export] Out of memory\n");
+ for(i = 1; i < af->data->nch; i++)
+ s->buf[i] = (uint8_t *)s->buf[0] + i*s->sz*af->data->bps;
+
+ // Init memory mapping
+ s->fd = open(s->filename, O_RDWR | O_CREAT | O_TRUNC, 0640);
+ mp_msg(MSGT_AFILTER, MSGL_INFO, "[export] Exporting to file: %s\n", s->filename);
+ if(s->fd < 0)
+ mp_msg(MSGT_AFILTER, MSGL_FATAL, "[export] Could not open/create file: %s\n",
+ s->filename);
+
+ // header + buffer
+ mapsize = (SIZE_HEADER + (af->data->bps * s->sz * af->data->nch));
+
+ // grow file to needed size
+ for(i = 0; i < mapsize; i++){
+ char null = 0;
+ write(s->fd, (void*) &null, 1);
+ }
+
+ // mmap size
+ s->mmap_area = mmap(0, mapsize, PROT_READ|PROT_WRITE,MAP_SHARED, s->fd, 0);
+ if(s->mmap_area == NULL)
+ mp_msg(MSGT_AFILTER, MSGL_FATAL, "[export] Could not mmap file %s\n", s->filename);
+ mp_msg(MSGT_AFILTER, MSGL_INFO, "[export] Memory mapped to file: %s (%p)\n",
+ s->filename, s->mmap_area);
+
+ // Initialize header
+ *((int*)s->mmap_area) = af->data->nch;
+ *((int*)s->mmap_area + 1) = s->sz * af->data->bps * af->data->nch;
+ msync(s->mmap_area, mapsize, MS_ASYNC);
+
+ // Use test_output to return FALSE if necessary
+ return af_test_output(af, (struct mp_audio*)arg);
+ }
+ case AF_CONTROL_COMMAND_LINE:{
+ int i=0;
+ char *str = arg;
+
+ if (!str){
+ free(s->filename);
+
+ s->filename = get_path(SHARED_FILE);
+ return AF_OK;
+ }
+
+ while((str[i]) && (str[i] != ':'))
+ i++;
+
+ free(s->filename);
+
+ s->filename = calloc(i + 1, 1);
+ memcpy(s->filename, str, i);
+ s->filename[i] = 0;
+
+ sscanf(str + i + 1, "%d", &(s->sz));
+
+ return af->control(af, AF_CONTROL_EXPORT_SZ | AF_CONTROL_SET, &s->sz);
+ }
+ case AF_CONTROL_EXPORT_SZ | AF_CONTROL_SET:
+ s->sz = * (int *) arg;
+ if((s->sz <= 0) || (s->sz > 2048))
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[export] Buffer size must be between"
+ " 1 and 2048\n" );
+
+ return AF_OK;
+ case AF_CONTROL_EXPORT_SZ | AF_CONTROL_GET:
+ *(int*) arg = s->sz;
+ return AF_OK;
+
+ }
+ return AF_UNKNOWN;
+}
+
+/* Free allocated memory and clean up other stuff too.
+ af audio filter instance
+*/
+static void uninit( struct af_instance* af )
+{
+ free(af->data);
+ af->data = NULL;
+
+ if(af->setup){
+ af_export_t* s = af->setup;
+ if (s->buf)
+ free(s->buf[0]);
+
+ // Free mmaped area
+ if(s->mmap_area)
+ munmap(s->mmap_area, sizeof(af_export_t));
+
+ if(s->fd > -1)
+ close(s->fd);
+
+ free(s->filename);
+
+ free(af->setup);
+ af->setup = NULL;
+ }
+}
+
+/* Filter data through filter
+ af audio filter instance
+ data audio data
+*/
+static struct mp_audio* play( struct af_instance* af, struct mp_audio* data )
+{
+ struct mp_audio* c = data; // Current working data
+ af_export_t* s = af->setup; // Setup for this instance
+ int16_t* a = c->audio; // Incomming sound
+ int nch = c->nch; // Number of channels
+ int len = c->len/c->bps; // Number of sample in data chunk
+ int sz = s->sz; // buffer size (in samples)
+ int flag = 0; // Set to 1 if buffer is filled
+
+ int ch, i;
+
+ // Fill all buffers
+ for(ch = 0; ch < nch; ch++){
+ int wi = s->wi; // Reset write index
+ int16_t* b = s->buf[ch]; // Current buffer
+
+ // Copy data to export buffers
+ for(i = ch; i < len; i += nch){
+ b[wi++] = a[i];
+ if(wi >= sz){ // Don't write outside the end of the buffer
+ flag = 1;
+ break;
+ }
+ }
+ s->wi = wi % s->sz;
+ }
+
+ // Export buffer to mmaped area
+ if(flag){
+ // update buffer in mapped area
+ memcpy(s->mmap_area + SIZE_HEADER, s->buf[0], sz * c->bps * nch);
+ s->count++; // increment counter (to sync)
+ memcpy(s->mmap_area + SIZE_HEADER - sizeof(s->count),
+ &(s->count), sizeof(s->count));
+ }
+
+ // We don't modify data, just export it
+ return data;
+}
+
+/* Allocate memory and set function pointers
+ af audio filter instance
+ returns AF_OK or AF_ERROR
+*/
+static int af_open( struct af_instance* af )
+{
+ af->control = control;
+ af->uninit = uninit;
+ af->play = play;
+ af->mul=1;
+ af->data = calloc(1, sizeof(struct mp_audio));
+ af->setup = calloc(1, sizeof(af_export_t));
+ if((af->data == NULL) || (af->setup == NULL))
+ return AF_ERROR;
+
+ ((af_export_t *)af->setup)->filename = get_path(SHARED_FILE);
+
+ return AF_OK;
+}
+
+// Description of this filter
+struct af_info af_info_export = {
+ "Sound export filter",
+ "export",
+ "Anders; Gustavo Sverzut Barbieri <gustavo.barbieri@ic.unicamp.br>",
+ "",
+ AF_FLAGS_REENTRANT,
+ af_open
+};
diff --git a/audio/filter/af_extrastereo.c b/audio/filter/af_extrastereo.c
new file mode 100644
index 0000000000..0f7fe36861
--- /dev/null
+++ b/audio/filter/af_extrastereo.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2004 Alex Beregszaszi & Pierre Lombard
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <inttypes.h>
+#include <math.h>
+#include <limits.h>
+
+#include "af.h"
+
+// Data for specific instances of this filter
+typedef struct af_extrastereo_s
+{
+ float mul;
+}af_extrastereo_t;
+
+static struct mp_audio* play_s16(struct af_instance* af, struct mp_audio* data);
+static struct mp_audio* play_float(struct af_instance* af, struct mp_audio* data);
+
+// Initialization and runtime control
+static int control(struct af_instance* af, int cmd, void* arg)
+{
+ af_extrastereo_t* s = (af_extrastereo_t*)af->setup;
+
+ switch(cmd){
+ case AF_CONTROL_REINIT:{
+ // Sanity check
+ if(!arg) return AF_ERROR;
+
+ af->data->rate = ((struct mp_audio*)arg)->rate;
+ af->data->nch = 2;
+ if (((struct mp_audio*)arg)->format == AF_FORMAT_FLOAT_NE)
+ {
+ af->data->format = AF_FORMAT_FLOAT_NE;
+ af->data->bps = 4;
+ af->play = play_float;
+ }// else
+ {
+ af->data->format = AF_FORMAT_S16_NE;
+ af->data->bps = 2;
+ af->play = play_s16;
+ }
+
+ return af_test_output(af,(struct mp_audio*)arg);
+ }
+ case AF_CONTROL_COMMAND_LINE:{
+ float f;
+ sscanf((char*)arg,"%f", &f);
+ s->mul = f;
+ return AF_OK;
+ }
+ case AF_CONTROL_ES_MUL | AF_CONTROL_SET:
+ s->mul = *(float*)arg;
+ return AF_OK;
+ case AF_CONTROL_ES_MUL | AF_CONTROL_GET:
+ *(float*)arg = s->mul;
+ return AF_OK;
+ }
+ return AF_UNKNOWN;
+}
+
+// Deallocate memory
+static void uninit(struct af_instance* af)
+{
+ free(af->data);
+ free(af->setup);
+}
+
+// Filter data through filter
+static struct mp_audio* play_s16(struct af_instance* af, struct mp_audio* data)
+{
+ af_extrastereo_t *s = af->setup;
+ register int i = 0;
+ int16_t *a = (int16_t*)data->audio; // Audio data
+ int len = data->len/2; // Number of samples
+ int avg, l, r;
+
+ for (i = 0; i < len; i+=2)
+ {
+ avg = (a[i] + a[i + 1]) / 2;
+
+ l = avg + (int)(s->mul * (a[i] - avg));
+ r = avg + (int)(s->mul * (a[i + 1] - avg));
+
+ a[i] = clamp(l, SHRT_MIN, SHRT_MAX);
+ a[i + 1] = clamp(r, SHRT_MIN, SHRT_MAX);
+ }
+
+ return data;
+}
+
+static struct mp_audio* play_float(struct af_instance* af, struct mp_audio* data)
+{
+ af_extrastereo_t *s = af->setup;
+ register int i = 0;
+ float *a = (float*)data->audio; // Audio data
+ int len = data->len/4; // Number of samples
+ float avg, l, r;
+
+ for (i = 0; i < len; i+=2)
+ {
+ avg = (a[i] + a[i + 1]) / 2;
+
+ l = avg + (s->mul * (a[i] - avg));
+ r = avg + (s->mul * (a[i + 1] - avg));
+
+ a[i] = af_softclip(l);
+ a[i + 1] = af_softclip(r);
+ }
+
+ return data;
+}
+
+// Allocate memory and set function pointers
+static int af_open(struct af_instance* af){
+ af->control=control;
+ af->uninit=uninit;
+ af->play=play_s16;
+ af->mul=1;
+ af->data=calloc(1,sizeof(struct mp_audio));
+ af->setup=calloc(1,sizeof(af_extrastereo_t));
+ if(af->data == NULL || af->setup == NULL)
+ return AF_ERROR;
+
+ ((af_extrastereo_t*)af->setup)->mul = 2.5;
+ return AF_OK;
+}
+
+// Description of this filter
+struct af_info af_info_extrastereo = {
+ "Increase difference between audio channels",
+ "extrastereo",
+ "Alex Beregszaszi & Pierre Lombard",
+ "",
+ AF_FLAGS_NOT_REENTRANT,
+ af_open
+};
diff --git a/audio/filter/af_format.c b/audio/filter/af_format.c
new file mode 100644
index 0000000000..4ac9caaa85
--- /dev/null
+++ b/audio/filter/af_format.c
@@ -0,0 +1,519 @@
+/*
+ * This audio filter changes the format of a data block. Valid
+ * formats are: AFMT_U8, AFMT_S8, AFMT_S16_LE, AFMT_S16_BE
+ * AFMT_U16_LE, AFMT_U16_BE, AFMT_S32_LE and AFMT_S32_BE.
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <math.h>
+#include <sys/types.h>
+
+#include "config.h"
+#include "af.h"
+#include "mpbswap.h"
+
+/* Functions used by play to convert the input audio to the correct
+ format */
+
+/* The below includes retrieves functions for converting to and from
+ ulaw and alaw */
+#include "af_format_ulaw.h"
+#include "af_format_alaw.h"
+
+// Switch endianness
+static void endian(void* in, void* out, int len, int bps);
+// From signed to unsigned and the other way
+static void si2us(void* data, int len, int bps);
+// Change the number of bits per sample
+static void change_bps(void* in, void* out, int len, int inbps, int outbps);
+// From float to int signed
+static void float2int(float* in, void* out, int len, int bps);
+// From signed int to float
+static void int2float(void* in, float* out, int len, int bps);
+
+static struct mp_audio* play(struct af_instance* af, struct mp_audio* data);
+static struct mp_audio* play_swapendian(struct af_instance* af, struct mp_audio* data);
+static struct mp_audio* play_float_s16(struct af_instance* af, struct mp_audio* data);
+static struct mp_audio* play_s16_float(struct af_instance* af, struct mp_audio* data);
+
+// Helper functions to check sanity for input arguments
+
+// Sanity check for bytes per sample
+static int check_bps(int bps)
+{
+ if(bps != 4 && bps != 3 && bps != 2 && bps != 1){
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[format] The number of bytes per sample"
+ " must be 1, 2, 3 or 4. Current value is %i \n",bps);
+ return AF_ERROR;
+ }
+ return AF_OK;
+}
+
+// Check for unsupported formats
+static int check_format(int format)
+{
+ char buf[256];
+ switch(format & AF_FORMAT_SPECIAL_MASK){
+ case(AF_FORMAT_IMA_ADPCM):
+ case(AF_FORMAT_MPEG2):
+ case(AF_FORMAT_AC3):
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[format] Sample format %s not yet supported \n",
+ af_fmt2str(format,buf,256));
+ return AF_ERROR;
+ }
+ return AF_OK;
+}
+
+// Initialization and runtime control
+static int control(struct af_instance* af, int cmd, void* arg)
+{
+ switch(cmd){
+ case AF_CONTROL_REINIT:{
+ char buf1[256];
+ char buf2[256];
+ struct mp_audio *data = arg;
+
+ // Make sure this filter isn't redundant
+ if(af->data->format == data->format &&
+ af->data->bps == data->bps)
+ return AF_DETACH;
+
+ // Allow trivial AC3-endianness conversion
+ if (!AF_FORMAT_IS_AC3(af->data->format) || !AF_FORMAT_IS_AC3(data->format))
+ // Check for errors in configuration
+ if((AF_OK != check_bps(data->bps)) ||
+ (AF_OK != check_format(data->format)) ||
+ (AF_OK != check_bps(af->data->bps)) ||
+ (AF_OK != check_format(af->data->format)))
+ return AF_ERROR;
+
+ mp_msg(MSGT_AFILTER, MSGL_V, "[format] Changing sample format from %s to %s\n",
+ af_fmt2str(data->format,buf1,256),
+ af_fmt2str(af->data->format,buf2,256));
+
+ af->data->rate = data->rate;
+ af->data->nch = data->nch;
+ af->mul = (double)af->data->bps / data->bps;
+
+ af->play = play; // set default
+
+ // look whether only endianness differences are there
+ if ((af->data->format & ~AF_FORMAT_END_MASK) ==
+ (data->format & ~AF_FORMAT_END_MASK))
+ {
+ mp_msg(MSGT_AFILTER, MSGL_V, "[format] Accelerated endianness conversion only\n");
+ af->play = play_swapendian;
+ }
+ if ((data->format == AF_FORMAT_FLOAT_NE) &&
+ (af->data->format == AF_FORMAT_S16_NE))
+ {
+ mp_msg(MSGT_AFILTER, MSGL_V, "[format] Accelerated %s to %s conversion\n",
+ af_fmt2str(data->format,buf1,256),
+ af_fmt2str(af->data->format,buf2,256));
+ af->play = play_float_s16;
+ }
+ if ((data->format == AF_FORMAT_S16_NE) &&
+ (af->data->format == AF_FORMAT_FLOAT_NE))
+ {
+ mp_msg(MSGT_AFILTER, MSGL_V, "[format] Accelerated %s to %s conversion\n",
+ af_fmt2str(data->format,buf1,256),
+ af_fmt2str(af->data->format,buf2,256));
+ af->play = play_s16_float;
+ }
+ return AF_OK;
+ }
+ case AF_CONTROL_COMMAND_LINE:{
+ int format = af_str2fmt_short(bstr0(arg));
+ if (format == -1) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[format] %s is not a valid format\n", (char *)arg);
+ return AF_ERROR;
+ }
+ if(AF_OK != af->control(af,AF_CONTROL_FORMAT_FMT | AF_CONTROL_SET,&format))
+ return AF_ERROR;
+ return AF_OK;
+ }
+ case AF_CONTROL_FORMAT_FMT | AF_CONTROL_SET:{
+ // Check for errors in configuration
+ if(!AF_FORMAT_IS_AC3(*(int*)arg) && AF_OK != check_format(*(int*)arg))
+ return AF_ERROR;
+
+ af->data->format = *(int*)arg;
+ af->data->bps = af_fmt2bits(af->data->format)/8;
+
+ return AF_OK;
+ }
+ }
+ return AF_UNKNOWN;
+}
+
+// Deallocate memory
+static void uninit(struct af_instance* af)
+{
+ if (af->data)
+ free(af->data->audio);
+ free(af->data);
+ af->setup = 0;
+}
+
+static struct mp_audio* play_swapendian(struct af_instance* af, struct mp_audio* data)
+{
+ struct mp_audio* l = af->data; // Local data
+ struct mp_audio* c = data; // Current working data
+ int len = c->len/c->bps; // Length in samples of current audio block
+
+ if(AF_OK != RESIZE_LOCAL_BUFFER(af,data))
+ return NULL;
+
+ endian(c->audio,l->audio,len,c->bps);
+
+ c->audio = l->audio;
+ c->format = l->format;
+
+ return c;
+}
+
+static struct mp_audio* play_float_s16(struct af_instance* af, struct mp_audio* data)
+{
+ struct mp_audio* l = af->data; // Local data
+ struct mp_audio* c = data; // Current working data
+ int len = c->len/4; // Length in samples of current audio block
+
+ if(AF_OK != RESIZE_LOCAL_BUFFER(af,data))
+ return NULL;
+
+ float2int(c->audio, l->audio, len, 2);
+
+ c->audio = l->audio;
+ c->len = len*2;
+ c->bps = 2;
+ c->format = l->format;
+
+ return c;
+}
+
+static struct mp_audio* play_s16_float(struct af_instance* af, struct mp_audio* data)
+{
+ struct mp_audio* l = af->data; // Local data
+ struct mp_audio* c = data; // Current working data
+ int len = c->len/2; // Length in samples of current audio block
+
+ if(AF_OK != RESIZE_LOCAL_BUFFER(af,data))
+ return NULL;
+
+ int2float(c->audio, l->audio, len, 2);
+
+ c->audio = l->audio;
+ c->len = len*4;
+ c->bps = 4;
+ c->format = l->format;
+
+ return c;
+}
+
+// Filter data through filter
+static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
+{
+ struct mp_audio* l = af->data; // Local data
+ struct mp_audio* c = data; // Current working data
+ int len = c->len/c->bps; // Length in samples of current audio block
+
+ if(AF_OK != RESIZE_LOCAL_BUFFER(af,data))
+ return NULL;
+
+ // Change to cpu native endian format
+ if((c->format&AF_FORMAT_END_MASK)!=AF_FORMAT_NE)
+ endian(c->audio,c->audio,len,c->bps);
+
+ // Conversion table
+ if((c->format & AF_FORMAT_SPECIAL_MASK) == AF_FORMAT_MU_LAW) {
+ from_ulaw(c->audio, l->audio, len, l->bps, l->format&AF_FORMAT_POINT_MASK);
+ if(AF_FORMAT_A_LAW == (l->format&AF_FORMAT_SPECIAL_MASK))
+ to_ulaw(l->audio, l->audio, len, 1, AF_FORMAT_SI);
+ if((l->format&AF_FORMAT_SIGN_MASK) == AF_FORMAT_US)
+ si2us(l->audio,len,l->bps);
+ } else if((c->format & AF_FORMAT_SPECIAL_MASK) == AF_FORMAT_A_LAW) {
+ from_alaw(c->audio, l->audio, len, l->bps, l->format&AF_FORMAT_POINT_MASK);
+ if(AF_FORMAT_A_LAW == (l->format&AF_FORMAT_SPECIAL_MASK))
+ to_alaw(l->audio, l->audio, len, 1, AF_FORMAT_SI);
+ if((l->format&AF_FORMAT_SIGN_MASK) == AF_FORMAT_US)
+ si2us(l->audio,len,l->bps);
+ } else if((c->format & AF_FORMAT_POINT_MASK) == AF_FORMAT_F) {
+ switch(l->format&AF_FORMAT_SPECIAL_MASK){
+ case(AF_FORMAT_MU_LAW):
+ to_ulaw(c->audio, l->audio, len, c->bps, c->format&AF_FORMAT_POINT_MASK);
+ break;
+ case(AF_FORMAT_A_LAW):
+ to_alaw(c->audio, l->audio, len, c->bps, c->format&AF_FORMAT_POINT_MASK);
+ break;
+ default:
+ float2int(c->audio, l->audio, len, l->bps);
+ if((l->format&AF_FORMAT_SIGN_MASK) == AF_FORMAT_US)
+ si2us(l->audio,len,l->bps);
+ break;
+ }
+ } else {
+ // Input must be int
+
+ // Change signed/unsigned
+ if((c->format&AF_FORMAT_SIGN_MASK) != (l->format&AF_FORMAT_SIGN_MASK)){
+ si2us(c->audio,len,c->bps);
+ }
+ // Convert to special formats
+ switch(l->format&(AF_FORMAT_SPECIAL_MASK|AF_FORMAT_POINT_MASK)){
+ case(AF_FORMAT_MU_LAW):
+ to_ulaw(c->audio, l->audio, len, c->bps, c->format&AF_FORMAT_POINT_MASK);
+ break;
+ case(AF_FORMAT_A_LAW):
+ to_alaw(c->audio, l->audio, len, c->bps, c->format&AF_FORMAT_POINT_MASK);
+ break;
+ case(AF_FORMAT_F):
+ int2float(c->audio, l->audio, len, c->bps);
+ break;
+ default:
+ // Change the number of bits
+ if(c->bps != l->bps)
+ change_bps(c->audio,l->audio,len,c->bps,l->bps);
+ else
+ memcpy(l->audio,c->audio,len*c->bps);
+ break;
+ }
+ }
+
+ // Switch from cpu native endian to the correct endianness
+ if((l->format&AF_FORMAT_END_MASK)!=AF_FORMAT_NE)
+ endian(l->audio,l->audio,len,l->bps);
+
+ // Set output data
+ c->audio = l->audio;
+ c->len = len*l->bps;
+ c->bps = l->bps;
+ c->format = l->format;
+ return c;
+}
+
+// Allocate memory and set function pointers
+static int af_open(struct af_instance* af){
+ af->control=control;
+ af->uninit=uninit;
+ af->play=play;
+ af->mul=1;
+ af->data=calloc(1,sizeof(struct mp_audio));
+ if(af->data == NULL)
+ return AF_ERROR;
+ return AF_OK;
+}
+
+// Description of this filter
+struct af_info af_info_format = {
+ "Sample format conversion",
+ "format",
+ "Anders",
+ "",
+ AF_FLAGS_REENTRANT,
+ af_open
+};
+
+static inline uint32_t load24bit(void* data, int pos) {
+#if BYTE_ORDER == BIG_ENDIAN
+ return (((uint32_t)((uint8_t*)data)[3*pos])<<24) |
+ (((uint32_t)((uint8_t*)data)[3*pos+1])<<16) |
+ (((uint32_t)((uint8_t*)data)[3*pos+2])<<8);
+#else
+ return (((uint32_t)((uint8_t*)data)[3*pos])<<8) |
+ (((uint32_t)((uint8_t*)data)[3*pos+1])<<16) |
+ (((uint32_t)((uint8_t*)data)[3*pos+2])<<24);
+#endif
+}
+
+static inline void store24bit(void* data, int pos, uint32_t expanded_value) {
+#if BYTE_ORDER == BIG_ENDIAN
+ ((uint8_t*)data)[3*pos]=expanded_value>>24;
+ ((uint8_t*)data)[3*pos+1]=expanded_value>>16;
+ ((uint8_t*)data)[3*pos+2]=expanded_value>>8;
+#else
+ ((uint8_t*)data)[3*pos]=expanded_value>>8;
+ ((uint8_t*)data)[3*pos+1]=expanded_value>>16;
+ ((uint8_t*)data)[3*pos+2]=expanded_value>>24;
+#endif
+}
+
+// Function implementations used by play
+static void endian(void* in, void* out, int len, int bps)
+{
+ register int i;
+ switch(bps){
+ case(2):{
+ for(i=0;i<len;i++){
+ ((uint16_t*)out)[i]=bswap_16(((uint16_t*)in)[i]);
+ }
+ break;
+ }
+ case(3):{
+ register uint8_t s;
+ for(i=0;i<len;i++){
+ s=((uint8_t*)in)[3*i];
+ ((uint8_t*)out)[3*i]=((uint8_t*)in)[3*i+2];
+ if (in != out)
+ ((uint8_t*)out)[3*i+1]=((uint8_t*)in)[3*i+1];
+ ((uint8_t*)out)[3*i+2]=s;
+ }
+ break;
+ }
+ case(4):{
+ for(i=0;i<len;i++){
+ ((uint32_t*)out)[i]=bswap_32(((uint32_t*)in)[i]);
+ }
+ break;
+ }
+ }
+}
+
+static void si2us(void* data, int len, int bps)
+{
+ register long i = -(len * bps);
+ register uint8_t *p = &((uint8_t *)data)[len * bps];
+#if AF_FORMAT_NE == AF_FORMAT_LE
+ p += bps - 1;
+#endif
+ if (len <= 0) return;
+ do {
+ p[i] ^= 0x80;
+ } while (i += bps);
+}
+
+static void change_bps(void* in, void* out, int len, int inbps, int outbps)
+{
+ register int i;
+ switch(inbps){
+ case(1):
+ switch(outbps){
+ case(2):
+ for(i=0;i<len;i++)
+ ((uint16_t*)out)[i]=((uint16_t)((uint8_t*)in)[i])<<8;
+ break;
+ case(3):
+ for(i=0;i<len;i++)
+ store24bit(out, i, ((uint32_t)((uint8_t*)in)[i])<<24);
+ break;
+ case(4):
+ for(i=0;i<len;i++)
+ ((uint32_t*)out)[i]=((uint32_t)((uint8_t*)in)[i])<<24;
+ break;
+ }
+ break;
+ case(2):
+ switch(outbps){
+ case(1):
+ for(i=0;i<len;i++)
+ ((uint8_t*)out)[i]=(uint8_t)((((uint16_t*)in)[i])>>8);
+ break;
+ case(3):
+ for(i=0;i<len;i++)
+ store24bit(out, i, ((uint32_t)((uint16_t*)in)[i])<<16);
+ break;
+ case(4):
+ for(i=0;i<len;i++)
+ ((uint32_t*)out)[i]=((uint32_t)((uint16_t*)in)[i])<<16;
+ break;
+ }
+ break;
+ case(3):
+ switch(outbps){
+ case(1):
+ for(i=0;i<len;i++)
+ ((uint8_t*)out)[i]=(uint8_t)(load24bit(in, i)>>24);
+ break;
+ case(2):
+ for(i=0;i<len;i++)
+ ((uint16_t*)out)[i]=(uint16_t)(load24bit(in, i)>>16);
+ break;
+ case(4):
+ for(i=0;i<len;i++)
+ ((uint32_t*)out)[i]=(uint32_t)load24bit(in, i);
+ break;
+ }
+ break;
+ case(4):
+ switch(outbps){
+ case(1):
+ for(i=0;i<len;i++)
+ ((uint8_t*)out)[i]=(uint8_t)((((uint32_t*)in)[i])>>24);
+ break;
+ case(2):
+ for(i=0;i<len;i++)
+ ((uint16_t*)out)[i]=(uint16_t)((((uint32_t*)in)[i])>>16);
+ break;
+ case(3):
+ for(i=0;i<len;i++)
+ store24bit(out, i, ((uint32_t*)in)[i]);
+ break;
+ }
+ break;
+ }
+}
+
+static void float2int(float* in, void* out, int len, int bps)
+{
+ register int i;
+ switch(bps){
+ case(1):
+ for(i=0;i<len;i++)
+ ((int8_t*)out)[i] = lrintf(127.0 * clamp(in[i], -1.0f, +1.0f));
+ break;
+ case(2):
+ for(i=0;i<len;i++)
+ ((int16_t*)out)[i] = lrintf(32767.0 * clamp(in[i], -1.0f, +1.0f));
+ break;
+ case(3):
+ for(i=0;i<len;i++)
+ store24bit(out, i, lrintf(2147483647.0 * clamp(in[i], -1.0f, +1.0f)));
+ break;
+ case(4):
+ for(i=0;i<len;i++)
+ ((int32_t*)out)[i] = lrintf(2147483647.0 * clamp(in[i], -1.0f, +1.0f));
+ break;
+ }
+}
+
+static void int2float(void* in, float* out, int len, int bps)
+{
+ register int i;
+ switch(bps){
+ case(1):
+ for(i=0;i<len;i++)
+ out[i]=(1.0/128.0)*((int8_t*)in)[i];
+ break;
+ case(2):
+ for(i=0;i<len;i++)
+ out[i]=(1.0/32768.0)*((int16_t*)in)[i];
+ break;
+ case(3):
+ for(i=0;i<len;i++)
+ out[i]=(1.0/2147483648.0)*((int32_t)load24bit(in, i));
+ break;
+ case(4):
+ for(i=0;i<len;i++)
+ out[i]=(1.0/2147483648.0)*((int32_t*)in)[i];
+ break;
+ }
+}
diff --git a/audio/filter/af_format_alaw.h b/audio/filter/af_format_alaw.h
new file mode 100644
index 0000000000..d7c00884f7
--- /dev/null
+++ b/audio/filter/af_format_alaw.h
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2002 Anders Johansson ajh@watri.uwa.edu.au
+ *
+ * This file is based on a part of libsndfile, the work of
+ * Erik de Castro Lopo <erikd@zip.com.au>.
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPLAYER_AF_FORMAT_ALAW_H
+#define MPLAYER_AF_FORMAT_ALAW_H
+
+#include <inttypes.h>
+
+#include "af.h"
+
+// Conversion tables (the function are below)
+static short alaw_decode [128] =
+{ -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
+ -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
+ -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
+ -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
+ -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
+ -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
+ -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472,
+ -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
+ -344, -328, -376, -360, -280, -264, -312, -296,
+ -472, -456, -504, -488, -408, -392, -440, -424,
+ -88, -72, -120, -104, -24, -8, -56, -40,
+ -216, -200, -248, -232, -152, -136, -184, -168,
+ -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
+ -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
+ -688, -656, -752, -720, -560, -528, -624, -592,
+ -944, -912, -1008, -976, -816, -784, -880, -848
+} ; /* alaw_decode */
+
+static unsigned char alaw_encode [2049] =
+{ 0xD5, 0xD4, 0xD7, 0xD6, 0xD1, 0xD0, 0xD3, 0xD2, 0xDD, 0xDC, 0xDF, 0xDE,
+ 0xD9, 0xD8, 0xDB, 0xDA, 0xC5, 0xC4, 0xC7, 0xC6, 0xC1, 0xC0, 0xC3, 0xC2,
+ 0xCD, 0xCC, 0xCF, 0xCE, 0xC9, 0xC8, 0xCB, 0xCA, 0xF5, 0xF5, 0xF4, 0xF4,
+ 0xF7, 0xF7, 0xF6, 0xF6, 0xF1, 0xF1, 0xF0, 0xF0, 0xF3, 0xF3, 0xF2, 0xF2,
+ 0xFD, 0xFD, 0xFC, 0xFC, 0xFF, 0xFF, 0xFE, 0xFE, 0xF9, 0xF9, 0xF8, 0xF8,
+ 0xFB, 0xFB, 0xFA, 0xFA, 0xE5, 0xE5, 0xE5, 0xE5, 0xE4, 0xE4, 0xE4, 0xE4,
+ 0xE7, 0xE7, 0xE7, 0xE7, 0xE6, 0xE6, 0xE6, 0xE6, 0xE1, 0xE1, 0xE1, 0xE1,
+ 0xE0, 0xE0, 0xE0, 0xE0, 0xE3, 0xE3, 0xE3, 0xE3, 0xE2, 0xE2, 0xE2, 0xE2,
+ 0xED, 0xED, 0xED, 0xED, 0xEC, 0xEC, 0xEC, 0xEC, 0xEF, 0xEF, 0xEF, 0xEF,
+ 0xEE, 0xEE, 0xEE, 0xEE, 0xE9, 0xE9, 0xE9, 0xE9, 0xE8, 0xE8, 0xE8, 0xE8,
+ 0xEB, 0xEB, 0xEB, 0xEB, 0xEA, 0xEA, 0xEA, 0xEA, 0x95, 0x95, 0x95, 0x95,
+ 0x95, 0x95, 0x95, 0x95, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+ 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x96,
+ 0x96, 0x96, 0x96, 0x96, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x93, 0x93, 0x93, 0x93,
+ 0x93, 0x93, 0x93, 0x93, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+ 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9C, 0x9C, 0x9C, 0x9C,
+ 0x9C, 0x9C, 0x9C, 0x9C, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F,
+ 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x99, 0x99, 0x99, 0x99,
+ 0x99, 0x99, 0x99, 0x99, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+ 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9A, 0x9A, 0x9A, 0x9A,
+ 0x9A, 0x9A, 0x9A, 0x9A, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, 0x84, 0x84, 0x84,
+ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+ 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+ 0x87, 0x87, 0x87, 0x87, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+ 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D,
+ 0x8D, 0x8D, 0x8D, 0x8D, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C,
+ 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8F, 0x8F, 0x8F, 0x8F,
+ 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
+ 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E,
+ 0x8E, 0x8E, 0x8E, 0x8E, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+ 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B,
+ 0x8B, 0x8B, 0x8B, 0x8B, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0xB5, 0xB5, 0xB5, 0xB5,
+ 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5,
+ 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5,
+ 0xB5, 0xB5, 0xB5, 0xB5, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4,
+ 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4,
+ 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4,
+ 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7,
+ 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7,
+ 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB6, 0xB6, 0xB6, 0xB6,
+ 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6,
+ 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6,
+ 0xB6, 0xB6, 0xB6, 0xB6, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1,
+ 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1,
+ 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1,
+ 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0,
+ 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0,
+ 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB3, 0xB3, 0xB3, 0xB3,
+ 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3,
+ 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3,
+ 0xB3, 0xB3, 0xB3, 0xB3, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2,
+ 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2,
+ 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2,
+ 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD,
+ 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD,
+ 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBC, 0xBC, 0xBC, 0xBC,
+ 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC,
+ 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC,
+ 0xBC, 0xBC, 0xBC, 0xBC, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF,
+ 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF,
+ 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF,
+ 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE,
+ 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE,
+ 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xB9, 0xB9, 0xB9, 0xB9,
+ 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9,
+ 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9,
+ 0xB9, 0xB9, 0xB9, 0xB9, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8,
+ 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8,
+ 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8,
+ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBA, 0xBA, 0xBA, 0xBA,
+ 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA,
+ 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA,
+ 0xBA, 0xBA, 0xBA, 0xBA, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5,
+ 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5,
+ 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5,
+ 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5,
+ 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5,
+ 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA4, 0xA4, 0xA4, 0xA4,
+ 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4,
+ 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4,
+ 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4,
+ 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4,
+ 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4,
+ 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7,
+ 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7,
+ 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7,
+ 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7,
+ 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7,
+ 0xA7, 0xA7, 0xA7, 0xA7, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6,
+ 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6,
+ 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6,
+ 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6,
+ 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6,
+ 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA1, 0xA1, 0xA1, 0xA1,
+ 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1,
+ 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1,
+ 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1,
+ 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1,
+ 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1,
+ 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
+ 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
+ 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
+ 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
+ 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
+ 0xA0, 0xA0, 0xA0, 0xA0, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
+ 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
+ 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
+ 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
+ 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
+ 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA2, 0xA2, 0xA2, 0xA2,
+ 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2,
+ 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2,
+ 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2,
+ 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2,
+ 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2,
+ 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD,
+ 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD,
+ 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD,
+ 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD,
+ 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD,
+ 0xAD, 0xAD, 0xAD, 0xAD, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC,
+ 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC,
+ 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC,
+ 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC,
+ 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC,
+ 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAF, 0xAF, 0xAF, 0xAF,
+ 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF,
+ 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF,
+ 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF,
+ 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF,
+ 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF,
+ 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE,
+ 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE,
+ 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE,
+ 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE,
+ 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE,
+ 0xAE, 0xAE, 0xAE, 0xAE, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9,
+ 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9,
+ 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9,
+ 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9,
+ 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9,
+ 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA8, 0xA8, 0xA8, 0xA8,
+ 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8,
+ 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8,
+ 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8,
+ 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8,
+ 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8,
+ 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB,
+ 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB,
+ 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB,
+ 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB,
+ 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB,
+ 0xAB, 0xAB, 0xAB, 0xAB, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x2A
+} ; /* alaw_encode */
+
+/* Convert from alaw to signd int8 to signed int32 or float */
+static int from_alaw(void* in, void* out, int len, int bps, int format)
+{
+ register int i;
+ // Make sure the input parametrs are OK
+ if(format & (AF_FORMAT_SPECIAL_MASK | AF_FORMAT_US))
+ return AF_ERROR;
+
+ // Convert to int or to float
+ if((format & AF_FORMAT_POINT_MASK) == AF_FORMAT_I){
+ switch(bps){
+ case(1):
+ for(i=0;i<len;i++){
+ if(((int8_t*)in)[i] & 0x80)
+ ((int8_t*)out)[i] = (-1 * alaw_decode[(((int8_t*)in)[i]) & 0x7F]) >> 8;
+ else
+ ((int8_t*)out)[i] = (alaw_decode[(((int8_t*)in)[i]) & 0x7F]) >> 8;
+ }
+ break;
+ case(2):
+ for(i=0;i<len;i++){
+ if(((int8_t*)in)[i] & 0x80)
+ ((int16_t*)out)[i] = -1 * alaw_decode[(((int8_t*)in)[i]) & 0x7F];
+ else
+ ((int16_t*)out)[i] = alaw_decode[(((int8_t*)in)[i]) & 0x7F];
+ }
+ break;
+ case(4):
+ for(i=0;i<len;i++){
+ if(((int8_t*)in)[i] & 0x80)
+ ((int32_t*)out)[i] = (-1 * alaw_decode[(((int8_t*)in)[i]) & 0x7F]) << 16;
+ else
+ ((int32_t*)out)[i] = (alaw_decode[(((int8_t*)in)[i]) & 0x7F]) << 16;
+ }
+ break;
+ default:
+ return AF_ERROR;
+ }
+ }
+ else{
+ for(i=0;i<len;i++){
+ if(((int8_t*)in)[i] & 0x80)
+ ((float*)out)[i] = -1.0/32768.0 * (float)alaw_decode[(((int8_t*)in)[i]) & 0x7F];
+ else
+ ((float*)out)[i] = +1.0/32768.0 * (float)alaw_decode[(((int8_t*)in)[i]) & 0x7F];
+ }
+ }
+ return AF_OK;
+}
+
+/* Convert from signed int8 to signed int32 or float to alaw */
+static int to_alaw(void* in, void* out, int len, int bps, int format)
+{
+ register int i;
+ // Make sure the input parametrs are OK
+ if(format & (AF_FORMAT_SPECIAL_MASK | AF_FORMAT_US))
+ return AF_ERROR;
+
+ // Convert from int or to float
+ if((format & AF_FORMAT_POINT_MASK) == AF_FORMAT_I){
+ switch(bps){
+ case(1):
+ for(i=0;i<len;i++){
+ if(((int8_t*)in)[i] >= 0)
+ ((int8_t*)out)[i] = alaw_encode[((int8_t*)in)[i] << 4];
+ else
+ ((int8_t*)out)[i] = 0x7F & alaw_encode[-((int8_t*)in)[i] << 4];
+ }
+ break;
+ case(2):
+ for(i=0;i<len;i++){
+ if(((int16_t*)in)[i] >= 0)
+ ((int8_t*)out)[i] = alaw_encode[((int16_t*)in)[i] / 16];
+ else
+ ((int8_t*)out)[i] = 0x7F & alaw_encode[((int16_t*)in)[i] / -16];
+ }
+ break;
+ case(4):
+ for(i=0;i<len;i++){
+ if(((int32_t*)in)[i] >= 0)
+ ((int8_t*)out)[i] = alaw_encode[((int32_t*)in)[i] >> (16 + 4)];
+ else
+ ((int8_t*)out)[i] = 0x7F & alaw_encode[-((int32_t*)in)[i] >> (16 + 4)];
+ }
+ break;
+ default:
+ return AF_ERROR;
+ }
+ }
+ else{
+ for(i=0;i<len;i++){
+ if(((float*)in)[i] >= 0)
+ ((int8_t*)out)[i] = alaw_encode[(int)(32767.0/16.0 * ((float*)in)[i])];
+ else
+ ((int8_t*)out)[i] = 0x7F & alaw_encode[(int)(-32767.0/16.0 * ((float*)in)[i])];
+ }
+ }
+ return AF_OK;
+}
+#endif /* MPLAYER_AF_FORMAT_ALAW_H */
diff --git a/audio/filter/af_format_ulaw.h b/audio/filter/af_format_ulaw.h
new file mode 100644
index 0000000000..5167a1593a
--- /dev/null
+++ b/audio/filter/af_format_ulaw.h
@@ -0,0 +1,837 @@
+/*
+ * Copyright (C) 2002 Anders Johansson ajh@watri.uwa.edu.au
+ *
+ * This file is based on a part of libsndfile, the work of
+ * Erik de Castro Lopo <erikd@zip.com.au>.
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPLAYER_AF_FORMAT_ULAW_H
+#define MPLAYER_AF_FORMAT_ULAW_H
+
+#include <inttypes.h>
+
+#include "af.h"
+// Conversion tables (the function are below)
+static short ulaw_decode[128] =
+{ -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
+ -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
+ -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
+ -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316,
+ -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
+ -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
+ -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
+ -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
+ -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
+ -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
+ -876, -844, -812, -780, -748, -716, -684, -652,
+ -620, -588, -556, -524, -492, -460, -428, -396,
+ -372, -356, -340, -324, -308, -292, -276, -260,
+ -244, -228, -212, -196, -180, -164, -148, -132,
+ -120, -112, -104, -96, -88, -80, -72, -64,
+ -56, -48, -40, -32, -24, -16, -8, 0,
+} ;
+
+static unsigned char ulaw_encode[8193] =
+{ 0xFF, 0xFE, 0xFE, 0xFD, 0xFD, 0xFC, 0xFC, 0xFB, 0xFB, 0xFA, 0xFA, 0xF9,
+ 0xF9, 0xF8, 0xF8, 0xF7, 0xF7, 0xF6, 0xF6, 0xF5, 0xF5, 0xF4, 0xF4, 0xF3,
+ 0xF3, 0xF2, 0xF2, 0xF1, 0xF1, 0xF0, 0xF0, 0xEF, 0xEF, 0xEF, 0xEF, 0xEE,
+ 0xEE, 0xEE, 0xEE, 0xED, 0xED, 0xED, 0xED, 0xEC, 0xEC, 0xEC, 0xEC, 0xEB,
+ 0xEB, 0xEB, 0xEB, 0xEA, 0xEA, 0xEA, 0xEA, 0xE9, 0xE9, 0xE9, 0xE9, 0xE8,
+ 0xE8, 0xE8, 0xE8, 0xE7, 0xE7, 0xE7, 0xE7, 0xE6, 0xE6, 0xE6, 0xE6, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE4, 0xE4, 0xE4, 0xE4, 0xE3, 0xE3, 0xE3, 0xE3, 0xE2,
+ 0xE2, 0xE2, 0xE2, 0xE1, 0xE1, 0xE1, 0xE1, 0xE0, 0xE0, 0xE0, 0xE0, 0xDF,
+ 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE,
+ 0xDE, 0xDE, 0xDE, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDC,
+ 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB,
+ 0xDB, 0xDB, 0xDB, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xD9,
+ 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8,
+ 0xD8, 0xD8, 0xD8, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD6,
+ 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5,
+ 0xD5, 0xD5, 0xD5, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD3,
+ 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD0,
+ 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF,
+ 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCE,
+ 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE,
+ 0xCE, 0xCE, 0xCE, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD,
+ 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
+ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCB,
+ 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB,
+ 0xCB, 0xCB, 0xCB, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA,
+ 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9,
+ 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC8,
+ 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8,
+ 0xC8, 0xC8, 0xC8, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7,
+ 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
+ 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC5,
+ 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5,
+ 0xC5, 0xC5, 0xC5, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4,
+ 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,
+ 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC2,
+ 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2,
+ 0xC2, 0xC2, 0xC2, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1,
+ 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,
+ 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xBF,
+ 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF,
+ 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF,
+ 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE,
+ 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE,
+ 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE,
+ 0xBE, 0xBE, 0xBE, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD,
+ 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD,
+ 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBC,
+ 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC,
+ 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC,
+ 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+ 0xBB, 0xBB, 0xBB, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA,
+ 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA,
+ 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xB9,
+ 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9,
+ 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9,
+ 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8,
+ 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8,
+ 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8,
+ 0xB8, 0xB8, 0xB8, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7,
+ 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7,
+ 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB6,
+ 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6,
+ 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6,
+ 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5,
+ 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5,
+ 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5,
+ 0xB5, 0xB5, 0xB5, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4,
+ 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4,
+ 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB3,
+ 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3,
+ 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3,
+ 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2,
+ 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2,
+ 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2,
+ 0xB2, 0xB2, 0xB2, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1,
+ 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1,
+ 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB0,
+ 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0,
+ 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0,
+ 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF,
+ 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF,
+ 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF,
+ 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF,
+ 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF,
+ 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAE,
+ 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE,
+ 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE,
+ 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE,
+ 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE,
+ 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE,
+ 0xAE, 0xAE, 0xAE, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD,
+ 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD,
+ 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD,
+ 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD,
+ 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD,
+ 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC,
+ 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC,
+ 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC,
+ 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC,
+ 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC,
+ 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAB,
+ 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB,
+ 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB,
+ 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB,
+ 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB,
+ 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB,
+ 0xAB, 0xAB, 0xAB, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9,
+ 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9,
+ 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9,
+ 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9,
+ 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9,
+ 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA8,
+ 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8,
+ 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8,
+ 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8,
+ 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8,
+ 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8,
+ 0xA8, 0xA8, 0xA8, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7,
+ 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7,
+ 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7,
+ 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7,
+ 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7,
+ 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6,
+ 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6,
+ 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6,
+ 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6,
+ 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6,
+ 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA5,
+ 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5,
+ 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5,
+ 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5,
+ 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5,
+ 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5,
+ 0xA5, 0xA5, 0xA5, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4,
+ 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4,
+ 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4,
+ 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4,
+ 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4,
+ 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
+ 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
+ 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
+ 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
+ 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
+ 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA2,
+ 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2,
+ 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2,
+ 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2,
+ 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2,
+ 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2,
+ 0xA2, 0xA2, 0xA2, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1,
+ 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1,
+ 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1,
+ 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1,
+ 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1,
+ 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
+ 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
+ 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
+ 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
+ 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
+ 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0x9F,
+ 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F,
+ 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F,
+ 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F,
+ 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F,
+ 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F,
+ 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F,
+ 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F,
+ 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F,
+ 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F,
+ 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F,
+ 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E,
+ 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E,
+ 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E,
+ 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E,
+ 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E,
+ 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E,
+ 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E,
+ 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E,
+ 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E,
+ 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E,
+ 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E,
+ 0x9E, 0x9E, 0x9E, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D,
+ 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D,
+ 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D,
+ 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D,
+ 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D,
+ 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D,
+ 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D,
+ 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D,
+ 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D,
+ 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D,
+ 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9C,
+ 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C,
+ 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C,
+ 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C,
+ 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C,
+ 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C,
+ 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C,
+ 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C,
+ 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C,
+ 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C,
+ 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C,
+ 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B,
+ 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B,
+ 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B,
+ 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B,
+ 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B,
+ 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B,
+ 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B,
+ 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B,
+ 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B,
+ 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B,
+ 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B,
+ 0x9B, 0x9B, 0x9B, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
+ 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
+ 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
+ 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
+ 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
+ 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
+ 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
+ 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
+ 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
+ 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
+ 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x99,
+ 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+ 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+ 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+ 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+ 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+ 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+ 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+ 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+ 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+ 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+ 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x98, 0x98, 0x98, 0x98, 0x98,
+ 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+ 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+ 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+ 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+ 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+ 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+ 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+ 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+ 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+ 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+ 0x98, 0x98, 0x98, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+ 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+ 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+ 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+ 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+ 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+ 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+ 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+ 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+ 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+ 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96,
+ 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+ 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+ 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+ 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+ 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+ 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+ 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+ 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+ 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+ 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+ 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x95, 0x95, 0x95, 0x95, 0x95,
+ 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+ 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+ 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+ 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+ 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+ 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+ 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+ 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+ 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+ 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+ 0x95, 0x95, 0x95, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+ 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+ 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+ 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+ 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+ 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+ 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+ 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+ 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+ 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+ 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x93,
+ 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+ 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+ 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+ 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+ 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+ 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+ 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+ 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+ 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+ 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+ 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x92, 0x92, 0x92, 0x92, 0x92,
+ 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+ 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+ 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+ 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+ 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+ 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+ 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+ 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+ 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+ 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+ 0x92, 0x92, 0x92, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+ 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+ 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+ 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+ 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+ 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+ 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+ 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+ 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+ 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+ 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
+ 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
+ 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
+ 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
+ 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
+ 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
+ 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
+ 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
+ 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
+ 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
+ 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
+ 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
+ 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
+ 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
+ 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
+ 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
+ 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
+ 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
+ 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
+ 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
+ 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
+ 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8E,
+ 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E,
+ 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E,
+ 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E,
+ 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E,
+ 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E,
+ 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E,
+ 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E,
+ 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E,
+ 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E,
+ 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E,
+ 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E,
+ 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E,
+ 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E,
+ 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E,
+ 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E,
+ 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E,
+ 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E,
+ 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E,
+ 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E,
+ 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E,
+ 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E,
+ 0x8E, 0x8E, 0x8E, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D,
+ 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D,
+ 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D,
+ 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D,
+ 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D,
+ 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D,
+ 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D,
+ 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D,
+ 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D,
+ 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D,
+ 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D,
+ 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D,
+ 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D,
+ 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D,
+ 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D,
+ 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D,
+ 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D,
+ 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D,
+ 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D,
+ 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D,
+ 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D,
+ 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C,
+ 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C,
+ 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C,
+ 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C,
+ 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C,
+ 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C,
+ 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C,
+ 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C,
+ 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C,
+ 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C,
+ 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C,
+ 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C,
+ 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C,
+ 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C,
+ 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C,
+ 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C,
+ 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C,
+ 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C,
+ 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C,
+ 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C,
+ 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C,
+ 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8B,
+ 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B,
+ 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B,
+ 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B,
+ 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B,
+ 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B,
+ 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B,
+ 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B,
+ 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B,
+ 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B,
+ 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B,
+ 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B,
+ 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B,
+ 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B,
+ 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B,
+ 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B,
+ 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B,
+ 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B,
+ 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B,
+ 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B,
+ 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B,
+ 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B,
+ 0x8B, 0x8B, 0x8B, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x89, 0x89, 0x89, 0x89, 0x89,
+ 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+ 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+ 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+ 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+ 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+ 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+ 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+ 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+ 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+ 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+ 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+ 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+ 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+ 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+ 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+ 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+ 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+ 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+ 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+ 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+ 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x88, 0x88, 0x88, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+ 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+ 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+ 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+ 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+ 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+ 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+ 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+ 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+ 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+ 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+ 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+ 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+ 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+ 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+ 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+ 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+ 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+ 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+ 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+ 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+ 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x86, 0x86, 0x86, 0x86, 0x86,
+ 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+ 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+ 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+ 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+ 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+ 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+ 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+ 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+ 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+ 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+ 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+ 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+ 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+ 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+ 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+ 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+ 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+ 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+ 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+ 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+ 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x85,
+ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0x85, 0x85, 0x85, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82,
+ 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00
+} ;
+
+
+/* Convert from ulaw to signd int8 to signed int32 or float */
+static int from_ulaw(void* in, void* out, int len, int bps, int format)
+{
+ register int i;
+ // Make sure the input parametrs are OK
+ if(format & (AF_FORMAT_SPECIAL_MASK | AF_FORMAT_US))
+ return AF_ERROR;
+
+ // Convert to int or to float
+ if((format & AF_FORMAT_POINT_MASK) == AF_FORMAT_I){
+ switch(bps){
+ case(1):
+ for(i=0;i<len;i++){
+ if(((int8_t*)in)[i] & 0x80)
+ ((int8_t*)out)[i] = (-1 * ulaw_decode[(((int8_t*)in)[i]) & 0x7F]) >> 8;
+ else
+ ((int8_t*)out)[i] = (ulaw_decode[(((int8_t*)in)[i]) & 0x7F]) >> 8;
+ }
+ break;
+ case(2):
+ for(i=0;i<len;i++){
+ if(((int8_t*)in)[i] & 0x80)
+ ((int16_t*)out)[i] = -1 * ulaw_decode[(((int8_t*)in)[i]) & 0x7F];
+ else
+ ((int16_t*)out)[i] = ulaw_decode[(((int8_t*)in)[i]) & 0x7F];
+ }
+ break;
+ case(4):
+ for(i=0;i<len;i++){
+ if(((int8_t*)in)[i] & 0x80)
+ ((int32_t*)out)[i] = (-1 * ulaw_decode[(((int8_t*)in)[i]) & 0x7F]) << 16;
+ else
+ ((int32_t*)out)[i] = (ulaw_decode[(((int8_t*)in)[i]) & 0x7F]) << 16;
+ }
+ break;
+ default:
+ return AF_ERROR;
+ }
+ }
+ else{
+ for(i=0;i<len;i++){
+ if(((int8_t*)in)[i] & 0x80)
+ ((float*)out)[i] = -1.0/32768.0 * (float)ulaw_decode[(((int8_t*)in)[i]) & 0x7F];
+ else
+ ((float*)out)[i] = +1.0/32768.0 * (float)ulaw_decode[(((int8_t*)in)[i]) & 0x7F];
+ }
+ }
+ return AF_OK;
+}
+
+/* Convert from signed int8 to signed int32 or float to ulaw */
+static int to_ulaw(void* in, void* out, int len, int bps, int format)
+{
+ register int i;
+ // Make sure the input parametrs are OK
+ if(format & (AF_FORMAT_SPECIAL_MASK | AF_FORMAT_US))
+ return AF_ERROR;
+
+ // Convert from int or to float
+ if((format & AF_FORMAT_POINT_MASK) == AF_FORMAT_I){
+ switch(bps){
+ case(1):
+ for(i=0;i<len;i++){
+ if(((int8_t*)in)[i] >= 0)
+ ((int8_t*)out)[i] = ulaw_encode[((int8_t*)in)[i] << 6];
+ else
+ ((int8_t*)out)[i] = 0x7F & ulaw_encode[-((int8_t*)in)[i] << 6];
+ }
+ break;
+ case(2):
+ for(i=0;i<len;i++){
+ if(((int16_t*)in)[i] >= 0)
+ ((int8_t*)out)[i] = ulaw_encode[((int16_t*)in)[i] / 4];
+ else
+ ((int8_t*)out)[i] = 0x7F & ulaw_encode[((int16_t*)in)[i] / -4];
+ }
+ break;
+ case(4):
+ for(i=0;i<len;i++){
+ if(((int32_t*)in)[i] >= 0)
+ ((int8_t*)out)[i] = ulaw_encode[((int32_t*)in)[i] >> (16 + 2)];
+ else
+ ((int8_t*)out)[i] = 0x7F & ulaw_encode[-((int32_t*)in)[i] >> (16 + 2)];
+ }
+ break;
+ default:
+ return AF_ERROR;
+ }
+ }
+ else{
+ for(i=0;i<len;i++){
+ if(((float*)in)[i] >= 0)
+ ((int8_t*)out)[i] = ulaw_encode[(int)(32767.0/4.0 * ((float*)in)[i])];
+ else
+ ((int8_t*)out)[i] = 0x7F & ulaw_encode[(int)(-32767.0/4.0 * ((float*)in)[i])];
+ }
+ }
+ return AF_OK;
+}
+
+#endif /* MPLAYER_AF_FORMAT_ULAW_H */
diff --git a/audio/filter/af_hrtf.c b/audio/filter/af_hrtf.c
new file mode 100644
index 0000000000..4f5eedb29d
--- /dev/null
+++ b/audio/filter/af_hrtf.c
@@ -0,0 +1,670 @@
+/*
+ * Experimental audio filter that mixes 5.1 and 5.1 with matrix
+ * encoded rear channels into headphone signal using FIR filtering
+ * with HRTF.
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+//#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include <math.h>
+#include <libavutil/common.h>
+
+#include "af.h"
+#include "dsp.h"
+
+/* HRTF filter coefficients and adjustable parameters */
+#include "af_hrtf.h"
+
+typedef struct af_hrtf_s {
+ /* Lengths */
+ int dlbuflen, hrflen, basslen;
+ /* L, C, R, Ls, Rs channels */
+ float *lf, *rf, *lr, *rr, *cf, *cr;
+ const float *cf_ir, *af_ir, *of_ir, *ar_ir, *or_ir, *cr_ir;
+ int cf_o, af_o, of_o, ar_o, or_o, cr_o;
+ /* Bass */
+ float *ba_l, *ba_r;
+ float *ba_ir;
+ /* Whether to matrix decode the rear center channel */
+ int matrix_mode;
+ /* How to decode the input:
+ 0 = 5/5+1 channels
+ 1 = 2 channels
+ 2 = matrix encoded 2 channels */
+ int decode_mode;
+ /* Full wave rectified (FWR) amplitudes and gain used to steer the
+ active matrix decoding of front channels (variable names
+ lpr/lmr means Lt + Rt, Lt - Rt) */
+ float l_fwr, r_fwr, lpr_fwr, lmr_fwr;
+ float adapt_l_gain, adapt_r_gain, adapt_lpr_gain, adapt_lmr_gain;
+ /* Matrix input decoding require special FWR buffer, since the
+ decoding is done in place. */
+ float *fwrbuf_l, *fwrbuf_r, *fwrbuf_lr, *fwrbuf_rr;
+ /* Rear channel delay buffer for matrix decoding */
+ float *rear_dlbuf;
+ /* Full wave rectified amplitude and gain used to steer the active
+ matrix decoding of center rear channel */
+ float lr_fwr, rr_fwr, lrprr_fwr, lrmrr_fwr;
+ float adapt_lr_gain, adapt_rr_gain;
+ float adapt_lrprr_gain, adapt_lrmrr_gain;
+ /* Cyclic position on the ring buffer */
+ int cyc_pos;
+ int print_flag;
+} af_hrtf_t;
+
+/* Convolution on a ring buffer
+ * nx: length of the ring buffer
+ * nk: length of the convolution kernel
+ * sx: ring buffer
+ * sk: convolution kernel
+ * offset: offset on the ring buffer, can be
+ */
+static float conv(const int nx, const int nk, const float *sx, const float *sk,
+ const int offset)
+{
+ /* k = reminder of offset / nx */
+ int k = offset >= 0 ? offset % nx : nx + (offset % nx);
+
+ if(nk + k <= nx)
+ return af_filter_fir(nk, sx + k, sk);
+ else
+ return af_filter_fir(nk + k - nx, sx, sk + nx - k) +
+ af_filter_fir(nx - k, sx + k, sk);
+}
+
+/* Detect when the impulse response starts (significantly) */
+static int pulse_detect(const float *sx)
+{
+ /* nmax must be the reference impulse response length (128) minus
+ s->hrflen */
+ const int nmax = 128 - HRTFFILTLEN;
+ const float thresh = IRTHRESH;
+ int i;
+
+ for(i = 0; i < nmax; i++)
+ if(fabs(sx[i]) > thresh)
+ return i;
+ return 0;
+}
+
+/* Fuzzy matrix coefficient transfer function to "lock" the matrix on
+ a effectively passive mode if the gain is approximately 1 */
+static inline float passive_lock(float x)
+{
+ const float x1 = x - 1;
+ const float ax1s = fabs(x - 1) * (1.0 / MATAGCLOCK);
+
+ return x1 - x1 / (1 + ax1s * ax1s) + 1;
+}
+
+/* Unified active matrix decoder for 2 channel matrix encoded surround
+ sources */
+static inline void matrix_decode(short *in, const int k, const int il,
+ const int ir, const int decode_rear,
+ const int dlbuflen,
+ float l_fwr, float r_fwr,
+ float lpr_fwr, float lmr_fwr,
+ float *adapt_l_gain, float *adapt_r_gain,
+ float *adapt_lpr_gain, float *adapt_lmr_gain,
+ float *lf, float *rf, float *lr,
+ float *rr, float *cf)
+{
+ const int kr = (k + MATREARDELAY) % dlbuflen;
+ float l_gain = (l_fwr + r_fwr) /
+ (1 + l_fwr + l_fwr);
+ float r_gain = (l_fwr + r_fwr) /
+ (1 + r_fwr + r_fwr);
+ /* The 2nd axis has strong gain fluctuations, and therefore require
+ limits. The factor corresponds to the 1 / amplification of (Lt
+ - Rt) when (Lt, Rt) is strongly correlated. (e.g. during
+ dialogues). It should be bigger than -12 dB to prevent
+ distortion. */
+ float lmr_lim_fwr = lmr_fwr > M9_03DB * lpr_fwr ?
+ lmr_fwr : M9_03DB * lpr_fwr;
+ float lpr_gain = (lpr_fwr + lmr_lim_fwr) /
+ (1 + lpr_fwr + lpr_fwr);
+ float lmr_gain = (lpr_fwr + lmr_lim_fwr) /
+ (1 + lmr_lim_fwr + lmr_lim_fwr);
+ float lmr_unlim_gain = (lpr_fwr + lmr_fwr) /
+ (1 + lmr_fwr + lmr_fwr);
+ float lpr, lmr;
+ float l_agc, r_agc, lpr_agc, lmr_agc;
+ float f, d_gain, c_gain, c_agc_cfk;
+
+#if 0
+ static int counter = 0;
+ static FILE *fp_out;
+
+ if(counter == 0)
+ fp_out = fopen("af_hrtf.log", "w");
+ if(counter % 240 == 0)
+ fprintf(fp_out, "%g %g %g %g %g ", counter * (1.0 / 48000),
+ l_gain, r_gain, lpr_gain, lmr_gain);
+#endif
+
+ /*** AXIS NO. 1: (Lt, Rt) -> (C, Ls, Rs) ***/
+ /* AGC adaption */
+ d_gain = (fabs(l_gain - *adapt_l_gain) +
+ fabs(r_gain - *adapt_r_gain)) * 0.5;
+ f = d_gain * (1.0 / MATAGCTRIG);
+ f = MATAGCDECAY - MATAGCDECAY / (1 + f * f);
+ *adapt_l_gain = (1 - f) * *adapt_l_gain + f * l_gain;
+ *adapt_r_gain = (1 - f) * *adapt_r_gain + f * r_gain;
+ /* Matrix */
+ l_agc = in[il] * passive_lock(*adapt_l_gain);
+ r_agc = in[ir] * passive_lock(*adapt_r_gain);
+ cf[k] = (l_agc + r_agc) * M_SQRT1_2;
+ if(decode_rear) {
+ lr[kr] = rr[kr] = (l_agc - r_agc) * M_SQRT1_2;
+ /* Stereo rear channel is steered with the same AGC steering as
+ the decoding matrix. Note this requires a fast updating AGC
+ at the order of 20 ms (which is the case here). */
+ lr[kr] *= (l_fwr + l_fwr) /
+ (1 + l_fwr + r_fwr);
+ rr[kr] *= (r_fwr + r_fwr) /
+ (1 + l_fwr + r_fwr);
+ }
+
+ /*** AXIS NO. 2: (Lt + Rt, Lt - Rt) -> (L, R) ***/
+ lpr = (in[il] + in[ir]) * M_SQRT1_2;
+ lmr = (in[il] - in[ir]) * M_SQRT1_2;
+ /* AGC adaption */
+ d_gain = fabs(lmr_unlim_gain - *adapt_lmr_gain);
+ f = d_gain * (1.0 / MATAGCTRIG);
+ f = MATAGCDECAY - MATAGCDECAY / (1 + f * f);
+ *adapt_lpr_gain = (1 - f) * *adapt_lpr_gain + f * lpr_gain;
+ *adapt_lmr_gain = (1 - f) * *adapt_lmr_gain + f * lmr_gain;
+ /* Matrix */
+ lpr_agc = lpr * passive_lock(*adapt_lpr_gain);
+ lmr_agc = lmr * passive_lock(*adapt_lmr_gain);
+ lf[k] = (lpr_agc + lmr_agc) * M_SQRT1_2;
+ rf[k] = (lpr_agc - lmr_agc) * M_SQRT1_2;
+
+ /*** CENTER FRONT CANCELLATION ***/
+ /* A heuristic approach exploits that Lt + Rt gain contains the
+ information about Lt, Rt correlation. This effectively reshapes
+ the front and rear "cones" to concentrate Lt + Rt to C and
+ introduce Lt - Rt in L, R. */
+ /* 0.67677 is the emprical lower bound for lpr_gain. */
+ c_gain = 8 * (*adapt_lpr_gain - 0.67677);
+ c_gain = c_gain > 0 ? c_gain : 0;
+ /* c_gain should not be too high, not even reaching full
+ cancellation (~ 0.50 - 0.55 at current AGC implementation), or
+ the center will s0und too narrow. */
+ c_gain = MATCOMPGAIN / (1 + c_gain * c_gain);
+ c_agc_cfk = c_gain * cf[k];
+ lf[k] -= c_agc_cfk;
+ rf[k] -= c_agc_cfk;
+ cf[k] += c_agc_cfk + c_agc_cfk;
+#if 0
+ if(counter % 240 == 0)
+ fprintf(fp_out, "%g %g %g %g %g\n",
+ *adapt_l_gain, *adapt_r_gain,
+ *adapt_lpr_gain, *adapt_lmr_gain,
+ c_gain);
+ counter++;
+#endif
+}
+
+static inline void update_ch(af_hrtf_t *s, short *in, const int k)
+{
+ const int fwr_pos = (k + FWRDURATION) % s->dlbuflen;
+ /* Update the full wave rectified total amplitude */
+ /* Input matrix decoder */
+ if(s->decode_mode == HRTF_MIX_MATRIX2CH) {
+ s->l_fwr += abs(in[0]) - fabs(s->fwrbuf_l[fwr_pos]);
+ s->r_fwr += abs(in[1]) - fabs(s->fwrbuf_r[fwr_pos]);
+ s->lpr_fwr += abs(in[0] + in[1]) -
+ fabs(s->fwrbuf_l[fwr_pos] + s->fwrbuf_r[fwr_pos]);
+ s->lmr_fwr += abs(in[0] - in[1]) -
+ fabs(s->fwrbuf_l[fwr_pos] - s->fwrbuf_r[fwr_pos]);
+ }
+ /* Rear matrix decoder */
+ if(s->matrix_mode) {
+ s->lr_fwr += abs(in[2]) - fabs(s->fwrbuf_lr[fwr_pos]);
+ s->rr_fwr += abs(in[3]) - fabs(s->fwrbuf_rr[fwr_pos]);
+ s->lrprr_fwr += abs(in[2] + in[3]) -
+ fabs(s->fwrbuf_lr[fwr_pos] + s->fwrbuf_rr[fwr_pos]);
+ s->lrmrr_fwr += abs(in[2] - in[3]) -
+ fabs(s->fwrbuf_lr[fwr_pos] - s->fwrbuf_rr[fwr_pos]);
+ }
+
+ switch (s->decode_mode) {
+ case HRTF_MIX_51:
+ /* 5/5+1 channel sources */
+ s->lf[k] = in[0];
+ s->cf[k] = in[4];
+ s->rf[k] = in[1];
+ s->fwrbuf_lr[k] = s->lr[k] = in[2];
+ s->fwrbuf_rr[k] = s->rr[k] = in[3];
+ break;
+ case HRTF_MIX_MATRIX2CH:
+ /* Matrix encoded 2 channel sources */
+ s->fwrbuf_l[k] = in[0];
+ s->fwrbuf_r[k] = in[1];
+ matrix_decode(in, k, 0, 1, 1, s->dlbuflen,
+ s->l_fwr, s->r_fwr,
+ s->lpr_fwr, s->lmr_fwr,
+ &(s->adapt_l_gain), &(s->adapt_r_gain),
+ &(s->adapt_lpr_gain), &(s->adapt_lmr_gain),
+ s->lf, s->rf, s->lr, s->rr, s->cf);
+ break;
+ case HRTF_MIX_STEREO:
+ /* Stereo sources */
+ s->lf[k] = in[0];
+ s->rf[k] = in[1];
+ s->cf[k] = s->lr[k] = s->rr[k] = 0;
+ break;
+ }
+
+ /* We need to update the bass compensation delay line, too. */
+ s->ba_l[k] = in[0] + in[4] + in[2];
+ s->ba_r[k] = in[4] + in[1] + in[3];
+}
+
+/* Initialization and runtime control */
+static int control(struct af_instance *af, int cmd, void* arg)
+{
+ af_hrtf_t *s = af->setup;
+ int test_output_res;
+ char mode;
+
+ switch(cmd) {
+ case AF_CONTROL_REINIT:
+ af->data->rate = ((struct mp_audio*)arg)->rate;
+ if(af->data->rate != 48000) {
+ // automatic samplerate adjustment in the filter chain
+ // is not yet supported.
+ mp_msg(MSGT_AFILTER, MSGL_ERR,
+ "[hrtf] ERROR: Sampling rate is not 48000 Hz (%d)!\n",
+ af->data->rate);
+ return AF_ERROR;
+ }
+ af->data->nch = ((struct mp_audio*)arg)->nch;
+ if(af->data->nch == 2) {
+ /* 2 channel input */
+ if(s->decode_mode != HRTF_MIX_MATRIX2CH) {
+ /* Default behavior is stereo mixing. */
+ s->decode_mode = HRTF_MIX_STEREO;
+ }
+ }
+ else if (af->data->nch < 5)
+ af->data->nch = 5;
+ af->data->format = AF_FORMAT_S16_NE;
+ af->data->bps = 2;
+ test_output_res = af_test_output(af, (struct mp_audio*)arg);
+ af->mul = 2.0 / af->data->nch;
+ // after testing input set the real output format
+ af->data->nch = 2;
+ s->print_flag = 1;
+ return test_output_res;
+ case AF_CONTROL_COMMAND_LINE:
+ sscanf((char*)arg, "%c", &mode);
+ switch(mode) {
+ case 'm':
+ /* Use matrix rear decoding. */
+ s->matrix_mode = 1;
+ break;
+ case 's':
+ /* Input needs matrix decoding. */
+ s->decode_mode = HRTF_MIX_MATRIX2CH;
+ break;
+ case '0':
+ s->matrix_mode = 0;
+ break;
+ default:
+ mp_msg(MSGT_AFILTER, MSGL_ERR,
+ "[hrtf] Mode is neither 'm', 's', nor '0' (%c).\n",
+ mode);
+ return AF_ERROR;
+ }
+ s->print_flag = 1;
+ return AF_OK;
+ }
+
+ return AF_UNKNOWN;
+}
+
+/* Deallocate memory */
+static void uninit(struct af_instance *af)
+{
+ if(af->setup) {
+ af_hrtf_t *s = af->setup;
+
+ free(s->lf);
+ free(s->rf);
+ free(s->lr);
+ free(s->rr);
+ free(s->cf);
+ free(s->cr);
+ free(s->ba_l);
+ free(s->ba_r);
+ free(s->ba_ir);
+ free(s->fwrbuf_l);
+ free(s->fwrbuf_r);
+ free(s->fwrbuf_lr);
+ free(s->fwrbuf_rr);
+ free(af->setup);
+ }
+ if(af->data)
+ free(af->data->audio);
+ free(af->data);
+}
+
+/* Filter data through filter
+
+Two "tricks" are used to compensate the "color" of the KEMAR data:
+
+1. The KEMAR data is refiltered to ensure that the front L, R channels
+on the same side of the ear are equalized (especially in the high
+frequencies).
+
+2. A bass compensation is introduced to ensure that 0-200 Hz are not
+damped (without any real 3D acoustical image, however).
+*/
+static struct mp_audio* play(struct af_instance *af, struct mp_audio *data)
+{
+ af_hrtf_t *s = af->setup;
+ short *in = data->audio; // Input audio data
+ short *out = NULL; // Output audio data
+ short *end = in + data->len / sizeof(short); // Loop end
+ float common, left, right, diff, left_b, right_b;
+ const int dblen = s->dlbuflen, hlen = s->hrflen, blen = s->basslen;
+
+ if(AF_OK != RESIZE_LOCAL_BUFFER(af, data))
+ return NULL;
+
+ if(s->print_flag) {
+ s->print_flag = 0;
+ switch (s->decode_mode) {
+ case HRTF_MIX_51:
+ mp_msg(MSGT_AFILTER, MSGL_INFO,
+ "[hrtf] Using HRTF to mix %s discrete surround into "
+ "L, R channels\n", s->matrix_mode ? "5+1" : "5");
+ break;
+ case HRTF_MIX_STEREO:
+ mp_msg(MSGT_AFILTER, MSGL_INFO,
+ "[hrtf] Using HRTF to mix stereo into "
+ "L, R channels\n");
+ break;
+ case HRTF_MIX_MATRIX2CH:
+ mp_msg(MSGT_AFILTER, MSGL_INFO,
+ "[hrtf] Using active matrix to decode 2 channel "
+ "input, HRTF to mix %s matrix surround into "
+ "L, R channels\n", "3/2");
+ break;
+ default:
+ mp_msg(MSGT_AFILTER, MSGL_WARN,
+ "[hrtf] bogus decode_mode: %d\n", s->decode_mode);
+ break;
+ }
+
+ if(s->matrix_mode)
+ mp_msg(MSGT_AFILTER, MSGL_INFO,
+ "[hrtf] Using active matrix to decode rear center "
+ "channel\n");
+ }
+
+ out = af->data->audio;
+
+ /* MPlayer's 5 channel layout (notation for the variable):
+ *
+ * 0: L (LF), 1: R (RF), 2: Ls (LR), 3: Rs (RR), 4: C (CF), matrix
+ * encoded: Cs (CR)
+ *
+ * or: L = left, C = center, R = right, F = front, R = rear
+ *
+ * Filter notation:
+ *
+ * CF
+ * OF AF
+ * Ear->
+ * OR AR
+ * CR
+ *
+ * or: C = center, A = same side, O = opposite, F = front, R = rear
+ */
+
+ while(in < end) {
+ const int k = s->cyc_pos;
+
+ update_ch(s, in, k);
+
+ /* Simulate a 7.5 ms -20 dB echo of the center channel in the
+ front channels (like reflection from a room wall) - a kind of
+ psycho-acoustically "cheating" to focus the center front
+ channel, which is normally hard to be perceived as front */
+ s->lf[k] += CFECHOAMPL * s->cf[(k + CFECHODELAY) % s->dlbuflen];
+ s->rf[k] += CFECHOAMPL * s->cf[(k + CFECHODELAY) % s->dlbuflen];
+
+ switch (s->decode_mode) {
+ case HRTF_MIX_51:
+ case HRTF_MIX_MATRIX2CH:
+ /* Mixer filter matrix */
+ common = conv(dblen, hlen, s->cf, s->cf_ir, k + s->cf_o);
+ if(s->matrix_mode) {
+ /* In matrix decoding mode, the rear channel gain must be
+ renormalized, as there is an additional channel. */
+ matrix_decode(in, k, 2, 3, 0, s->dlbuflen,
+ s->lr_fwr, s->rr_fwr,
+ s->lrprr_fwr, s->lrmrr_fwr,
+ &(s->adapt_lr_gain), &(s->adapt_rr_gain),
+ &(s->adapt_lrprr_gain), &(s->adapt_lrmrr_gain),
+ s->lr, s->rr, NULL, NULL, s->cr);
+ common +=
+ conv(dblen, hlen, s->cr, s->cr_ir, k + s->cr_o) *
+ M1_76DB;
+ left =
+ ( conv(dblen, hlen, s->lf, s->af_ir, k + s->af_o) +
+ conv(dblen, hlen, s->rf, s->of_ir, k + s->of_o) +
+ (conv(dblen, hlen, s->lr, s->ar_ir, k + s->ar_o) +
+ conv(dblen, hlen, s->rr, s->or_ir, k + s->or_o)) *
+ M1_76DB + common);
+ right =
+ ( conv(dblen, hlen, s->rf, s->af_ir, k + s->af_o) +
+ conv(dblen, hlen, s->lf, s->of_ir, k + s->of_o) +
+ (conv(dblen, hlen, s->rr, s->ar_ir, k + s->ar_o) +
+ conv(dblen, hlen, s->lr, s->or_ir, k + s->or_o)) *
+ M1_76DB + common);
+ } else {
+ left =
+ ( conv(dblen, hlen, s->lf, s->af_ir, k + s->af_o) +
+ conv(dblen, hlen, s->rf, s->of_ir, k + s->of_o) +
+ conv(dblen, hlen, s->lr, s->ar_ir, k + s->ar_o) +
+ conv(dblen, hlen, s->rr, s->or_ir, k + s->or_o) +
+ common);
+ right =
+ ( conv(dblen, hlen, s->rf, s->af_ir, k + s->af_o) +
+ conv(dblen, hlen, s->lf, s->of_ir, k + s->of_o) +
+ conv(dblen, hlen, s->rr, s->ar_ir, k + s->ar_o) +
+ conv(dblen, hlen, s->lr, s->or_ir, k + s->or_o) +
+ common);
+ }
+ break;
+ case HRTF_MIX_STEREO:
+ left =
+ ( conv(dblen, hlen, s->lf, s->af_ir, k + s->af_o) +
+ conv(dblen, hlen, s->rf, s->of_ir, k + s->of_o));
+ right =
+ ( conv(dblen, hlen, s->rf, s->af_ir, k + s->af_o) +
+ conv(dblen, hlen, s->lf, s->of_ir, k + s->of_o));
+ break;
+ default:
+ /* make gcc happy */
+ left = 0.0;
+ right = 0.0;
+ break;
+ }
+
+ /* Bass compensation for the lower frequency cut of the HRTF. A
+ cross talk of the left and right channel is introduced to
+ match the directional characteristics of higher frequencies.
+ The bass will not have any real 3D perception, but that is
+ OK (note at 180 Hz, the wavelength is about 2 m, and any
+ spatial perception is impossible). */
+ left_b = conv(dblen, blen, s->ba_l, s->ba_ir, k);
+ right_b = conv(dblen, blen, s->ba_r, s->ba_ir, k);
+ left += (1 - BASSCROSS) * left_b + BASSCROSS * right_b;
+ right += (1 - BASSCROSS) * right_b + BASSCROSS * left_b;
+ /* Also mix the LFE channel (if available) */
+ if(data->nch >= 6) {
+ left += in[5] * M3_01DB;
+ right += in[5] * M3_01DB;
+ }
+
+ /* Amplitude renormalization. */
+ left *= AMPLNORM;
+ right *= AMPLNORM;
+
+ switch (s->decode_mode) {
+ case HRTF_MIX_51:
+ case HRTF_MIX_STEREO:
+ /* "Cheating": linear stereo expansion to amplify the 3D
+ perception. Note: Too much will destroy the acoustic space
+ and may even result in headaches. */
+ diff = STEXPAND2 * (left - right);
+ out[0] = av_clip_int16(left + diff);
+ out[1] = av_clip_int16(right - diff);
+ break;
+ case HRTF_MIX_MATRIX2CH:
+ /* Do attempt any stereo expansion with matrix encoded
+ sources. The L, R channels are already stereo expanded
+ by the steering, any further stereo expansion will sound
+ very unnatural. */
+ out[0] = av_clip_int16(left);
+ out[1] = av_clip_int16(right);
+ break;
+ }
+
+ /* Next sample... */
+ in = &in[data->nch];
+ out = &out[af->data->nch];
+ (s->cyc_pos)--;
+ if(s->cyc_pos < 0)
+ s->cyc_pos += dblen;
+ }
+
+ /* Set output data */
+ data->audio = af->data->audio;
+ data->len = data->len / data->nch * 2;
+ data->nch = 2;
+
+ return data;
+}
+
+static int allocate(af_hrtf_t *s)
+{
+ if ((s->lf = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
+ if ((s->rf = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
+ if ((s->lr = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
+ if ((s->rr = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
+ if ((s->cf = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
+ if ((s->cr = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
+ if ((s->ba_l = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
+ if ((s->ba_r = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
+ if ((s->fwrbuf_l =
+ malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
+ if ((s->fwrbuf_r =
+ malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
+ if ((s->fwrbuf_lr =
+ malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
+ if ((s->fwrbuf_rr =
+ malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
+ return 0;
+}
+
+/* Allocate memory and set function pointers */
+static int af_open(struct af_instance* af)
+{
+ int i;
+ af_hrtf_t *s;
+ float fc;
+
+ af->control = control;
+ af->uninit = uninit;
+ af->play = play;
+ af->mul = 1;
+ af->data = calloc(1, sizeof(struct mp_audio));
+ af->setup = calloc(1, sizeof(af_hrtf_t));
+ if((af->data == NULL) || (af->setup == NULL))
+ return AF_ERROR;
+
+ s = af->setup;
+
+ s->dlbuflen = DELAYBUFLEN;
+ s->hrflen = HRTFFILTLEN;
+ s->basslen = BASSFILTLEN;
+
+ s->cyc_pos = s->dlbuflen - 1;
+ /* With a full (two axis) steering matrix decoder, s->matrix_mode
+ should not be enabled lightly (it will also steer the Ls, Rs
+ channels). */
+ s->matrix_mode = 0;
+ s->decode_mode = HRTF_MIX_51;
+
+ s->print_flag = 1;
+
+ if (allocate(s) != 0) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[hrtf] Memory allocation error.\n");
+ return AF_ERROR;
+ }
+
+ for(i = 0; i < s->dlbuflen; i++)
+ s->lf[i] = s->rf[i] = s->lr[i] = s->rr[i] = s->cf[i] =
+ s->cr[i] = 0;
+
+ s->lr_fwr =
+ s->rr_fwr = 0;
+
+ s->cf_ir = cf_filt + (s->cf_o = pulse_detect(cf_filt));
+ s->af_ir = af_filt + (s->af_o = pulse_detect(af_filt));
+ s->of_ir = of_filt + (s->of_o = pulse_detect(of_filt));
+ s->ar_ir = ar_filt + (s->ar_o = pulse_detect(ar_filt));
+ s->or_ir = or_filt + (s->or_o = pulse_detect(or_filt));
+ s->cr_ir = cr_filt + (s->cr_o = pulse_detect(cr_filt));
+
+ if((s->ba_ir = malloc(s->basslen * sizeof(float))) == NULL) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[hrtf] Memory allocation error.\n");
+ return AF_ERROR;
+ }
+ fc = 2.0 * BASSFILTFREQ / (float)af->data->rate;
+ if(af_filter_design_fir(s->basslen, s->ba_ir, &fc, LP | KAISER, 4 * M_PI) ==
+ -1) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[hrtf] Unable to design low-pass "
+ "filter.\n");
+ return AF_ERROR;
+ }
+ for(i = 0; i < s->basslen; i++)
+ s->ba_ir[i] *= BASSGAIN;
+
+ return AF_OK;
+}
+
+/* Description of this filter */
+struct af_info af_info_hrtf = {
+ "HRTF Headphone",
+ "hrtf",
+ "ylai",
+ "",
+ AF_FLAGS_REENTRANT,
+ af_open
+};
diff --git a/audio/filter/af_hrtf.h b/audio/filter/af_hrtf.h
new file mode 100644
index 0000000000..887310b57d
--- /dev/null
+++ b/audio/filter/af_hrtf.h
@@ -0,0 +1,511 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPLAYER_AF_HRTF_H
+#define MPLAYER_AF_HRTF_H
+
+#define HRTF_MIX_51 0
+#define HRTF_MIX_STEREO 1
+#define HRTF_MIX_MATRIX2CH 2
+
+/* Amplitude scaling factors */
+#define M17_0DB 0.1414213562
+#define M9_03DB 0.3535533906
+#define M6_99DB 0.4472135955
+#define M4_77DB 0.5773502692
+#define M3_01DB 0.7071067812
+#define M1_76DB 0.8164965809
+
+#define DELAYBUFLEN 1024 /* Length of the delay buffer */
+#define HRTFFILTLEN 64 /* HRTF filter length */
+#define IRTHRESH 0.001 /* Impulse response pruning thresh. */
+
+#define AMPLNORM M6_99DB /* Overall amplitude renormalization */
+
+#define BASSFILTFREQ 180 /* Bass compensation filter cut (Hz) */
+#define BASSFILTLEN 193 /* Bass compensation filter length */
+#define BASSGAIN M_SQRT2 /* Bass compensation gain */
+#define BASSCROSS 0.35 /* Bass cross talk */
+
+#define FWRDURATION 240 /* FWR average duration (samples) */
+#define MATREARDELAY 720 /* Matrix mode rear delay (samples) */
+
+#define MATAGCTRIG 8.0 /* (Fuzzy) AGC trigger */
+#define MATAGCDECAY 1.0 /* AGC baseline decay rate (1/samp.) */
+#define MATAGCLOCK 0.2 /* AGC range (around 1) where the
+ matrix behaves passively */
+#define MATCOMPGAIN 0.37 /* Cross talk compensation gain,
+ 0.50 - 0.55 is full cancellation. */
+
+#define CFECHODELAY 360 /* Center front echo delay (samples) */
+#define CFECHOAMPL M17_0DB /* Center front echo amplitude */
+
+#define STEXPAND2 0.07 /* Stereo expansion / 2 */
+
+/* Head related impulse response (HRIR) derived from KEMAR measurement
+ data by Bill Gardner <billg@media.mit.edu> and Keith Martin
+ <kdm@media.mit.edu>
+
+ URL: http://sound.media.mit.edu/KEMAR.html
+
+ Distributed under GPL with authors' permission
+*/
+
+/* EQUALIZED KEMAR HRIR
+
+How to generate these data:
+
+1. You need the MIT Media Lab's KEMAR data, read it into an software
+ capable of signal/time series analysis (like Mathematica, Matlab,
+ ...)
+
+2. Construct an equalizing FIR inverse filter by calculating the
+ transfer function of the front, same side impulse response, then
+ take 1 over the absolute magnitude.
+
+3. Cut the poles in the inverse filter's transfer function
+ specification by limiting the amplification to 2.5 (note, this
+ number assumes that you have correct signal processing
+ normalization of the Fourier transform).
+
+4. Design the FIR inverse filter by calculating the inverse Fourier
+ transform, then chopping the coefficients down to a reasonable
+ number (N = 15 is used here), apply the Kaiser-Bessel window (alpha
+ = 2 is used here). Note the objective is remove the color bias
+ only (as if you are using an equalizer), _not_ to do a full inverse
+ filtering. (Note: beta = pi*alpha in other notation.)
+
+ For N = 15, alpha = 2, you should get the following impulse
+ response:
+
+ 0.001001558668605168, 0.00698457265741865, 0.040453643039829436,
+ 0.012230541722147855, -0.11939760844854072, 0.16468099899755967,
+ -0.30297563073747436, 1.3140211791355982, -0.30297563073747436,
+ 0.16468099899755967, -0.11939760844854072, 0.012230541722147855,
+ 0.040453643039829436, 0.00698457265741865, 0.001001558668605168
+
+5. Linearly convolve all KEMAR HRIR with this inverse filter.
+
+6. Resample from 44.1 kHz sampling frequency to 48 kHz.
+*/
+
+/* Center front (-5 degree) - not 0 degree in order to create a clear
+ front image from a finite distance */
+static const float cf_filt[128] = {
+ -0.00008638082319075036, 0.0003198059946385229,
+ -0.0005010631339162132, 0.0011424741331126876,
+ -0.001584220794688753, 0.001742715363246275,
+ -0.0011080796626780694, 0.0001651829990860167,
+ 0.005235028337314985, 0.0035223828473357776,
+ 0.010057681388431303, -0.033469432129545514,
+ 0.013391253316233523, 0.004858462839827063,
+ 0.08172161220103627, 0.26158596134500023,
+ -0.12420314583323326, -0.14298458356097565,
+ 0.14421897280453896, -0.1635792507629016,
+ -0.02187136722480014, 0.2426863044711817,
+ 0.07229814207917194, 0.0942742651913879,
+ 0.29856830878076834, 0.2944146162057754,
+ -0.12122157003421209, -0.19640092165631157,
+ 0.11623836502034968, -0.05794027397995521,
+ -0.34313138341973776, -0.19487516249168105,
+ 0.010118993953802401, -0.09460218797710966,
+ -0.16761521117359582, 0.004154461610153861,
+ 0.052768641758969316, -0.00041823982226147407,
+ 0.021634960445143514, 0.07562793486871108,
+ 0.08895407129506479, 0.039857755093416214,
+ 0.044257936180422945, 0.061557584906101664,
+ 0.015547268541895703, -0.023908191934932484,
+ 0.009498030443468223, 0.03816269003221337,
+ -0.009820500607303615, -0.042003975527908084,
+ -0.03335447117311547, -0.029294510859746596,
+ -0.05212623136198511, -0.073427547153205,
+ -0.061190797824958836, -0.04620925059966413,
+ -0.04204619420702159, -0.02331915902615157,
+ 0.00211481411477094, 0.00852563995740107,
+ 0.008766809731743399, 0.008666632180812078,
+ 0.018279202191625352, 0.02924332751289675,
+ 0.022293148257836494, 0.012362146008584188,
+ 0.008572582458807008, 0.006491370763597344,
+ -0.0019366944997535774, -0.006318669309634434,
+ -0.006457921690218669, -0.015050265524669974,
+ -0.02110660282616213, -0.017027809096377904,
+ -0.01651052305334348, -0.022770064150046673,
+ -0.01999875754219472, -0.012294792027337775,
+ -0.011506057031057188, -0.011448970577312903,
+ -0.004823572302580925, 0.0022451134042777883,
+ 0.004145473526859826, 0.005629030064546135,
+ 0.008588029213398785, 0.010092048834844231,
+ 0.007182013245552008, 0.0014600979508720656,
+ -0.0038314646272511756, -0.003443901997881347,
+ -0.0029483418254804047, -0.007609357112679647,
+ -0.006518368948030822, -0.004495803701497202,
+ -0.007109113004849672, -0.008346237278084265,
+ -0.005560847336252453, -0.002993453167553188,
+ -0.005122897816824269, -0.004389782626604215,
+ -0.0010912633695218108, -0.0019712029474458835,
+ -0.005870162265802235, -0.005626159534954128,
+ -0.00027254977910844407, 0.0013794425431633785,
+ -0.0005919083190430062, -0.0007861203545416682,
+ -0.0007049560240893946, -0.0032720188494468868,
+ -0.004460645567968504, -0.0032018528193571696,
+ -0.0030579229375062105, -0.003593998902656612,
+ -0.0038032977997776445, -0.004613776010454773,
+ -0.0059796549143736845, -0.00420126194319768,
+ -0.0012374419948287222, 0.0008572699213050608,
+ 0.0021490971020081094, 0.00047295283198381995,
+ -0.0009670277915884887, -0.001354440866080231,
+ -0.002962902746547851, -0.00533935813338141,
+ -0.005469203016468759, -0.004355784273189485
+};
+/* Front, same side (30 degree) */
+static const float af_filt[128] = {
+ -0.004140580614755493, 0.005790934614385445,
+ 0.003318916682081112, 0.014257145544366063,
+ 0.007328442487127339, -0.06550381777876194,
+ 0.03502225818161845, -0.013090579770708259,
+ 0.2517776798694195, 0.420770489950659,
+ -0.3418854608834852, -0.24371032493696737,
+ 0.04901356150030018, -0.1778083521632833,
+ 0.26448004245714163, 0.23245199964546834,
+ 0.033053145803936305, 0.46811222821062415,
+ 0.5359265986255611, -0.011912195468533787,
+ -0.39763432601411647, -0.034482864386898314,
+ 0.029445398240649626, -0.3850940407863262,
+ -0.3272328478175581, -0.14701421403616477,
+ -0.08522137400169517, -0.14936851633336035,
+ -0.09432605283433723, 0.0991200405937827,
+ 0.011075012089917331, -0.0051036489980274685,
+ 0.0933903289749412, 0.1344189369609565,
+ 0.10507466913017807, 0.04240159324684365,
+ 0.06559270110638656, 0.026984119875617524,
+ -0.03359846103238096, -0.018000197099174275,
+ 0.042031818548178244, 0.03849039666888434,
+ -0.02450829674011345, -0.03407882403088576,
+ -0.029230189282961977, -0.046964865291761734,
+ -0.09458258700116245, -0.1527349330901158,
+ -0.15411577687826097, -0.08761679790956928,
+ -0.033623549089171874, -0.007204768531481949,
+ 0.008273425020444852, 0.021368717994908505,
+ 0.04366608267875025, 0.05660907333076205,
+ 0.06775726495503939, 0.05621881735271431,
+ 0.03576231950669927, 0.02500825834889175,
+ 0.015423811076054601, 0.007903258334503761,
+ -0.0053873014137761945, -0.006987955469434698,
+ -0.012027972007598602, -0.025228281243816594,
+ -0.026225091797257318, -0.023809293997344882,
+ -0.03250172017712295, -0.03195696301067249,
+ -0.01784813952189948, -0.01663267233760342,
+ -0.016184530450468065, -0.011659883749357463,
+ -0.0035378511240219163, -0.0005485800790443406,
+ 0.0018432660108168625, 0.011634844139907534,
+ 0.018333603402051105, 0.020447379185133056,
+ 0.00850783664147828, 0.0004694148911037838,
+ -0.0017047130409786676, -0.0022409152834483997,
+ -0.000860472174892845, -0.004111075059198666,
+ -0.003527843382056666, -0.009640160874903018,
+ -0.01750044574231376, -0.015613389403672443,
+ -0.010790028120953001, -0.0095313499955768,
+ -0.007469721416726809, -0.0019186578145117315,
+ -0.00014977322572890802, -0.0029803838028179728,
+ -0.006520567233727221, 0.000035015132033882596,
+ 0.009245098100543752, 0.009896930052308656,
+ 0.008316744929565786, 0.004575207140193997,
+ -0.0000647420103997081, -0.004502916832871627,
+ -0.004225962213251224, -0.002886014126381486,
+ -0.006416834142585976, -0.007156609995423569,
+ -0.008840274447579472, -0.01441763751386817,
+ -0.015435817484659574, -0.00924487254924743,
+ -0.0021571721940235205, 0.0028540722992305453,
+ 0.00273577475088536, -0.000788412365513805,
+ -0.0032650029728365907, -0.003880217646231338,
+ -0.0035302087299613778, -0.0038531436176586246,
+ -0.0011921632190514074, -0.0020722967099011938,
+ -0.004985351145629344, -0.0042375588844648735,
+ -0.003030360463006021, -0.0014161075428041471,
+ -0.0005083025643192044, 0.00035096963769606926
+};
+/* Front, opposite (-30 degree) */
+static const float of_filt[128] = {
+ -0.000013472538374193126, -0.00008048061877079751,
+ 0.000043927265781258155, -0.000017931700794858892,
+ -0.000034774602476112886, -0.00009576223008735474,
+ 0.0001557797638630691, -0.00018742885883751094,
+ 0.00026512448626705716, -0.0001451040203319678,
+ -0.00008263233117758043, 0.0006486245853639179,
+ -0.0010631408451846698, 0.0026571994100746143,
+ 0.0014179177997092787, 0.0062326502956616256,
+ -0.008194149324545333, -0.006568029415878379,
+ 0.009538759710818582, 0.012309193558632693,
+ 0.12336638055838955, 0.046164307101829005,
+ -0.10228706407884815, 0.04047687260345798,
+ -0.00296595313977046, -0.07057949208414134,
+ 0.08172114840714612, 0.08736490764127891,
+ 0.05105250431333021, 0.11627179512747428,
+ 0.20717888490340705, 0.09375052213570291,
+ -0.09784374168330194, -0.010493571845901443,
+ 0.053131894303891716, -0.10157443971694806,
+ -0.16264032634244974, -0.05402369511361273,
+ -0.0274403608654217, -0.09860277022495063,
+ -0.06841875821090282, -0.004434574400066223,
+ -0.0005222661652743502, -0.006231881259827263,
+ 0.014410397820340159, 0.04885649512730243,
+ 0.04361962569042684, 0.03399214029009391,
+ 0.04961073933475931, 0.04067325604132289,
+ 0.007850647519227257, 0.004564440466905299,
+ 0.02257107958021618, 0.008183791928884486,
+ -0.014913479343180557, -0.018685938460856224,
+ -0.01745737397226911, -0.02327177054233603,
+ -0.03723048632685227, -0.044739390162299685,
+ -0.042651220125613766, -0.03730017561004743,
+ -0.029039465434276192, -0.01885087458914294,
+ -0.01207127752277769, -0.006779800724164512,
+ -0.001930416967444157, 0.000029454577995528385,
+ 0.0013822760965755472, 0.0014799128583230202,
+ 0.0002068200609199832, 0.0022254295286201083,
+ 0.005143858159434566, 0.0018580542060917013,
+ -0.0019426046325146259, -0.0014464042108543495,
+ -0.0034430083560735582, -0.009692758426099499,
+ -0.011840035292593485, -0.010716508855893968,
+ -0.012939889036853034, -0.0121846427935653,
+ -0.006198503315630782, -0.0023186723099380305,
+ -0.002679872498314837, -0.003086020446226295,
+ -0.0015709623347698936, -0.0008147490468332398,
+ -0.0012384575726770983, -0.0005212877089109362,
+ 0.0017707578744906142, 0.001324932723905786,
+ -0.0017023653780617696, -0.0045108927752919425,
+ -0.005422155613096912, -0.0039489323837623835,
+ -0.005295995750506547, -0.00629706566356189,
+ -0.004685732198036754, -0.0048076735568143,
+ -0.005978864279217503, -0.005928999306332966,
+ -0.004187703549017582, -0.003213999896976475,
+ -0.0028068699816073414, -0.0010889703907593833,
+ 0.0003276714243495386, -0.0013015007040186994,
+ -0.003208050402434782, -0.0025115319088208545,
+ -0.0013787553006401076, -0.0018279087370218635,
+ -0.0025904836507747754, -0.002071221947222004,
+ -0.0026424212922485594, -0.0039837031817577,
+ -0.0041635566057380965, -0.004355223489150822,
+ -0.004350395332709937, -0.0036693292471930263,
+ -0.003386384394185026, -0.003972568655001128,
+ -0.004332336840023821, -0.002648767912111827,
+ -0.001384410080218114, -0.0011353792711849466,
+ -0.0013726264946164232, -0.0020075119315034313
+};
+/* Rear, same side (135 degree) */
+static const float ar_filt[128] = {
+ 0.004573315040810066, 0.0013592578059426913,
+ 0.01553271930902704, -0.0002356117224941317,
+ -0.05746098219774702, 0.03430688963370445,
+ 0.00808371687447385, 0.21893535841158596,
+ 0.2984357591724814, -0.3302799746504719,
+ -0.3194029149806245, 0.21633225051331056,
+ 0.24371260938097083, -0.08843705549751085,
+ 0.03939684701343366, 0.45386926431114494,
+ 0.07599118140753386, -0.18114706160474578,
+ 0.285640624686038, 0.4049515236666218,
+ -0.05347890222071792, -0.31464359045319074,
+ -0.1033502246468194, -0.04553593949283157,
+ -0.1880747731157464, -0.13629090230626037,
+ -0.10435789106123239, -0.19818232801888755,
+ -0.16701805476330397, -0.022793111199284,
+ 0.058049696762683685, 0.007048321372693906,
+ -0.002966419183225961, 0.10140569697797763,
+ 0.11648999956673124, 0.05218347182779882,
+ 0.028427001212735392, 0.04151900310166159,
+ -0.0006960604221423734, -0.05898623212226975,
+ -0.03801934531173312, -0.029306970535287986,
+ -0.04549125782835908, -0.0599222718506552,
+ -0.058299618975430116, -0.03765579129720727,
+ -0.03559302657499581, -0.020647901025903054,
+ -0.005720957338744348, -0.0041915732688915545,
+ -0.0011470880098346143, 0.008737404798553,
+ 0.023444168098121512, 0.024204226042172663,
+ 0.01894897166475026, 0.020807655257479588,
+ 0.021570431128040954, 0.006800556178576289,
+ -0.009000089216921362, -0.010969824547067934,
+ -0.0033653428332822374, -0.012676936164668659,
+ -0.026739938673413587, -0.023427869194287573,
+ -0.023302007105117244, -0.023647155590533712,
+ -0.021289317515613106, -0.009120487305069884,
+ 0.0009251551667728967, 0.00004285344125653763,
+ -0.00009042365479456271, 0.00022573242339446494,
+ 0.00720168491586098, 0.007111875505402431,
+ 0.003186514817683482, 0.00810087718334745,
+ 0.012619557025922575, 0.007854726400013397,
+ -0.0024013592881066267, -0.001452457473161119,
+ -0.0025535188366093945, -0.012428911627809337,
+ -0.013729251536694145, -0.0070099675146427344,
+ -0.007165284278706593, -0.01639289295622301,
+ -0.015831795079778305, -0.007305768485523729,
+ -0.003608863157004021, -0.0032640528878698084,
+ 0.0030901263998481944, 0.00749497566124848,
+ 0.002515185532327241, 0.00004840875738621367,
+ 0.0017596043486043966, 0.0046229941553338144,
+ 0.0034259167322926096, 0.003707347634186093,
+ 0.0035584806528586328, -0.0019078936035275198,
+ -0.006057343815214898, -0.0069262470468817,
+ -0.004345020728618624, -0.004177623355574794,
+ -0.005373506556122508, -0.006624933928893836,
+ -0.008679541408588839, -0.010718719681595322,
+ -0.011392246979594496, -0.007893917064389902,
+ -0.0027572935365832536, -0.00006064707149834412,
+ -0.0012512537319656323, -0.0024501501002409786,
+ -0.0022106788572895998, -0.00234124933370301,
+ -0.0008953445167066823, 0.0005393670625637734,
+ -0.00033175600142209297, -0.004023994309351289,
+ -0.008655472335784443, -0.009899957354849682,
+ -0.008664952919996412, -0.00553483124503576,
+ -0.003735336089277662, -0.002754824348643885,
+ -0.0026884314856593368, -0.004084181815125924
+};
+/* Rear, opposite (-135 degree) */
+static const float or_filt[128] = {
+ 0.0001220944028243897, -0.000021785381808441314,
+ 5.823057988603169e-6, -0.00001217768176447613,
+ -0.00006123604397345513, 5.574117262531134e-6,
+ -0.00004935331914366778, 1.1771577934768211e-6,
+ -0.000059236211621095756, 9.503536190497286e-6,
+ -0.0001494445696103564, 0.00012248858284145305,
+ -0.0000963975321456313, 6.017905197665205e-6,
+ 0.00003353395360402643, -0.0001931511015359506,
+ 0.0005113536523931485, -0.0005676652619386114,
+ 0.0012057159755477467, 0.0009370492250339692,
+ 0.004596472288877981, -0.0018831773384237068,
+ -0.008208535225621212, 0.0038178646400751056,
+ 0.008726517739105965, 0.06664363898418262,
+ 0.06788684221502142, -0.04492315162807267,
+ -0.04019906311255255, 0.026203059677375153,
+ 0.013678129114847544, -0.014334962223993527,
+ 0.010141709596167392, 0.11559131576945537,
+ 0.1586402064538425, 0.059975334707967023,
+ 0.004671725963777715, 0.031498678282775874,
+ 0.014338626006524587, -0.014749719448472231,
+ -0.02055508237941379, -0.05407690143992048,
+ -0.07767559836886143, -0.05029091786216801,
+ -0.030808335706574427, -0.03401958135442541,
+ -0.030520368430288967, -0.014168302104259355,
+ 0.011907621259989802, 0.014286081013069,
+ 0.006377467879613449, 0.018546823568277478,
+ 0.028297012771618273, 0.025222339408338186,
+ 0.021931611353415138, 0.019708894333646355,
+ 0.01729258494072014, 0.017468204169564034,
+ 0.009729094845051928, -0.002976992018531901,
+ -0.00956986166277019, -0.016125733548332074,
+ -0.02934094241442545, -0.04133767871051455,
+ -0.043536981145416466, -0.0385966307108608,
+ -0.02784453599342459, -0.018995135307247116,
+ -0.012849534096536747, -0.004437491064613308,
+ 0.00028385411598204655, 0.003776874988516643,
+ 0.008069432041547833, 0.008764754183751848,
+ 0.008020908861878062, 0.006830351461360802,
+ 0.002218330884267235, -0.0020478725582339444,
+ -0.003997428121462543, -0.007066287373515421,
+ -0.00940847412544698, -0.010938998446237963,
+ -0.011775483016151306, -0.011391103919484287,
+ -0.010586061195163017, -0.009842793078929053,
+ -0.007753202010139829, -0.00569213732353025,
+ -0.006506783349722073, -0.005346134281903736,
+ -0.003913089814898934, -0.0036091443854759727,
+ -0.0020328564301266287, 0.00017932870773467683,
+ 0.0032779786679056357, 0.003969695813293966,
+ 0.0020339334412434987, -0.00011345940675415259,
+ -0.0018344103399567666, -0.003556764701666365,
+ -0.004263523639408391, -0.002940568582022133,
+ -0.0034341188272627556, -0.006023399920020824,
+ -0.0077456903203677865, -0.007912219312377842,
+ -0.00625202770436523, -0.00530785086116117,
+ -0.005569722659634311, -0.004664448462594344,
+ -0.0037747773914077747, -0.004175649656985592,
+ -0.004659601521384289, -0.005008602967819641,
+ -0.004730625079902729, -0.0034039554356604146,
+ -0.0017110333873406587, -0.0006091938771510242,
+ -0.0016051679050678297, -0.003312864664007262,
+ -0.004505512715977288, -0.004152222189861692,
+ -0.003218596419678823, -0.0027277806209877343,
+ -0.001715005444317267, -0.0012589960071233749,
+ -0.001852908777923165, -0.002540339553144362
+};
+/* Center rear (180 degree) */
+static const float cr_filt[128] = {
+ -0.00005989110716536726, -0.00022790291829128702,
+ 0.0002659166098971966, -0.0003774772716776257,
+ 0.0004540309551867803, -0.000420238187386368,
+ 0.00025518536450885686, 0.00028285526288953955,
+ -0.001016391007574093, 0.0028634984299063795,
+ 0.0021574799687976045, 0.01035121276682072,
+ -0.010481720917298163, -0.013197198495899292,
+ 0.0031928225328717195, 0.02903137843618603,
+ 0.1632429772511569, 0.1047487989875262,
+ -0.10464685060623742, -0.09260196288035998,
+ -0.007514241993554443, 0.013596249226741712,
+ -0.019876166508450258, 0.1255626123599804,
+ 0.3648170359521724, 0.19458249753223478,
+ -0.04434070930031298, 0.046582528121935265,
+ 0.09484427347230277, -0.03137795311969644,
+ -0.10297437925363695, -0.09351091015917065,
+ -0.1129521092162064, -0.14925322995658827,
+ -0.1231466295584665, -0.06356719756705227,
+ -0.05442277895126282, -0.07568433015661316,
+ -0.023314932828602003, 0.04260950721318558,
+ 0.02249026315598923, 0.02048195669571197,
+ 0.05651342117268278, 0.05885038917623213,
+ 0.03797102097397795, 0.011767394419953451,
+ 0.00560502503429481, 0.005051125343961189,
+ -0.012925933188033823, -0.023918884651306566,
+ -0.013251659441678816, -0.010694772488866284,
+ -0.03080486448617846, -0.03661278237783158,
+ -0.0379227303416262, -0.042189005718490775,
+ -0.026595666344596286, -0.009759025956801257,
+ -0.002064986663513004, -0.002420117028098389,
+ -0.006629991977552491, 0.004619970897631026,
+ 0.019450642967537877, 0.0173521119057514,
+ 0.017641425439988062, 0.02270029598048491,
+ 0.018976431925275348, 0.009299852902290885,
+ -0.001695039371619912, -0.00675162574265618,
+ -0.009380968871003034, -0.011208396125485165,
+ -0.01308640049201482, -0.0165636375633249,
+ -0.022004099870933345, -0.025173458684139286,
+ -0.016918759559175375, -0.00865150653575917,
+ -0.006999929082792643, -0.005454830010518988,
+ -0.0021129521131095317, 0.00018717090054046307,
+ -0.0002864344788569993, 0.0017615225381095569,
+ 0.006985907557802283, 0.010577308310476465,
+ 0.006466104789306027, -0.0014988738575948326,
+ -0.0039669755229277195, -0.0065156971200080235,
+ -0.009343206924192169, -0.0076430644693577495,
+ -0.004395214976600924, -0.003052735340422483,
+ -0.007019103043066595, -0.00974109267696527,
+ -0.007968015032797376, -0.007801513845528344,
+ -0.007535748903681969, -0.003543341967287925,
+ 0.0015083125553729722, 0.0023345972556147025,
+ -0.0010043623069557037, -0.0025295765105203746,
+ -0.0023701840891643634, -0.0005908186035024362,
+ 0.0029826252289082847, 0.004829048542117764,
+ 0.004488360022902081, 0.00002643748103005408,
+ -0.0042100779212597295, -0.006170600558114495,
+ -0.007267149164680168, -0.006825522903494639,
+ -0.006899834372739123, -0.0073493916110062675,
+ -0.009554351265163382, -0.011790297433830197,
+ -0.010645796603734424, -0.0064661575394022106,
+ -0.002026743466524137, -0.0004337034584909932,
+ -0.0011172647031654614, -0.0017947816283674731,
+ -0.00255615052036616, -0.0017721562881944813,
+ -0.0002379619297227554, 0.0007130120121089036
+};
+
+#endif /* MPLAYER_AF_HRTF_H */
diff --git a/audio/filter/af_karaoke.c b/audio/filter/af_karaoke.c
new file mode 100644
index 0000000000..965eb8f40d
--- /dev/null
+++ b/audio/filter/af_karaoke.c
@@ -0,0 +1,98 @@
+/*
+ * simple voice removal filter
+ *
+ * copyright (c) 2006 Reynaldo H. Verdejo Pinochet
+ * Based on code by Alex Beregszaszi for his 'center' filter.
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "af.h"
+
+// Data for specific instances of this filter
+
+// Initialization and runtime control
+static int control(struct af_instance* af, int cmd, void* arg)
+{
+ switch(cmd){
+ case AF_CONTROL_REINIT:
+ af->data->rate = ((struct mp_audio*)arg)->rate;
+ af->data->nch = ((struct mp_audio*)arg)->nch;
+ af->data->format= AF_FORMAT_FLOAT_NE;
+ af->data->bps = 4;
+ return af_test_output(af,(struct mp_audio*)arg);
+ }
+ return AF_UNKNOWN;
+}
+
+// Deallocate memory
+static void uninit(struct af_instance* af)
+{
+ free(af->data);
+}
+
+// Filter data through filter
+static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
+{
+ struct mp_audio* c = data; // Current working data
+ float* a = c->audio; // Audio data
+ int len = c->len/4; // Number of samples in current audio block
+ int nch = c->nch; // Number of channels
+ register int i;
+
+ /*
+ FIXME1 add a low band pass filter to avoid suppressing
+ centered bass/drums
+ FIXME2 better calculated* attenuation factor
+ */
+
+ for(i=0;i<len;i+=nch)
+ {
+ a[i] = (a[i] - a[i+1]) * 0.7;
+ a[i+1]=a[i];
+ }
+
+ return c;
+}
+
+// Allocate memory and set function pointers
+static int af_open(struct af_instance* af){
+ af->control = control;
+ af->uninit = uninit;
+ af->play = play;
+ af->mul = 1;
+ af->data = calloc(1,sizeof(struct mp_audio));
+
+ if(af->data == NULL)
+ return AF_ERROR;
+
+ return AF_OK;
+}
+
+// Description of this filter
+struct af_info af_info_karaoke = {
+ "Simple karaoke/voice-removal audio filter",
+ "karaoke",
+ "Reynaldo H. Verdejo Pinochet",
+ "",
+ AF_FLAGS_NOT_REENTRANT,
+ af_open
+};
diff --git a/audio/filter/af_ladspa.c b/audio/filter/af_ladspa.c
new file mode 100644
index 0000000000..c1b3f24360
--- /dev/null
+++ b/audio/filter/af_ladspa.c
@@ -0,0 +1,915 @@
+/*
+ * LADSPA plugin loader
+ *
+ * Written by Ivo van Poorten <ivop@euronet.nl>
+ * Copyright (C) 2004, 2005
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* ------------------------------------------------------------------------- */
+
+/* Global Includes */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <inttypes.h>
+#include <math.h>
+#include <limits.h>
+
+#include <dlfcn.h>
+#include <ladspa.h>
+
+/* ------------------------------------------------------------------------- */
+
+/* Local Includes */
+
+#include "af.h"
+
+/* ------------------------------------------------------------------------- */
+
+/* Filter specific data */
+
+typedef struct af_ladspa_s
+{
+ int status; /**< Status of the filter.
+ * Either AF_OK or AF_ERROR
+ * Because MPlayer re-inits audio filters that
+ * _clearly_ returned AF_ERROR anyway, I use this
+ * in play() to skip the processing and return
+ * the data unchanged.
+ */
+
+ int activated; /**< 0 or 1. Activate LADSPA filters only once, even
+ * if the buffers get resized, to avoid a stuttering
+ * filter.
+ */
+
+ char *file;
+ char *label;
+
+ char *myname; /**< It's easy to have a concatenation of file and label */
+
+ void *libhandle;
+ const LADSPA_Descriptor *plugin_descriptor;
+
+ int nports;
+
+ int ninputs;
+ int *inputs;
+
+ int noutputs;
+ int *outputs;
+
+ int ninputcontrols;
+ int *inputcontrolsmap; /**< Map input port number [0-] to actual port */
+ float *inputcontrols;
+
+ int noutputcontrols;
+ int *outputcontrolsmap;
+ float *outputcontrols;
+
+ int nch; /**< number of channels */
+ int bufsize;
+ float **inbufs;
+ float **outbufs;
+ LADSPA_Handle *chhandles;
+
+} af_ladspa_t;
+
+/* ------------------------------------------------------------------------- */
+
+static int af_open(struct af_instance *af);
+static int af_ladspa_malloc_failed(char*);
+
+/* ------------------------------------------------------------------------- */
+
+/* Description */
+
+struct af_info af_info_ladspa = {
+ "LADSPA plugin loader",
+ "ladspa",
+ "Ivo van Poorten",
+ "",
+ AF_FLAGS_REENTRANT,
+ af_open
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* By lack of a better word (in my vocabulary) this is called 'parse'.
+ * Feel free to suggest an alternative.
+ */
+
+/** \brief Check for inputs, outputs and controls of a given filter.
+ *
+ * This function counts and checks all input, output and control ports
+ * of the filter that was loaded. If it turns out to be a valid
+ * filter for MPlayer use, it prints out a list of all controls and
+ * the corresponding range of its value at message level MSGL_V.
+ *
+ * \param setup Current setup of the filter. Must have its
+ * plugin_descriptor set!
+ *
+ * \return Returns AF_OK if it has a valid input/output/controls
+ * configuration. Else, it returns AF_ERROR.
+ */
+
+static int af_ladspa_parse_plugin(af_ladspa_t *setup) {
+ int p, i;
+ const LADSPA_Descriptor *pdes = setup->plugin_descriptor;
+ LADSPA_PortDescriptor d;
+ LADSPA_PortRangeHint hint;
+
+ if (!setup->libhandle)
+ return AF_ERROR; /* only call parse after a succesful load */
+ if (!setup->plugin_descriptor)
+ return AF_ERROR; /* same as above */
+
+ /* let's do it */
+
+ setup->nports = pdes->PortCount;
+
+ /* allocate memory for all inputs/outputs/controls */
+
+ setup->inputs = calloc(setup->nports, sizeof(int));
+ if (!setup->inputs) return af_ladspa_malloc_failed(setup->myname);
+
+ setup->outputs = calloc(setup->nports, sizeof(int));
+ if (!setup->outputs) return af_ladspa_malloc_failed(setup->myname);
+
+ setup->inputcontrolsmap = calloc(setup->nports, sizeof(int));
+ if (!setup->inputcontrolsmap) return af_ladspa_malloc_failed(setup->myname);
+
+ setup->inputcontrols = calloc(setup->nports, sizeof(float));
+ if (!setup->inputcontrols) return af_ladspa_malloc_failed(setup->myname);
+
+ setup->outputcontrolsmap = calloc(setup->nports, sizeof(int));
+ if (!setup->outputcontrolsmap) return af_ladspa_malloc_failed(setup->myname);
+
+ setup->outputcontrols = calloc(setup->nports, sizeof(float));
+ if (!setup->outputcontrols) return af_ladspa_malloc_failed(setup->myname);
+
+ /* set counts to zero */
+
+ setup->ninputs = 0;
+ setup->noutputs = 0;
+ setup->ninputcontrols = 0;
+ setup->noutputcontrols = 0;
+
+ /* check all ports, see what type it is and set variables according to
+ * what we have found
+ */
+
+ for (p=0; p<setup->nports; p++) {
+ d = pdes->PortDescriptors[p];
+
+ if (LADSPA_IS_PORT_AUDIO(d)) {
+ if (LADSPA_IS_PORT_INPUT(d)) {
+ setup->inputs[setup->ninputs] = p;
+ setup->ninputs++;
+ } else if (LADSPA_IS_PORT_OUTPUT(d)) {
+ setup->outputs[setup->noutputs] = p;
+ setup->noutputs++;
+ }
+ }
+
+ if (LADSPA_IS_PORT_CONTROL(d)) {
+ if (LADSPA_IS_PORT_INPUT(d)) {
+ setup->inputcontrolsmap[setup->ninputcontrols] = p;
+ setup->ninputcontrols++;
+ /* set control to zero. set values after reading the rest
+ * of the suboptions and check LADSPA_?_HINT's later.
+ */
+ setup->inputcontrols[p] = 0.0f;
+ } else if (LADSPA_IS_PORT_OUTPUT(d)) {
+ /* read and handle these too, otherwise filters that have them
+ * will sig11
+ */
+ setup->outputcontrolsmap[setup->noutputcontrols]=p;
+ setup->noutputcontrols++;
+ setup->outputcontrols[p] = 0.0f;
+ }
+ }
+
+ }
+
+ if (setup->ninputs == 0) {
+ mp_msg(MSGT_AFILTER, MSGL_WARN, "%s: %s\n", setup->myname,
+ _("WARNING! This LADSPA plugin has no audio inputs.\n The incoming audio signal will be lost."));
+ } else if (setup->ninputs == 1) {
+ mp_msg(MSGT_AFILTER, MSGL_V, "%s: this is a mono effect\n", setup->myname);
+ } else if (setup->ninputs == 2) {
+ mp_msg(MSGT_AFILTER, MSGL_V, "%s: this is a stereo effect\n", setup->myname);
+ } else {
+ mp_msg(MSGT_AFILTER, MSGL_V, "%s: this is a %i-channel effect, "
+ "support is experimental\n", setup->myname, setup->ninputs);
+ }
+
+ if (setup->noutputs == 0) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "%s: %s\n", setup->myname,
+ _("This LADSPA plugin has no audio outputs."));
+ return AF_ERROR;
+ }
+
+ if (setup->noutputs != setup->ninputs ) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "%s: %s\n", setup->myname,
+ _("The number of audio inputs and audio outputs of the LADSPA plugin differ."));
+ return AF_ERROR;
+ }
+
+ mp_msg(MSGT_AFILTER, MSGL_V, "%s: this plugin has %d input control(s)\n",
+ setup->myname, setup->ninputcontrols);
+
+ /* Print list of controls and its range of values it accepts */
+
+ for (i=0; i<setup->ninputcontrols; i++) {
+ p = setup->inputcontrolsmap[i];
+ hint = pdes->PortRangeHints[p];
+ mp_msg(MSGT_AFILTER, MSGL_V, " --- %d %s [", i, pdes->PortNames[p]);
+
+ if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor)) {
+ mp_msg(MSGT_AFILTER, MSGL_V, "%0.2f , ", hint.LowerBound);
+ } else {
+ mp_msg(MSGT_AFILTER, MSGL_V, "... , ");
+ }
+
+ if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor)) {
+ mp_msg(MSGT_AFILTER, MSGL_V, "%0.2f]\n", hint.UpperBound);
+ } else {
+ mp_msg(MSGT_AFILTER, MSGL_V, "...]\n");
+ }
+
+ }
+
+ return AF_OK;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* This function might "slightly" look like dlopenLADSPA in the LADSPA SDK :-)
+ * But, I changed a few things, because imho it was broken. It did not support
+ * relative paths, only absolute paths that start with a /
+ * I think ../../some/dir/foobar.so is just as valid. And if one wants to call
+ * his library '...somename...so' he's crazy, but it should be allowed.
+ * So, search the path first, try plain *filename later.
+ * Also, try adding .so first! I like the recursion the SDK did, but it's
+ * better the other way around. -af ladspa=cmt:amp_stereo:0.5 is easier to type
+ * than -af ladspa=cmt.so:amp_stereo:0.5 :-))
+ */
+
+/** \brief dlopen() wrapper
+ *
+ * This is a wrapper around dlopen(). It tries various variations of the
+ * filename (with or without the addition of the .so extension) in various
+ * directories specified by the LADSPA_PATH environment variable. If all fails
+ * it tries the filename directly as an absolute path to the library.
+ *
+ * \param filename filename of the library to load.
+ * \param flag see dlopen(3) for a description of the flags.
+ *
+ * \return returns a pointer to the loaded library on success, or
+ * NULL if it fails to load.
+ */
+
+static void* mydlopen(const char *filename, int flag) {
+ char *buf;
+ const char *end, *start, *ladspapath;
+ int endsinso, needslash;
+ size_t filenamelen;
+ void *result = NULL;
+
+#if defined(__MINGW32__) || defined(__CYGWIN__)
+ /* For Windows there's only absolute path support.
+ * If you have a Windows machine, feel free to fix this.
+ * (path separator, shared objects extension, et cetera). */
+ mp_msg(MSGT_AFILTER, MSGL_V, "\ton windows, only absolute pathnames "
+ "are supported\n");
+ mp_msg(MSGT_AFILTER, MSGL_V, "\ttrying %s\n", filename);
+ return dlopen(filename, flag);
+#endif
+
+ filenamelen = strlen(filename);
+
+ endsinso = 0;
+ if (filenamelen > 3)
+ endsinso = (strcmp(filename+filenamelen-3, ".so") == 0);
+ if (!endsinso) {
+ buf=malloc(filenamelen+4);
+ strcpy(buf, filename);
+ strcat(buf, ".so");
+ result=mydlopen(buf, flag);
+ free(buf);
+ }
+
+ if (result)
+ return result;
+
+ ladspapath=getenv("LADSPA_PATH");
+
+ if (ladspapath) {
+
+ start=ladspapath;
+ while (*start != '\0') {
+ end=start;
+ while ( (*end != ':') && (*end != '\0') )
+ end++;
+
+ buf=malloc(filenamelen + 2 + (end-start) );
+ if (end > start)
+ strncpy(buf, start, end-start);
+ needslash=0;
+ if (end > start)
+ if (*(end-1) != '/') {
+ needslash = 1;
+ buf[end-start] = '/';
+ }
+ strcpy(buf+needslash+(end-start), filename);
+
+ mp_msg(MSGT_AFILTER, MSGL_V, "\ttrying %s\n", buf);
+ result=dlopen(buf, flag);
+
+ free(buf);
+ if (result)
+ return result;
+
+ start = end;
+ if (*start == ':')
+ start++;
+ } /* end while there's still more in the path */
+ } /* end if there's a ladspapath */
+
+ /* last resort, just open it again, so the dlerror() message is correct */
+ mp_msg(MSGT_AFILTER, MSGL_V, "\ttrying %s\n", filename);
+ return dlopen(filename,flag);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/** \brief Load a LADSPA Plugin
+ *
+ * This function loads the LADSPA plugin specified by the file and label
+ * that are present in the setup variable. First, it loads the library.
+ * If it fails, it returns AF_ERROR. If not, it continues to look for the
+ * specified label. If it finds it, it sets the plugin_descriptor inside
+ * setup and returns AF_OK. If it doesn't, it returns AF_ERROR. Special case
+ * is a label called 'help'. In that case, it prints a list of all available
+ * labels (filters) in the library specified by file.
+ *
+ * \param setup Current setup of the filter. Contains filename and label.
+ *
+ * \return Either AF_ERROR or AF_OK, depending on the success of the operation.
+ */
+
+static int af_ladspa_load_plugin(af_ladspa_t *setup) {
+ const LADSPA_Descriptor *ladspa_descriptor;
+ LADSPA_Descriptor_Function descriptor_function;
+ int i;
+
+ /* load library */
+ mp_msg(MSGT_AFILTER, MSGL_V, "%s: loading ladspa plugin library %s\n",
+ setup->myname, setup->file);
+
+ setup->libhandle = mydlopen(setup->file, RTLD_NOW);
+
+ if (!setup->libhandle) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "%s: %s %s\n\t%s\n", setup->myname,
+ _("failed to load"), setup->file, dlerror() );
+ return AF_ERROR;
+ }
+
+ mp_msg(MSGT_AFILTER, MSGL_V, "%s: library found.\n", setup->myname);
+
+ /* find descriptor function */
+ dlerror();
+ descriptor_function = (LADSPA_Descriptor_Function) dlsym (setup->libhandle,
+ "ladspa_descriptor");
+
+ if (!descriptor_function) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "%s: %s\n\t%s\n", setup->myname,
+ _("Couldn't find ladspa_descriptor() function in the specified library file."), dlerror());
+ return AF_ERROR;
+ }
+
+ /* if label == help, list all labels in library and exit */
+
+ if (strcmp(setup->label, "help") == 0) {
+ mp_msg(MSGT_AFILTER, MSGL_INFO, "%s: %s %s:\n", setup->myname,
+ _("available labels in"), setup->file);
+ for (i=0; ; i++) {
+ ladspa_descriptor = descriptor_function(i);
+ if (ladspa_descriptor == NULL) {
+ return AF_ERROR;
+ }
+ mp_msg(MSGT_AFILTER, MSGL_INFO, " %-16s - %s (%lu)\n",
+ ladspa_descriptor->Label,
+ ladspa_descriptor->Name,
+ ladspa_descriptor->UniqueID);
+ }
+ }
+
+ mp_msg(MSGT_AFILTER, MSGL_V, "%s: looking for label\n", setup->myname);
+
+ /* find label in library */
+ for (i=0; ; i++) {
+ ladspa_descriptor = descriptor_function(i);
+ if (ladspa_descriptor == NULL) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "%s: %s\n", setup->myname,
+ _("Couldn't find label in plugin library."));
+ return AF_ERROR;
+ }
+ if (strcmp(ladspa_descriptor->Label, setup->label) == 0) {
+ setup->plugin_descriptor = ladspa_descriptor;
+ mp_msg(MSGT_AFILTER, MSGL_V, "%s: %s found\n", setup->myname,
+ setup->label);
+ return AF_OK;
+ }
+ }
+
+ return AF_OK;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/** \brief Print a malloc() failed error message.
+ *
+ * Generic function which can be called if a call to malloc(), calloc(),
+ * strdup(), et cetera, failed. It prints a message to the console and
+ * returns AF_ERROR.
+ *
+ * \return AF_ERROR
+ */
+
+static int af_ladspa_malloc_failed(char *myname) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "%s: %s", myname, "Memory allocation failed.\n");
+ return AF_ERROR;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/** \brief Controls the filter.
+ *
+ * Control the behaviour of the filter.
+ *
+ * Commands:
+ * CONTROL_REINIT Sets the af structure with proper values for number
+ * of channels, rate, format, et cetera.
+ * CONTROL_COMMAND_LINE Parses the suboptions given to this filter
+ * through arg. It first parses the filename and
+ * the label. After that, it loads the filter
+ * and finds out its proprties. Then in continues
+ * parsing the controls given on the commandline,
+ * if any are needed.
+ *
+ * \param af Audio filter instance
+ * \param cmd The command to execute
+ * \param arg Arguments to the command
+ *
+ * \return Either AF_ERROR or AF_OK, depending on the succes of the
+ * operation.
+ */
+
+static int control(struct af_instance *af, int cmd, void *arg) {
+ af_ladspa_t *setup = (af_ladspa_t*) af->setup;
+ int i, r;
+ float val;
+
+ switch(cmd) {
+ case AF_CONTROL_REINIT:
+ mp_msg(MSGT_AFILTER, MSGL_V, "%s: (re)init\n", setup->myname);
+
+ if (!arg) return AF_ERROR;
+
+ /* accept FLOAT, let af_format do conversion */
+
+ af->data->rate = ((struct mp_audio*)arg)->rate;
+ af->data->nch = ((struct mp_audio*)arg)->nch;
+ af->data->format = AF_FORMAT_FLOAT_NE;
+ af->data->bps = 4;
+
+ /* arg->len is not set here yet, so init of buffers and connecting the
+ * filter, has to be done in play() :-/
+ */
+
+ return af_test_output(af, (struct mp_audio*)arg);
+ case AF_CONTROL_COMMAND_LINE: {
+ char *buf;
+ char *line = arg;
+
+ mp_msg(MSGT_AFILTER, MSGL_V, "%s: parse suboptions\n", setup->myname);
+
+ /* suboption parser here!
+ * format is (ladspa=)file:label:controls....
+ */
+
+ if (!line) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "%s: %s\n", setup->myname,
+ _("No suboptions specified."));
+ return AF_ERROR;
+ }
+
+ buf = malloc(strlen(line)+1);
+ if (!buf) return af_ladspa_malloc_failed(setup->myname);
+
+ /* file... */
+ buf[0] = '\0';
+ sscanf(line, "%[^:]", buf);
+ if (buf[0] == '\0') {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "%s: %s\n", setup->myname,
+ _("No library file specified."));
+ free(buf);
+ return AF_ERROR;
+ }
+ line += strlen(buf);
+ setup->file = strdup(buf);
+ if (!setup->file) return af_ladspa_malloc_failed(setup->myname);
+ mp_msg(MSGT_AFILTER, MSGL_V, "%s: file --> %s\n", setup->myname,
+ setup->file);
+ if (*line != '\0') line++; /* read ':' */
+
+ /* label... */
+ buf[0] = '\0';
+ sscanf(line, "%[^:]", buf);
+ if (buf[0] == '\0') {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "%s: %s\n", setup->myname,
+ _("No filter label specified."));
+ free(buf);
+ return AF_ERROR;
+ }
+ line += strlen(buf);
+ setup->label = strdup(buf);
+ if (!setup->label) return af_ladspa_malloc_failed(setup->myname);
+ mp_msg(MSGT_AFILTER, MSGL_V, "%s: label --> %s\n", setup->myname,
+ setup->label);
+/* if (*line != '0') line++; */ /* read ':' */
+
+ free(buf); /* no longer needed */
+
+ /* set new setup->myname */
+
+ free(setup->myname);
+ setup->myname = calloc(strlen(af_info_ladspa.name)+strlen(setup->file)+
+ strlen(setup->label)+6, 1);
+ snprintf(setup->myname, strlen(af_info_ladspa.name)+
+ strlen(setup->file)+strlen(setup->label)+6, "%s: (%s:%s)",
+ af_info_ladspa.name, setup->file, setup->label);
+
+ /* load plugin :) */
+
+ if ( af_ladspa_load_plugin(setup) != AF_OK )
+ return AF_ERROR;
+
+ /* see what inputs, outputs and controls this plugin has */
+ if ( af_ladspa_parse_plugin(setup) != AF_OK )
+ return AF_ERROR;
+
+ /* ninputcontrols is set by now, read control values from arg */
+
+ for(i=0; i<setup->ninputcontrols; i++) {
+ if (!line || *line != ':') {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "%s: %s\n", setup->myname,
+ _("Not enough controls specified on the command line."));
+ return AF_ERROR;
+ }
+ line++;
+ r = sscanf(line, "%f", &val);
+ if (r!=1) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "%s: %s\n", setup->myname,
+ _("Not enough controls specified on the command line."));
+ return AF_ERROR;
+ }
+ setup->inputcontrols[setup->inputcontrolsmap[i]] = val;
+ line = strchr(line, ':');
+ }
+
+ mp_msg(MSGT_AFILTER, MSGL_V, "%s: input controls: ", setup->myname);
+ for(i=0; i<setup->ninputcontrols; i++) {
+ mp_msg(MSGT_AFILTER, MSGL_V, "%0.4f ",
+ setup->inputcontrols[setup->inputcontrolsmap[i]]);
+ }
+ mp_msg(MSGT_AFILTER, MSGL_V, "\n");
+
+ /* check boundaries of inputcontrols */
+
+ mp_msg(MSGT_AFILTER, MSGL_V, "%s: checking boundaries of input controls\n",
+ setup->myname);
+ for(i=0; i<setup->ninputcontrols; i++) {
+ int p = setup->inputcontrolsmap[i];
+ LADSPA_PortRangeHint hint =
+ setup->plugin_descriptor->PortRangeHints[p];
+ val = setup->inputcontrols[p];
+
+ if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor) &&
+ val < hint.LowerBound) {
+ mp_tmsg(MSGT_AFILTER, MSGL_ERR, "%s: Input control #%d is below lower boundary of %0.4f.\n",
+ setup->myname, i, hint.LowerBound);
+ return AF_ERROR;
+ }
+ if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor) &&
+ val > hint.UpperBound) {
+ mp_tmsg(MSGT_AFILTER, MSGL_ERR, "%s: Input control #%d is above upper boundary of %0.4f.\n",
+ setup->myname, i, hint.UpperBound);
+ return AF_ERROR;
+ }
+ }
+ mp_msg(MSGT_AFILTER, MSGL_V, "%s: all controls have sane values\n",
+ setup->myname);
+
+ /* All is well! */
+ setup->status = AF_OK;
+
+ return AF_OK; }
+ }
+
+ return AF_UNKNOWN;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/** \brief Uninitialise the LADSPA Plugin Loader filter.
+ *
+ * This function deactivates the plugin(s), cleans up, frees all allocated
+ * memory and exits.
+ *
+ * \return No return value.
+ */
+
+static void uninit(struct af_instance *af) {
+ int i;
+
+ free(af->data);
+ if (af->setup) {
+ af_ladspa_t *setup = (af_ladspa_t*) af->setup;
+ const LADSPA_Descriptor *pdes = setup->plugin_descriptor;
+
+ if (setup->myname) {
+ mp_msg(MSGT_AFILTER, MSGL_V, "%s: cleaning up\n", setup->myname);
+ free(setup->myname);
+ }
+
+ if (setup->chhandles) {
+ for(i=0; i<setup->nch; i+=setup->ninputs) {
+ if (pdes->deactivate) pdes->deactivate(setup->chhandles[i]);
+ if (pdes->cleanup) pdes->cleanup(setup->chhandles[i]);
+ }
+ free(setup->chhandles);
+ }
+
+ free(setup->file);
+ free(setup->label);
+ free(setup->inputcontrolsmap);
+ free(setup->inputcontrols);
+ free(setup->outputcontrolsmap);
+ free(setup->outputcontrols);
+ free(setup->inputs);
+ free(setup->outputs);
+
+ if (setup->inbufs) {
+ for(i=0; i<setup->nch; i++)
+ free(setup->inbufs[i]);
+ free(setup->inbufs);
+ }
+
+ if (setup->outbufs) {
+ for(i=0; i<setup->nch; i++)
+ free(setup->outbufs[i]);
+ free(setup->outbufs);
+ }
+
+ if (setup->libhandle)
+ dlclose(setup->libhandle);
+
+ free(setup);
+ setup = NULL;
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+/** \brief Process chunk of audio data through the selected LADSPA Plugin.
+ *
+ * \param af Pointer to audio filter instance
+ * \param data Pointer to chunk of audio data
+ *
+ * \return Either AF_ERROR or AF_OK
+ */
+
+static struct mp_audio* play(struct af_instance *af, struct mp_audio *data) {
+ af_ladspa_t *setup = af->setup;
+ const LADSPA_Descriptor *pdes = setup->plugin_descriptor;
+ float *audio = (float*)data->audio;
+ int nsamples = data->len/4; /* /4 because it's 32-bit float */
+ int nch = data->nch;
+ int rate = data->rate;
+ int i, p;
+
+ if (setup->status !=AF_OK)
+ return data;
+
+ /* See if it's the first call. If so, setup inbufs/outbufs, instantiate
+ * plugin, connect ports and activate plugin
+ */
+
+ /* 2004-12-07: Also check if the buffersize has to be changed!
+ * data->len is not constant per se! re-init buffers.
+ */
+
+ if ( (setup->bufsize != nsamples/nch) || (setup->nch != nch) ) {
+
+ /* if setup->nch==0, it's the first call, if not, something has
+ * changed and all previous mallocs have to be freed
+ */
+
+ if (setup->nch != 0) {
+ mp_msg(MSGT_AFILTER, MSGL_DBG3, "%s: bufsize change; free old buffer\n",
+ setup->myname);
+
+ if(setup->inbufs) {
+ for(i=0; i<setup->nch; i++)
+ free(setup->inbufs[i]);
+ free(setup->inbufs);
+ }
+ if(setup->outbufs) {
+ for(i=0; i<setup->nch; i++)
+ free(setup->outbufs[i]);
+ free(setup->outbufs);
+ }
+ } /* everything is freed */
+
+ setup->bufsize = nsamples/nch;
+ setup->nch = nch;
+
+ setup->inbufs = calloc(nch, sizeof(float*));
+ setup->outbufs = calloc(nch, sizeof(float*));
+
+ mp_msg(MSGT_AFILTER, MSGL_DBG3, "%s: bufsize = %d\n",
+ setup->myname, setup->bufsize);
+
+ for(i=0; i<nch; i++) {
+ setup->inbufs[i] = calloc(setup->bufsize, sizeof(float));
+ setup->outbufs[i] = calloc(setup->bufsize, sizeof(float));
+ }
+
+ /* only on the first call, there are no handles. */
+
+ if (!setup->chhandles) {
+ setup->chhandles = calloc(nch, sizeof(LADSPA_Handle));
+
+ /* create handles
+ * for stereo effects, create one handle for two channels
+ */
+
+ for(i=0; i<nch; i++) {
+
+ if (i % setup->ninputs) { /* stereo effect */
+ /* copy the handle from previous channel */
+ setup->chhandles[i] = setup->chhandles[i-1];
+ continue;
+ }
+
+ setup->chhandles[i] = pdes->instantiate(pdes, rate);
+ }
+ }
+
+ /* connect input/output ports for each channel/filter instance
+ *
+ * always (re)connect ports
+ */
+
+ for(i=0; i<nch; i++) {
+ pdes->connect_port(setup->chhandles[i],
+ setup->inputs[i % setup->ninputs],
+ setup->inbufs[i]);
+ pdes->connect_port(setup->chhandles[i],
+ setup->outputs[i % setup->ninputs],
+ setup->outbufs[i]);
+
+ /* connect (input) controls */
+
+ for (p=0; p<setup->nports; p++) {
+ LADSPA_PortDescriptor d = pdes->PortDescriptors[p];
+ if (LADSPA_IS_PORT_CONTROL(d)) {
+ if (LADSPA_IS_PORT_INPUT(d)) {
+ pdes->connect_port(setup->chhandles[i], p,
+ &(setup->inputcontrols[p]) );
+ } else {
+ pdes->connect_port(setup->chhandles[i], p,
+ &(setup->outputcontrols[p]) );
+ }
+ }
+ }
+
+ /* Activate filter (if it isn't already :) ) */
+
+ if (pdes->activate && !setup->activated && i % setup->ninputs == 0)
+ pdes->activate(setup->chhandles[i]);
+
+ } /* All channels/filters done! except for... */
+ setup->activated = 1;
+
+ /* Stereo effect with one channel left. Use same buffer for left
+ * and right. connect it to the second port.
+ */
+
+ for (p = i; p % setup->ninputs; p++) {
+ pdes->connect_port(setup->chhandles[i-1],
+ setup->inputs[p % setup->ninputs],
+ setup->inbufs[i-1]);
+ pdes->connect_port(setup->chhandles[i-1],
+ setup->outputs[p % setup->ninputs],
+ setup->outbufs[i-1]);
+ } /* done! */
+
+ } /* setup for first call/change of bufsize is done.
+ * normal playing routine follows...
+ */
+
+ /* Right now, I use a separate input and output buffer.
+ * I could change this to in-place processing (inbuf==outbuf), but some
+ * ladspa filters are broken and are not able to handle that. This seems
+ * fast enough, so unless somebody complains, it stays this way :)
+ */
+
+ /* Fill inbufs */
+
+ for (p=0; p<setup->bufsize; p++) {
+ for (i=0; i<nch; i++) {
+ setup->inbufs[i][p] = audio[p*nch + i];
+ }
+ }
+
+ /* Run filter(s) */
+
+ for (i=0; i<nch; i+=setup->ninputs) {
+ pdes->run(setup->chhandles[i], setup->bufsize);
+ }
+
+ /* Extract outbufs */
+
+ for (p=0; p<setup->bufsize; p++) {
+ for (i=0; i<nch; i++) {
+ audio[p*nch + i] = setup->outbufs[i][p];
+ }
+ }
+
+ /* done */
+
+ return data;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/** \brief Open LADSPA Plugin Loader Filter
+ *
+ * \param af Audio Filter instance
+ *
+ * \return Either AF_ERROR or AF_OK
+ */
+
+static int af_open(struct af_instance *af) {
+
+ af->control=control;
+ af->uninit=uninit;
+ af->play=play;
+ af->mul=1;
+
+ af->data = calloc(1, sizeof(struct mp_audio));
+ if (af->data == NULL)
+ return af_ladspa_malloc_failed((char*)af_info_ladspa.name);
+
+ af->setup = calloc(1, sizeof(af_ladspa_t));
+ if (af->setup == NULL) {
+ free(af->data);
+ af->data=NULL;
+ return af_ladspa_malloc_failed((char*)af_info_ladspa.name);
+ }
+
+ ((af_ladspa_t*)af->setup)->status = AF_ERROR; /* will be set to AF_OK if
+ * all went OK and play()
+ * should proceed.
+ */
+
+ ((af_ladspa_t*)af->setup)->myname = strdup(af_info_ladspa.name);
+ if (!((af_ladspa_t*)af->setup)->myname)
+ return af_ladspa_malloc_failed((char*)af_info_ladspa.name);
+
+ return AF_OK;
+}
+
+/* ------------------------------------------------------------------------- */
diff --git a/audio/filter/af_lavcac3enc.c b/audio/filter/af_lavcac3enc.c
new file mode 100644
index 0000000000..ad78266ad3
--- /dev/null
+++ b/audio/filter/af_lavcac3enc.c
@@ -0,0 +1,332 @@
+/*
+ * audio filter for runtime AC-3 encoding with libavcodec.
+ *
+ * Copyright (C) 2007 Ulion <ulion A gmail P com>
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <assert.h>
+
+#include <libavcodec/avcodec.h>
+#include <libavutil/intreadwrite.h>
+#include <libavutil/mem.h>
+
+#include "config.h"
+#include "af.h"
+#include "reorder_ch.h"
+
+
+#define AC3_MAX_CHANNELS 6
+#define AC3_MAX_CODED_FRAME_SIZE 3840
+#define AC3_FRAME_SIZE (6 * 256)
+const uint16_t ac3_bitrate_tab[19] = {
+ 32, 40, 48, 56, 64, 80, 96, 112, 128,
+ 160, 192, 224, 256, 320, 384, 448, 512, 576, 640
+};
+
+// Data for specific instances of this filter
+typedef struct af_ac3enc_s {
+ struct AVCodec *lavc_acodec;
+ struct AVCodecContext *lavc_actx;
+ int add_iec61937_header;
+ int bit_rate;
+ int pending_data_size;
+ char *pending_data;
+ int pending_len;
+ int expect_len;
+ int min_channel_num;
+ int in_sampleformat;
+} af_ac3enc_t;
+
+// Initialization and runtime control
+static int control(struct af_instance *af, int cmd, void *arg)
+{
+ af_ac3enc_t *s = af->setup;
+ struct mp_audio *data = arg;
+ int i, bit_rate, test_output_res;
+ static const int default_bit_rate[AC3_MAX_CHANNELS+1] = \
+ {0, 96000, 192000, 256000, 384000, 448000, 448000};
+
+ switch (cmd){
+ case AF_CONTROL_REINIT:
+ if (AF_FORMAT_IS_AC3(data->format) || data->nch < s->min_channel_num)
+ return AF_DETACH;
+
+ af->data->format = s->in_sampleformat;
+ af->data->bps = af_fmt2bits(s->in_sampleformat) / 8;
+ if (data->rate == 48000 || data->rate == 44100 || data->rate == 32000)
+ af->data->rate = data->rate;
+ else
+ af->data->rate = 48000;
+ if (data->nch > AC3_MAX_CHANNELS)
+ af->data->nch = AC3_MAX_CHANNELS;
+ else
+ af->data->nch = data->nch;
+ test_output_res = af_test_output(af, data);
+
+ s->pending_len = 0;
+ s->expect_len = AC3_FRAME_SIZE * data->nch * af->data->bps;
+ assert(s->expect_len <= s->pending_data_size);
+ if (s->add_iec61937_header)
+ af->mul = (double)AC3_FRAME_SIZE * 2 * 2 / s->expect_len;
+ else
+ af->mul = (double)AC3_MAX_CODED_FRAME_SIZE / s->expect_len;
+
+ mp_msg(MSGT_AFILTER, MSGL_DBG2, "af_lavcac3enc reinit: %d, %d, %f, %d.\n",
+ data->nch, data->rate, af->mul, s->expect_len);
+
+ bit_rate = s->bit_rate ? s->bit_rate : default_bit_rate[af->data->nch];
+
+ if (s->lavc_actx->channels != af->data->nch ||
+ s->lavc_actx->sample_rate != af->data->rate ||
+ s->lavc_actx->bit_rate != bit_rate) {
+
+ avcodec_close(s->lavc_actx);
+
+ // Put sample parameters
+ s->lavc_actx->channels = af->data->nch;
+ s->lavc_actx->sample_rate = af->data->rate;
+ s->lavc_actx->bit_rate = bit_rate;
+
+ if (avcodec_open2(s->lavc_actx, s->lavc_acodec, NULL) < 0) {
+ mp_tmsg(MSGT_AFILTER, MSGL_ERR, "Couldn't open codec %s, br=%d.\n", "ac3", bit_rate);
+ return AF_ERROR;
+ }
+ }
+ if (s->lavc_actx->frame_size != AC3_FRAME_SIZE) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "lavcac3enc: unexpected ac3 "
+ "encoder frame size %d\n", s->lavc_actx->frame_size);
+ return AF_ERROR;
+ }
+ af->data->format = AF_FORMAT_AC3_BE;
+ af->data->bps = 2;
+ af->data->nch = 2;
+ return test_output_res;
+ case AF_CONTROL_COMMAND_LINE:
+ mp_msg(MSGT_AFILTER, MSGL_DBG2, "af_lavcac3enc cmdline: %s.\n", (char*)arg);
+ s->bit_rate = 0;
+ s->min_channel_num = 0;
+ s->add_iec61937_header = 0;
+ sscanf(arg,"%d:%d:%d", &s->add_iec61937_header, &s->bit_rate,
+ &s->min_channel_num);
+ if (s->bit_rate < 1000)
+ s->bit_rate *= 1000;
+ if (s->bit_rate) {
+ for (i = 0; i < 19; ++i)
+ if (ac3_bitrate_tab[i] * 1000 == s->bit_rate)
+ break;
+ if (i >= 19) {
+ mp_msg(MSGT_AFILTER, MSGL_WARN, "af_lavcac3enc unable set unsupported "
+ "bitrate %d, use default bitrate (check manpage to see "
+ "supported bitrates).\n", s->bit_rate);
+ s->bit_rate = 0;
+ }
+ }
+ if (s->min_channel_num == 0)
+ s->min_channel_num = 5;
+ mp_msg(MSGT_AFILTER, MSGL_V, "af_lavcac3enc config spdif:%d, bitrate:%d, "
+ "minchnum:%d.\n", s->add_iec61937_header, s->bit_rate,
+ s->min_channel_num);
+ return AF_OK;
+ }
+ return AF_UNKNOWN;
+}
+
+// Deallocate memory
+static void uninit(struct af_instance* af)
+{
+ if (af->data)
+ free(af->data->audio);
+ free(af->data);
+ if (af->setup) {
+ af_ac3enc_t *s = af->setup;
+ af->setup = NULL;
+ if(s->lavc_actx) {
+ avcodec_close(s->lavc_actx);
+ av_free(s->lavc_actx);
+ }
+ free(s->pending_data);
+ free(s);
+ }
+}
+
+// Filter data through filter
+static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
+{
+ af_ac3enc_t *s = af->setup;
+ struct mp_audio *c = data; // Current working data
+ struct mp_audio *l;
+ int len, left, outsize = 0, destsize;
+ char *buf, *src, *dest;
+ int max_output_len;
+ int frame_num = (data->len + s->pending_len) / s->expect_len;
+ int samplesize = af_fmt2bits(s->in_sampleformat) / 8;
+
+ if (s->add_iec61937_header)
+ max_output_len = AC3_FRAME_SIZE * 2 * 2 * frame_num;
+ else
+ max_output_len = AC3_MAX_CODED_FRAME_SIZE * frame_num;
+
+ if (af->data->len < max_output_len) {
+ mp_msg(MSGT_AFILTER, MSGL_V, "[libaf] Reallocating memory in module %s, "
+ "old len = %i, new len = %i\n", af->info->name, af->data->len,
+ max_output_len);
+ free(af->data->audio);
+ af->data->audio = malloc(max_output_len);
+ if (!af->data->audio) {
+ mp_msg(MSGT_AFILTER, MSGL_FATAL, "[libaf] Could not allocate memory \n");
+ return NULL;
+ }
+ af->data->len = max_output_len;
+ }
+
+ l = af->data; // Local data
+ buf = l->audio;
+ src = c->audio;
+ left = c->len;
+
+
+ while (left > 0) {
+ if (left + s->pending_len < s->expect_len) {
+ memcpy(s->pending_data + s->pending_len, src, left);
+ src += left;
+ s->pending_len += left;
+ left = 0;
+ break;
+ }
+
+ dest = s->add_iec61937_header ? buf + 8 : buf;
+ destsize = (char *)l->audio + l->len - buf;
+
+ if (s->pending_len) {
+ int needs = s->expect_len - s->pending_len;
+ if (needs > 0) {
+ memcpy(s->pending_data + s->pending_len, src, needs);
+ src += needs;
+ left -= needs;
+ }
+
+ if (c->nch >= 5)
+ reorder_channel_nch(s->pending_data,
+ AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT,
+ AF_CHANNEL_LAYOUT_LAVC_DEFAULT,
+ c->nch,
+ s->expect_len / samplesize, samplesize);
+
+ len = avcodec_encode_audio(s->lavc_actx, dest, destsize,
+ (void *)s->pending_data);
+ s->pending_len = 0;
+ }
+ else {
+ if (c->nch >= 5)
+ reorder_channel_nch(src,
+ AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT,
+ AF_CHANNEL_LAYOUT_LAVC_DEFAULT,
+ c->nch,
+ s->expect_len / samplesize, samplesize);
+ len = avcodec_encode_audio(s->lavc_actx,dest,destsize,(void *)src);
+ src += s->expect_len;
+ left -= s->expect_len;
+ }
+ mp_msg(MSGT_AFILTER, MSGL_DBG2, "avcodec_encode_audio got %d, pending %d.\n",
+ len, s->pending_len);
+
+ if (s->add_iec61937_header) {
+ int bsmod = dest[5] & 0x7;
+
+ AV_WB16(buf, 0xF872); // iec 61937 syncword 1
+ AV_WB16(buf + 2, 0x4E1F); // iec 61937 syncword 2
+ buf[4] = bsmod; // bsmod
+ buf[5] = 0x01; // data-type ac3
+ AV_WB16(buf + 6, len << 3); // number of bits in payload
+
+ memset(buf + 8 + len, 0, AC3_FRAME_SIZE * 2 * 2 - 8 - len);
+ len = AC3_FRAME_SIZE * 2 * 2;
+ }
+
+ outsize += len;
+ buf += len;
+ }
+ c->audio = l->audio;
+ c->nch = 2;
+ c->bps = 2;
+ c->len = outsize;
+ mp_msg(MSGT_AFILTER, MSGL_DBG2, "play return size %d, pending %d\n",
+ outsize, s->pending_len);
+ return c;
+}
+
+static int af_open(struct af_instance* af){
+
+ af_ac3enc_t *s = calloc(1,sizeof(af_ac3enc_t));
+ af->control=control;
+ af->uninit=uninit;
+ af->play=play;
+ af->mul=1;
+ af->data=calloc(1,sizeof(struct mp_audio));
+ af->setup=s;
+
+ s->lavc_acodec = avcodec_find_encoder_by_name("ac3");
+ if (!s->lavc_acodec) {
+ mp_tmsg(MSGT_AFILTER, MSGL_ERR, "Audio LAVC, couldn't find encoder for codec %s.\n", "ac3");
+ return AF_ERROR;
+ }
+
+ s->lavc_actx = avcodec_alloc_context3(s->lavc_acodec);
+ if (!s->lavc_actx) {
+ mp_tmsg(MSGT_AFILTER, MSGL_ERR, "Audio LAVC, couldn't allocate context!\n");
+ return AF_ERROR;
+ }
+ const enum AVSampleFormat *fmts = s->lavc_acodec->sample_fmts;
+ for (int i = 0; ; i++) {
+ if (fmts[i] == AV_SAMPLE_FMT_NONE) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "Audio LAVC, encoder doesn't "
+ "support expected sample formats!\n");
+ return AF_ERROR;
+ } else if (fmts[i] == AV_SAMPLE_FMT_S16) {
+ s->in_sampleformat = AF_FORMAT_S16_NE;
+ s->lavc_actx->sample_fmt = fmts[i];
+ break;
+ } else if (fmts[i] == AV_SAMPLE_FMT_FLT) {
+ s->in_sampleformat = AF_FORMAT_FLOAT_NE;
+ s->lavc_actx->sample_fmt = fmts[i];
+ break;
+ }
+ }
+ char buf[100];
+ mp_msg(MSGT_AFILTER, MSGL_V, "[af_lavcac3enc]: in sample format: %s\n",
+ af_fmt2str(s->in_sampleformat, buf, 100));
+ s->pending_data_size = AF_NCH * AC3_FRAME_SIZE *
+ af_fmt2bits(s->in_sampleformat) / 8;
+ s->pending_data = malloc(s->pending_data_size);
+
+ return AF_OK;
+}
+
+struct af_info af_info_lavcac3enc = {
+ "runtime encode to ac3 using libavcodec",
+ "lavcac3enc",
+ "Ulion",
+ "",
+ AF_FLAGS_REENTRANT,
+ af_open
+};
diff --git a/audio/filter/af_lavcresample.c b/audio/filter/af_lavcresample.c
new file mode 100644
index 0000000000..ce777fed31
--- /dev/null
+++ b/audio/filter/af_lavcresample.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "config.h"
+#include "af.h"
+#include "libavcodec/avcodec.h"
+#include "libavutil/rational.h"
+
+// Data for specific instances of this filter
+typedef struct af_resample_s{
+ struct AVResampleContext *avrctx;
+ int16_t *in[AF_NCH];
+ int in_alloc;
+ int index;
+
+ int filter_length;
+ int linear;
+ int phase_shift;
+ double cutoff;
+
+ int ctx_out_rate;
+ int ctx_in_rate;
+ int ctx_filter_size;
+ int ctx_phase_shift;
+ int ctx_linear;
+ double ctx_cutoff;
+}af_resample_t;
+
+
+// Initialization and runtime control
+static int control(struct af_instance* af, int cmd, void* arg)
+{
+ af_resample_t* s = (af_resample_t*)af->setup;
+ struct mp_audio *data= (struct mp_audio*)arg;
+ int out_rate, test_output_res; // helpers for checking input format
+
+ switch(cmd){
+ case AF_CONTROL_REINIT:
+ if((af->data->rate == data->rate) || (af->data->rate == 0))
+ return AF_DETACH;
+
+ af->data->nch = data->nch;
+ if (af->data->nch > AF_NCH) af->data->nch = AF_NCH;
+ af->data->format = AF_FORMAT_S16_NE;
+ af->data->bps = 2;
+ af->mul = (double)af->data->rate / data->rate;
+ af->delay = af->data->nch * s->filter_length / min(af->mul, 1); // *bps*.5
+
+ if (s->ctx_out_rate != af->data->rate || s->ctx_in_rate != data->rate || s->ctx_filter_size != s->filter_length ||
+ s->ctx_phase_shift != s->phase_shift || s->ctx_linear != s->linear || s->ctx_cutoff != s->cutoff) {
+ if(s->avrctx) av_resample_close(s->avrctx);
+ s->avrctx= av_resample_init(af->data->rate, /*in_rate*/data->rate, s->filter_length, s->phase_shift, s->linear, s->cutoff);
+ s->ctx_out_rate = af->data->rate;
+ s->ctx_in_rate = data->rate;
+ s->ctx_filter_size = s->filter_length;
+ s->ctx_phase_shift = s->phase_shift;
+ s->ctx_linear = s->linear;
+ s->ctx_cutoff = s->cutoff;
+ }
+
+ // hack to make af_test_output ignore the samplerate change
+ out_rate = af->data->rate;
+ af->data->rate = data->rate;
+ test_output_res = af_test_output(af, (struct mp_audio*)arg);
+ af->data->rate = out_rate;
+ return test_output_res;
+ case AF_CONTROL_COMMAND_LINE:{
+ s->cutoff= 0.0;
+ sscanf((char*)arg,"%d:%d:%d:%d:%lf", &af->data->rate, &s->filter_length, &s->linear, &s->phase_shift, &s->cutoff);
+ if(s->cutoff <= 0.0) s->cutoff= max(1.0 - 6.5/(s->filter_length+8), 0.80);
+ return AF_OK;
+ }
+ case AF_CONTROL_RESAMPLE_RATE | AF_CONTROL_SET:
+ af->data->rate = *(int*)arg;
+ return AF_OK;
+ }
+ return AF_UNKNOWN;
+}
+
+// Deallocate memory
+static void uninit(struct af_instance* af)
+{
+ if(af->data)
+ free(af->data->audio);
+ free(af->data);
+ if(af->setup){
+ int i;
+ af_resample_t *s = af->setup;
+ if(s->avrctx) av_resample_close(s->avrctx);
+ for (i=0; i < AF_NCH; i++)
+ free(s->in[i]);
+ free(s);
+ }
+}
+
+// Filter data through filter
+static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
+{
+ af_resample_t *s = af->setup;
+ int i, j, consumed, ret = 0;
+ int16_t *in = (int16_t*)data->audio;
+ int16_t *out;
+ int chans = data->nch;
+ int in_len = data->len/(2*chans);
+ int out_len = in_len * af->mul + 10;
+ int16_t tmp[AF_NCH][out_len];
+
+ if(AF_OK != RESIZE_LOCAL_BUFFER(af,data))
+ return NULL;
+
+ out= (int16_t*)af->data->audio;
+
+ out_len= min(out_len, af->data->len/(2*chans));
+
+ if(s->in_alloc < in_len + s->index){
+ s->in_alloc= in_len + s->index;
+ for(i=0; i<chans; i++){
+ s->in[i]= realloc(s->in[i], s->in_alloc*sizeof(int16_t));
+ }
+ }
+
+ if(chans==1){
+ memcpy(&s->in[0][s->index], in, in_len * sizeof(int16_t));
+ }else if(chans==2){
+ for(j=0; j<in_len; j++){
+ s->in[0][j + s->index]= *(in++);
+ s->in[1][j + s->index]= *(in++);
+ }
+ }else{
+ for(j=0; j<in_len; j++){
+ for(i=0; i<chans; i++){
+ s->in[i][j + s->index]= *(in++);
+ }
+ }
+ }
+ in_len += s->index;
+
+ for(i=0; i<chans; i++){
+ ret= av_resample(s->avrctx, tmp[i], s->in[i], &consumed, in_len, out_len, i+1 == chans);
+ }
+ out_len= ret;
+
+ s->index= in_len - consumed;
+ for(i=0; i<chans; i++){
+ memmove(s->in[i], s->in[i] + consumed, s->index*sizeof(int16_t));
+ }
+
+ if(chans==1){
+ memcpy(out, tmp[0], out_len*sizeof(int16_t));
+ }else if(chans==2){
+ for(j=0; j<out_len; j++){
+ *(out++)= tmp[0][j];
+ *(out++)= tmp[1][j];
+ }
+ }else{
+ for(j=0; j<out_len; j++){
+ for(i=0; i<chans; i++){
+ *(out++)= tmp[i][j];
+ }
+ }
+ }
+
+ data->audio = af->data->audio;
+ data->len = out_len*chans*2;
+ data->rate = af->data->rate;
+ return data;
+}
+
+static int af_open(struct af_instance* af){
+ af_resample_t *s = calloc(1,sizeof(af_resample_t));
+ af->control=control;
+ af->uninit=uninit;
+ af->play=play;
+ af->mul=1;
+ af->data=calloc(1,sizeof(struct mp_audio));
+ s->filter_length= 16;
+ s->cutoff= max(1.0 - 6.5/(s->filter_length+8), 0.80);
+ s->phase_shift= 10;
+// s->setup = RSMP_INT | FREQ_SLOPPY;
+ af->setup=s;
+ return AF_OK;
+}
+
+struct af_info af_info_lavcresample = {
+ "Sample frequency conversion using libavcodec",
+ "lavcresample",
+ "Michael Niedermayer",
+ "",
+ AF_FLAGS_REENTRANT,
+ af_open
+};
diff --git a/audio/filter/af_pan.c b/audio/filter/af_pan.c
new file mode 100644
index 0000000000..8b1783ee84
--- /dev/null
+++ b/audio/filter/af_pan.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2002 Anders Johansson ajh@atri.curtin.edu.au
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <inttypes.h>
+#include <math.h>
+#include <limits.h>
+
+#include "af.h"
+
+// Data for specific instances of this filter
+typedef struct af_pan_s
+{
+ int nch; // Number of output channels; zero means same as input
+ float level[AF_NCH][AF_NCH]; // Gain level for each channel
+}af_pan_t;
+
+// Initialization and runtime control
+static int control(struct af_instance* af, int cmd, void* arg)
+{
+ af_pan_t* s = af->setup;
+
+ switch(cmd){
+ case AF_CONTROL_REINIT:
+ // Sanity check
+ if(!arg) return AF_ERROR;
+
+ af->data->rate = ((struct mp_audio*)arg)->rate;
+ af->data->format = AF_FORMAT_FLOAT_NE;
+ af->data->bps = 4;
+ af->data->nch = s->nch ? s->nch: ((struct mp_audio*)arg)->nch;
+ af->mul = (double)af->data->nch / ((struct mp_audio*)arg)->nch;
+
+ if((af->data->format != ((struct mp_audio*)arg)->format) ||
+ (af->data->bps != ((struct mp_audio*)arg)->bps)){
+ ((struct mp_audio*)arg)->format = af->data->format;
+ ((struct mp_audio*)arg)->bps = af->data->bps;
+ return AF_FALSE;
+ }
+ return AF_OK;
+ case AF_CONTROL_COMMAND_LINE:{
+ int nch = 0;
+ int n = 0;
+ char* cp = NULL;
+ int j,k;
+ // Read number of outputs
+ sscanf((char*)arg,"%i%n", &nch,&n);
+ if(AF_OK != control(af,AF_CONTROL_PAN_NOUT | AF_CONTROL_SET, &nch))
+ return AF_ERROR;
+
+ // Read pan values
+ cp = &((char*)arg)[n];
+ j = 0; k = 0;
+ while((*cp == ':') && (k < AF_NCH)){
+ sscanf(cp, ":%f%n" , &s->level[j][k], &n);
+ mp_msg(MSGT_AFILTER, MSGL_V, "[pan] Pan level from channel %i to"
+ " channel %i = %f\n",k,j,s->level[j][k]);
+ cp =&cp[n];
+ j++;
+ if(j>=nch){
+ j = 0;
+ k++;
+ }
+ }
+ return AF_OK;
+ }
+ case AF_CONTROL_PAN_LEVEL | AF_CONTROL_SET:{
+ int i;
+ int ch = ((af_control_ext_t*)arg)->ch;
+ float* level = ((af_control_ext_t*)arg)->arg;
+ if (ch >= AF_NCH)
+ return AF_FALSE;
+ for(i=0;i<AF_NCH;i++)
+ s->level[ch][i] = level[i];
+ return AF_OK;
+ }
+ case AF_CONTROL_PAN_LEVEL | AF_CONTROL_GET:{
+ int i;
+ int ch = ((af_control_ext_t*)arg)->ch;
+ float* level = ((af_control_ext_t*)arg)->arg;
+ if (ch >= AF_NCH)
+ return AF_FALSE;
+ for(i=0;i<AF_NCH;i++)
+ level[i] = s->level[ch][i];
+ return AF_OK;
+ }
+ case AF_CONTROL_PAN_NOUT | AF_CONTROL_SET:
+ // Reinit must be called after this function has been called
+
+ // Sanity check
+ if(((int*)arg)[0] <= 0 || ((int*)arg)[0] > AF_NCH){
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[pan] The number of output channels must be"
+ " between 1 and %i. Current value is %i\n",AF_NCH,((int*)arg)[0]);
+ return AF_ERROR;
+ }
+ s->nch=((int*)arg)[0];
+ return AF_OK;
+ case AF_CONTROL_PAN_NOUT | AF_CONTROL_GET:
+ *(int*)arg = af->data->nch;
+ return AF_OK;
+ case AF_CONTROL_PAN_BALANCE | AF_CONTROL_SET:{
+ float val = *(float*)arg;
+ if (s->nch)
+ return AF_ERROR;
+ if (af->data->nch >= 2) {
+ s->level[0][0] = min(1.f, 1.f - val);
+ s->level[0][1] = max(0.f, val);
+ s->level[1][0] = max(0.f, -val);
+ s->level[1][1] = min(1.f, 1.f + val);
+ }
+ return AF_OK;
+ }
+ case AF_CONTROL_PAN_BALANCE | AF_CONTROL_GET:
+ if (s->nch)
+ return AF_ERROR;
+ *(float*)arg = s->level[0][1] - s->level[1][0];
+ return AF_OK;
+ }
+ return AF_UNKNOWN;
+}
+
+// Deallocate memory
+static void uninit(struct af_instance* af)
+{
+ if(af->data)
+ free(af->data->audio);
+ free(af->data);
+ free(af->setup);
+}
+
+// Filter data through filter
+static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
+{
+ struct mp_audio* c = data; // Current working data
+ struct mp_audio* l = af->data; // Local data
+ af_pan_t* s = af->setup; // Setup for this instance
+ float* in = c->audio; // Input audio data
+ float* out = NULL; // Output audio data
+ float* end = in+c->len/4; // End of loop
+ int nchi = c->nch; // Number of input channels
+ int ncho = l->nch; // Number of output channels
+ register int j,k;
+
+ if(AF_OK != RESIZE_LOCAL_BUFFER(af,data))
+ return NULL;
+
+ out = l->audio;
+ // Execute panning
+ // FIXME: Too slow
+ while(in < end){
+ for(j=0;j<ncho;j++){
+ register float x = 0.0;
+ register float* tin = in;
+ for(k=0;k<nchi;k++)
+ x += tin[k] * s->level[j][k];
+ out[j] = x;
+ }
+ out+= ncho;
+ in+= nchi;
+ }
+
+ // Set output data
+ c->audio = l->audio;
+ c->len = c->len / c->nch * l->nch;
+ c->nch = l->nch;
+
+ return c;
+}
+
+// Allocate memory and set function pointers
+static int af_open(struct af_instance* af){
+ af->control=control;
+ af->uninit=uninit;
+ af->play=play;
+ af->mul=1;
+ af->data=calloc(1,sizeof(struct mp_audio));
+ af->setup=calloc(1,sizeof(af_pan_t));
+ if(af->data == NULL || af->setup == NULL)
+ return AF_ERROR;
+ return AF_OK;
+}
+
+// Description of this filter
+struct af_info af_info_pan = {
+ "Panning audio filter",
+ "pan",
+ "Anders",
+ "",
+ AF_FLAGS_REENTRANT,
+ af_open
+};
diff --git a/audio/filter/af_resample.c b/audio/filter/af_resample.c
new file mode 100644
index 0000000000..1f0b7cc942
--- /dev/null
+++ b/audio/filter/af_resample.c
@@ -0,0 +1,394 @@
+/*
+ * This audio filter changes the sample rate.
+ *
+ * Copyright (C) 2002 Anders Johansson ajh@atri.curtin.edu.au
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include "libavutil/common.h"
+#include "libavutil/mathematics.h"
+#include "af.h"
+#include "dsp.h"
+
+/* Below definition selects the length of each poly phase component.
+ Valid definitions are L8 and L16, where the number denotes the
+ length of the filter. This definition affects the computational
+ complexity (see play()), the performance (see filter.h) and the
+ memory usage. The filter length is chosen to 8 if the machine is
+ slow and to 16 if the machine is fast and has MMX.
+*/
+
+#if !HAVE_MMX // This machine is slow
+#define L8
+#else
+#define L16
+#endif
+
+#include "af_resample_template.c"
+
+// Filtering types
+#define RSMP_LIN (0<<0) // Linear interpolation
+#define RSMP_INT (1<<0) // 16 bit integer
+#define RSMP_FLOAT (2<<0) // 32 bit floating point
+#define RSMP_MASK (3<<0)
+
+// Defines for sloppy or exact resampling
+#define FREQ_SLOPPY (0<<2)
+#define FREQ_EXACT (1<<2)
+#define FREQ_MASK (1<<2)
+
+// Accuracy for linear interpolation
+#define STEPACCURACY 32
+
+// local data
+typedef struct af_resample_s
+{
+ void* w; // Current filter weights
+ void** xq; // Circular buffers
+ uint32_t xi; // Index for circular buffers
+ uint32_t wi; // Index for w
+ uint32_t i; // Number of new samples to put in x queue
+ uint32_t dn; // Down sampling factor
+ uint32_t up; // Up sampling factor
+ uint64_t step; // Step size for linear interpolation
+ uint64_t pt; // Pointer remainder for linear interpolation
+ int setup; // Setup parameters cmdline or through postcreate
+} af_resample_t;
+
+// Fast linear interpolation resample with modest audio quality
+static int linint(struct mp_audio* c,struct mp_audio* l, af_resample_t* s)
+{
+ uint32_t len = 0; // Number of input samples
+ uint32_t nch = l->nch; // Words pre transfer
+ uint64_t step = s->step;
+ int16_t* in16 = ((int16_t*)c->audio);
+ int16_t* out16 = ((int16_t*)l->audio);
+ int32_t* in32 = ((int32_t*)c->audio);
+ int32_t* out32 = ((int32_t*)l->audio);
+ uint64_t end = ((((uint64_t)c->len)/2LL)<<STEPACCURACY);
+ uint64_t pt = s->pt;
+ uint16_t tmp;
+
+ switch (nch){
+ case 1:
+ while(pt < end){
+ out16[len++]=in16[pt>>STEPACCURACY];
+ pt+=step;
+ }
+ s->pt=pt & ((1LL<<STEPACCURACY)-1);
+ break;
+ case 2:
+ end/=2;
+ while(pt < end){
+ out32[len++]=in32[pt>>STEPACCURACY];
+ pt+=step;
+ }
+ len=(len<<1);
+ s->pt=pt & ((1LL<<STEPACCURACY)-1);
+ break;
+ default:
+ end /=nch;
+ while(pt < end){
+ tmp=nch;
+ do {
+ tmp--;
+ out16[len+tmp]=in16[tmp+(pt>>STEPACCURACY)*nch];
+ } while (tmp);
+ len+=nch;
+ pt+=step;
+ }
+ s->pt=pt & ((1LL<<STEPACCURACY)-1);
+ }
+ return len;
+}
+
+/* Determine resampling type and format */
+static int set_types(struct af_instance* af, struct mp_audio* data)
+{
+ af_resample_t* s = af->setup;
+ int rv = AF_OK;
+ float rd = 0;
+
+ // Make sure this filter isn't redundant
+ if((af->data->rate == data->rate) || (af->data->rate == 0))
+ return AF_DETACH;
+ /* If sloppy and small resampling difference (2%) */
+ rd = abs((float)af->data->rate - (float)data->rate)/(float)data->rate;
+ if((((s->setup & FREQ_MASK) == FREQ_SLOPPY) && (rd < 0.02) &&
+ (data->format != (AF_FORMAT_FLOAT_NE))) ||
+ ((s->setup & RSMP_MASK) == RSMP_LIN)){
+ s->setup = (s->setup & ~RSMP_MASK) | RSMP_LIN;
+ af->data->format = AF_FORMAT_S16_NE;
+ af->data->bps = 2;
+ mp_msg(MSGT_AFILTER, MSGL_V, "[resample] Using linear interpolation. \n");
+ }
+ else{
+ /* If the input format is float or if float is explicitly selected
+ use float, otherwise use int */
+ if((data->format == (AF_FORMAT_FLOAT_NE)) ||
+ ((s->setup & RSMP_MASK) == RSMP_FLOAT)){
+ s->setup = (s->setup & ~RSMP_MASK) | RSMP_FLOAT;
+ af->data->format = AF_FORMAT_FLOAT_NE;
+ af->data->bps = 4;
+ }
+ else{
+ s->setup = (s->setup & ~RSMP_MASK) | RSMP_INT;
+ af->data->format = AF_FORMAT_S16_NE;
+ af->data->bps = 2;
+ }
+ mp_msg(MSGT_AFILTER, MSGL_V, "[resample] Using %s processing and %s frequecy"
+ " conversion.\n",
+ ((s->setup & RSMP_MASK) == RSMP_FLOAT)?"floating point":"integer",
+ ((s->setup & FREQ_MASK) == FREQ_SLOPPY)?"inexact":"exact");
+ }
+
+ if(af->data->format != data->format || af->data->bps != data->bps)
+ rv = AF_FALSE;
+ data->format = af->data->format;
+ data->bps = af->data->bps;
+ af->data->nch = data->nch;
+ return rv;
+}
+
+// Initialization and runtime control
+static int control(struct af_instance* af, int cmd, void* arg)
+{
+ switch(cmd){
+ case AF_CONTROL_REINIT:{
+ af_resample_t* s = af->setup;
+ struct mp_audio* n = arg; // New configuration
+ int i,d = 0;
+ int rv = AF_OK;
+
+ // Free space for circular buffers
+ if(s->xq){
+ free(s->xq[0]);
+ free(s->xq);
+ s->xq = NULL;
+ }
+
+ if(AF_DETACH == (rv = set_types(af,n)))
+ return AF_DETACH;
+
+ // If linear interpolation
+ if((s->setup & RSMP_MASK) == RSMP_LIN){
+ s->pt=0LL;
+ s->step=((uint64_t)n->rate<<STEPACCURACY)/(uint64_t)af->data->rate+1LL;
+ mp_msg(MSGT_AFILTER, MSGL_DBG2, "[resample] Linear interpolation step: 0x%016"PRIX64".\n",
+ s->step);
+ af->mul = (double)af->data->rate / n->rate;
+ return rv;
+ }
+
+ // Calculate up and down sampling factors
+ d=av_gcd(af->data->rate,n->rate);
+
+ // If sloppy resampling is enabled limit the upsampling factor
+ if(((s->setup & FREQ_MASK) == FREQ_SLOPPY) && (af->data->rate/d > 5000)){
+ int up=af->data->rate/2;
+ int dn=n->rate/2;
+ int m=2;
+ while(af->data->rate/(d*m) > 5000){
+ d=av_gcd(up,dn);
+ up/=2; dn/=2; m*=2;
+ }
+ d*=m;
+ }
+
+ // Create space for circular buffers
+ s->xq = malloc(n->nch*sizeof(void*));
+ s->xq[0] = calloc(n->nch, 2*L*af->data->bps);
+ for(i=1;i<n->nch;i++)
+ s->xq[i] = (uint8_t *)s->xq[i-1] + 2*L*af->data->bps;
+ s->xi = 0;
+
+ // Check if the design needs to be redone
+ if(s->up != af->data->rate/d || s->dn != n->rate/d){
+ float* w;
+ float* wt;
+ float fc;
+ int j;
+ s->up = af->data->rate/d;
+ s->dn = n->rate/d;
+ s->wi = 0;
+ s->i = 0;
+
+ // Calculate cutoff frequency for filter
+ fc = 1/(float)(max(s->up,s->dn));
+ // Allocate space for polyphase filter bank and prototype filter
+ w = malloc(sizeof(float) * s->up *L);
+ free(s->w);
+ s->w = malloc(L*s->up*af->data->bps);
+
+ // Design prototype filter type using Kaiser window with beta = 10
+ if(NULL == w || NULL == s->w ||
+ -1 == af_filter_design_fir(s->up*L, w, &fc, LP|KAISER , 10.0)){
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[resample] Unable to design prototype filter.\n");
+ return AF_ERROR;
+ }
+ // Copy data from prototype to polyphase filter
+ wt=w;
+ for(j=0;j<L;j++){//Columns
+ for(i=0;i<s->up;i++){//Rows
+ if((s->setup & RSMP_MASK) == RSMP_INT){
+ float t=(float)s->up*32767.0*(*wt);
+ ((int16_t*)s->w)[i*L+j] = (int16_t)((t>=0.0)?(t+0.5):(t-0.5));
+ }
+ else
+ ((float*)s->w)[i*L+j] = (float)s->up*(*wt);
+ wt++;
+ }
+ }
+ free(w);
+ mp_msg(MSGT_AFILTER, MSGL_V, "[resample] New filter designed up: %i "
+ "down: %i\n", s->up, s->dn);
+ }
+
+ // Set multiplier and delay
+ af->delay = 0; // not set correctly, but shouldn't be too large anyway
+ af->mul = (double)s->up / s->dn;
+ return rv;
+ }
+ case AF_CONTROL_COMMAND_LINE:{
+ af_resample_t* s = af->setup;
+ int rate=0;
+ int type=RSMP_INT;
+ int sloppy=1;
+ sscanf((char*)arg,"%i:%i:%i", &rate, &sloppy, &type);
+ s->setup = (sloppy?FREQ_SLOPPY:FREQ_EXACT) |
+ (clamp(type,RSMP_LIN,RSMP_FLOAT));
+ return af->control(af,AF_CONTROL_RESAMPLE_RATE | AF_CONTROL_SET, &rate);
+ }
+ case AF_CONTROL_POST_CREATE:
+ if((((struct af_cfg*)arg)->force & AF_INIT_FORMAT_MASK) == AF_INIT_FLOAT)
+ ((af_resample_t*)af->setup)->setup = RSMP_FLOAT;
+ return AF_OK;
+ case AF_CONTROL_RESAMPLE_RATE | AF_CONTROL_SET:
+ // Reinit must be called after this function has been called
+
+ // Sanity check
+ if(((int*)arg)[0] < 8000 || ((int*)arg)[0] > 192000){
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[resample] The output sample frequency "
+ "must be between 8kHz and 192kHz. Current value is %i \n",
+ ((int*)arg)[0]);
+ return AF_ERROR;
+ }
+
+ af->data->rate=((int*)arg)[0];
+ mp_msg(MSGT_AFILTER, MSGL_V, "[resample] Changing sample rate "
+ "to %iHz\n",af->data->rate);
+ return AF_OK;
+ }
+ return AF_UNKNOWN;
+}
+
+// Deallocate memory
+static void uninit(struct af_instance* af)
+{
+ af_resample_t *s = af->setup;
+ if (s) {
+ if (s->xq) free(s->xq[0]);
+ free(s->xq);
+ free(s->w);
+ free(s);
+ }
+ if(af->data)
+ free(af->data->audio);
+ free(af->data);
+}
+
+// Filter data through filter
+static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
+{
+ int len = 0; // Length of output data
+ struct mp_audio* c = data; // Current working data
+ struct mp_audio* l = af->data; // Local data
+ af_resample_t* s = af->setup;
+
+ if(AF_OK != RESIZE_LOCAL_BUFFER(af,data))
+ return NULL;
+
+ // Run resampling
+ switch(s->setup & RSMP_MASK){
+ case(RSMP_INT):
+# define FORMAT_I 1
+ if(s->up>s->dn){
+# define UP
+# include "af_resample_template.c"
+# undef UP
+ }
+ else{
+# define DN
+# include "af_resample_template.c"
+# undef DN
+ }
+ break;
+ case(RSMP_FLOAT):
+# undef FORMAT_I
+# define FORMAT_F 1
+ if(s->up>s->dn){
+# define UP
+# include "af_resample_template.c"
+# undef UP
+ }
+ else{
+# define DN
+# include "af_resample_template.c"
+# undef DN
+ }
+ break;
+ case(RSMP_LIN):
+ len = linint(c, l, s);
+ break;
+ }
+
+ // Set output data
+ c->audio = l->audio;
+ c->len = len*l->bps;
+ c->rate = l->rate;
+
+ return c;
+}
+
+// Allocate memory and set function pointers
+static int af_open(struct af_instance* af){
+ af->control=control;
+ af->uninit=uninit;
+ af->play=play;
+ af->mul=1;
+ af->data=calloc(1,sizeof(struct mp_audio));
+ af->setup=calloc(1,sizeof(af_resample_t));
+ if(af->data == NULL || af->setup == NULL)
+ return AF_ERROR;
+ ((af_resample_t*)af->setup)->setup = RSMP_INT | FREQ_SLOPPY;
+ return AF_OK;
+}
+
+// Description of this plugin
+struct af_info af_info_resample = {
+ "Sample frequency conversion",
+ "resample",
+ "Anders",
+ "",
+ AF_FLAGS_REENTRANT,
+ af_open
+};
diff --git a/audio/filter/af_resample_template.c b/audio/filter/af_resample_template.c
new file mode 100644
index 0000000000..4d4c5922ca
--- /dev/null
+++ b/audio/filter/af_resample_template.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2002 Anders Johansson ajh@atri.curtin.edu.au
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* This file contains the resampling engine, the sample format is
+ controlled by the FORMAT parameter, the filter length by the L
+ parameter and the resampling type by UP and DN. This file should
+ only be included by af_resample.c
+*/
+
+#undef L
+#undef SHIFT
+#undef FORMAT
+#undef FIR
+#undef ADDQUE
+
+/* The length Lxx definition selects the length of each poly phase
+ component. Valid definitions are L8 and L16 where the number
+ defines the nuber of taps. This definition affects the
+ computational complexity, the performance and the memory usage.
+*/
+
+/* The FORMAT_x parameter selects the sample format type currently
+ float and int16 are supported. Thes two formats are selected by
+ defining eiter FORMAT_F or FORMAT_I. The advantage of using float
+ is that the amplitude and therefore the SNR isn't affected by the
+ filtering, the disadvantage is that it is a lot slower.
+*/
+
+#if defined(FORMAT_I)
+#define SHIFT >>16
+#define FORMAT int16_t
+#else
+#define SHIFT
+#define FORMAT float
+#endif
+
+// Short filter
+#if defined(L8)
+
+#define L 8 // Filter length
+// Unrolled loop to speed up execution
+#define FIR(x,w,y) \
+ (y[0]) = ( w[0]*x[0]+w[1]*x[1]+w[2]*x[2]+w[3]*x[3] \
+ + w[4]*x[4]+w[5]*x[5]+w[6]*x[6]+w[7]*x[7] ) SHIFT
+
+
+
+#else /* L8/L16 */
+
+#define L 16
+// Unrolled loop to speed up execution
+#define FIR(x,w,y) \
+ y[0] = ( w[0] *x[0] +w[1] *x[1] +w[2] *x[2] +w[3] *x[3] \
+ + w[4] *x[4] +w[5] *x[5] +w[6] *x[6] +w[7] *x[7] \
+ + w[8] *x[8] +w[9] *x[9] +w[10]*x[10]+w[11]*x[11] \
+ + w[12]*x[12]+w[13]*x[13]+w[14]*x[14]+w[15]*x[15] ) SHIFT
+
+#endif /* L8/L16 */
+
+// Macro to add data to circular que
+#define ADDQUE(xi,xq,in)\
+ xq[xi]=xq[(xi)+L]=*(in);\
+ xi=((xi)-1)&(L-1);
+
+#if defined(UP)
+
+ uint32_t ci = l->nch; // Index for channels
+ uint32_t nch = l->nch; // Number of channels
+ uint32_t inc = s->up/s->dn;
+ uint32_t level = s->up%s->dn;
+ uint32_t up = s->up;
+ uint32_t dn = s->dn;
+ uint32_t ns = c->len/l->bps;
+ register FORMAT* w = s->w;
+
+ register uint32_t wi = 0;
+ register uint32_t xi = 0;
+
+ // Index current channel
+ while(ci--){
+ // Temporary pointers
+ register FORMAT* x = s->xq[ci];
+ register FORMAT* in = ((FORMAT*)c->audio)+ci;
+ register FORMAT* out = ((FORMAT*)l->audio)+ci;
+ FORMAT* end = in+ns; // Block loop end
+ wi = s->wi; xi = s->xi;
+
+ while(in < end){
+ register uint32_t i = inc;
+ if(wi<level) i++;
+
+ ADDQUE(xi,x,in);
+ in+=nch;
+ while(i--){
+ // Run the FIR filter
+ FIR((&x[xi]),(&w[wi*L]),out);
+ len++; out+=nch;
+ // Update wi to point at the correct polyphase component
+ wi=(wi+dn)%up;
+ }
+ }
+
+ }
+ // Save values that needs to be kept for next time
+ s->wi = wi;
+ s->xi = xi;
+#endif /* UP */
+
+#if defined(DN) /* DN */
+ uint32_t ci = l->nch; // Index for channels
+ uint32_t nch = l->nch; // Number of channels
+ uint32_t inc = s->dn/s->up;
+ uint32_t level = s->dn%s->up;
+ uint32_t up = s->up;
+ uint32_t dn = s->dn;
+ uint32_t ns = c->len/l->bps;
+ FORMAT* w = s->w;
+
+ register int32_t i = 0;
+ register uint32_t wi = 0;
+ register uint32_t xi = 0;
+
+ // Index current channel
+ while(ci--){
+ // Temporary pointers
+ register FORMAT* x = s->xq[ci];
+ register FORMAT* in = ((FORMAT*)c->audio)+ci;
+ register FORMAT* out = ((FORMAT*)l->audio)+ci;
+ register FORMAT* end = in+ns; // Block loop end
+ i = s->i; wi = s->wi; xi = s->xi;
+
+ while(in < end){
+
+ ADDQUE(xi,x,in);
+ in+=nch;
+ if((--i)<=0){
+ // Run the FIR filter
+ FIR((&x[xi]),(&w[wi*L]),out);
+ len++; out+=nch;
+
+ // Update wi to point at the correct polyphase component
+ wi=(wi+dn)%up;
+
+ // Insert i number of new samples in queue
+ i = inc;
+ if(wi<level) i++;
+ }
+ }
+ }
+ // Save values that needs to be kept for next time
+ s->wi = wi;
+ s->xi = xi;
+ s->i = i;
+#endif /* DN */
diff --git a/audio/filter/af_scaletempo.c b/audio/filter/af_scaletempo.c
new file mode 100644
index 0000000000..0bbc220997
--- /dev/null
+++ b/audio/filter/af_scaletempo.c
@@ -0,0 +1,581 @@
+/*
+ * scaletempo audio filter
+ *
+ * scale tempo while maintaining pitch
+ * (WSOLA technique with cross correlation)
+ * inspired by SoundTouch library by Olli Parviainen
+ *
+ * basic algorithm
+ * - produce 'stride' output samples per loop
+ * - consume stride*scale input samples per loop
+ *
+ * to produce smoother transitions between strides, blend next overlap
+ * samples from last stride with correlated samples of current input
+ *
+ * Copyright (c) 2007 Robert Juliano
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+
+#include "af.h"
+#include "libavutil/common.h"
+#include "subopt-helper.h"
+
+// Data for specific instances of this filter
+typedef struct af_scaletempo_s
+{
+ // stride
+ float scale;
+ float speed;
+ float frames_stride_scaled;
+ float frames_stride_error;
+ int bytes_per_frame;
+ int bytes_stride;
+ float bytes_stride_scaled;
+ int bytes_queue;
+ int bytes_queued;
+ int bytes_to_slide;
+ int8_t* buf_queue;
+ // overlap
+ int samples_overlap;
+ int samples_standing;
+ int bytes_overlap;
+ int bytes_standing;
+ void* buf_overlap;
+ void* table_blend;
+ void (*output_overlap)(struct af_scaletempo_s* s, void* out_buf, int bytes_off);
+ // best overlap
+ int frames_search;
+ int num_channels;
+ void* buf_pre_corr;
+ void* table_window;
+ int (*best_overlap_offset)(struct af_scaletempo_s* s);
+ // command line
+ float scale_nominal;
+ float ms_stride;
+ float percent_overlap;
+ float ms_search;
+ short speed_tempo;
+ short speed_pitch;
+} af_scaletempo_t;
+
+static int fill_queue(struct af_instance* af, struct mp_audio* data, int offset)
+{
+ af_scaletempo_t* s = af->setup;
+ int bytes_in = data->len - offset;
+ int offset_unchanged = offset;
+
+ if (s->bytes_to_slide > 0) {
+ if (s->bytes_to_slide < s->bytes_queued) {
+ int bytes_move = s->bytes_queued - s->bytes_to_slide;
+ memmove(s->buf_queue,
+ s->buf_queue + s->bytes_to_slide,
+ bytes_move);
+ s->bytes_to_slide = 0;
+ s->bytes_queued = bytes_move;
+ } else {
+ int bytes_skip;
+ s->bytes_to_slide -= s->bytes_queued;
+ bytes_skip = FFMIN(s->bytes_to_slide, bytes_in);
+ s->bytes_queued = 0;
+ s->bytes_to_slide -= bytes_skip;
+ offset += bytes_skip;
+ bytes_in -= bytes_skip;
+ }
+ }
+
+ if (bytes_in > 0) {
+ int bytes_copy = FFMIN(s->bytes_queue - s->bytes_queued, bytes_in);
+ assert(bytes_copy >= 0);
+ memcpy(s->buf_queue + s->bytes_queued,
+ (int8_t*)data->audio + offset,
+ bytes_copy);
+ s->bytes_queued += bytes_copy;
+ offset += bytes_copy;
+ }
+
+ return offset - offset_unchanged;
+}
+
+#define UNROLL_PADDING (4*4)
+
+static int best_overlap_offset_float(af_scaletempo_t* s)
+{
+ float *pw, *po, *ppc, *search_start;
+ float best_corr = INT_MIN;
+ int best_off = 0;
+ int i, off;
+
+ pw = s->table_window;
+ po = s->buf_overlap;
+ po += s->num_channels;
+ ppc = s->buf_pre_corr;
+ for (i=s->num_channels; i<s->samples_overlap; i++) {
+ *ppc++ = *pw++ * *po++;
+ }
+
+ search_start = (float*)s->buf_queue + s->num_channels;
+ for (off=0; off<s->frames_search; off++) {
+ float corr = 0;
+ float* ps = search_start;
+ ppc = s->buf_pre_corr;
+ for (i=s->num_channels; i<s->samples_overlap; i++) {
+ corr += *ppc++ * *ps++;
+ }
+ if (corr > best_corr) {
+ best_corr = corr;
+ best_off = off;
+ }
+ search_start += s->num_channels;
+ }
+
+ return best_off * 4 * s->num_channels;
+}
+
+static int best_overlap_offset_s16(af_scaletempo_t* s)
+{
+ int32_t *pw, *ppc;
+ int16_t *po, *search_start;
+ int64_t best_corr = INT64_MIN;
+ int best_off = 0;
+ int off;
+ long i;
+
+ pw = s->table_window;
+ po = s->buf_overlap;
+ po += s->num_channels;
+ ppc = s->buf_pre_corr;
+ for (i=s->num_channels; i<s->samples_overlap; i++) {
+ *ppc++ = ( *pw++ * *po++ ) >> 15;
+ }
+
+ search_start = (int16_t*)s->buf_queue + s->num_channels;
+ for (off=0; off<s->frames_search; off++) {
+ int64_t corr = 0;
+ int16_t* ps = search_start;
+ ppc = s->buf_pre_corr;
+ ppc += s->samples_overlap - s->num_channels;
+ ps += s->samples_overlap - s->num_channels;
+ i = -(s->samples_overlap - s->num_channels);
+ do {
+ corr += ppc[i+0] * ps[i+0];
+ corr += ppc[i+1] * ps[i+1];
+ corr += ppc[i+2] * ps[i+2];
+ corr += ppc[i+3] * ps[i+3];
+ i += 4;
+ } while (i < 0);
+ if (corr > best_corr) {
+ best_corr = corr;
+ best_off = off;
+ }
+ search_start += s->num_channels;
+ }
+
+ return best_off * 2 * s->num_channels;
+}
+
+static void output_overlap_float(af_scaletempo_t* s, void* buf_out,
+ int bytes_off)
+{
+ float* pout = buf_out;
+ float* pb = s->table_blend;
+ float* po = s->buf_overlap;
+ float* pin = (float*)(s->buf_queue + bytes_off);
+ int i;
+ for (i=0; i<s->samples_overlap; i++) {
+ *pout++ = *po - *pb++ * ( *po - *pin++ ); po++;
+ }
+}
+static void output_overlap_s16(af_scaletempo_t* s, void* buf_out,
+ int bytes_off)
+{
+ int16_t* pout = buf_out;
+ int32_t* pb = s->table_blend;
+ int16_t* po = s->buf_overlap;
+ int16_t* pin = (int16_t*)(s->buf_queue + bytes_off);
+ int i;
+ for (i=0; i<s->samples_overlap; i++) {
+ *pout++ = *po - ( ( *pb++ * ( *po - *pin++ ) ) >> 16 ); po++;
+ }
+}
+
+// Filter data through filter
+static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
+{
+ af_scaletempo_t* s = af->setup;
+ int offset_in;
+ int max_bytes_out;
+ int8_t* pout;
+
+ if (s->scale == 1.0) {
+ af->delay = 0;
+ return data;
+ }
+
+ // RESIZE_LOCAL_BUFFER - can't use macro
+ max_bytes_out = ((int)(data->len / s->bytes_stride_scaled) + 1) * s->bytes_stride;
+ if (max_bytes_out > af->data->len) {
+ mp_msg(MSGT_AFILTER, MSGL_V, "[libaf] Reallocating memory in module %s, "
+ "old len = %i, new len = %i\n",af->info->name,af->data->len,max_bytes_out);
+ af->data->audio = realloc(af->data->audio, max_bytes_out);
+ if (!af->data->audio) {
+ mp_msg(MSGT_AFILTER, MSGL_FATAL, "[libaf] Could not allocate memory\n");
+ return NULL;
+ }
+ af->data->len = max_bytes_out;
+ }
+
+ offset_in = fill_queue(af, data, 0);
+ pout = af->data->audio;
+ while (s->bytes_queued >= s->bytes_queue) {
+ int ti;
+ float tf;
+ int bytes_off = 0;
+
+ // output stride
+ if (s->output_overlap) {
+ if (s->best_overlap_offset)
+ bytes_off = s->best_overlap_offset(s);
+ s->output_overlap(s, pout, bytes_off);
+ }
+ memcpy(pout + s->bytes_overlap,
+ s->buf_queue + bytes_off + s->bytes_overlap,
+ s->bytes_standing);
+ pout += s->bytes_stride;
+
+ // input stride
+ memcpy(s->buf_overlap,
+ s->buf_queue + bytes_off + s->bytes_stride,
+ s->bytes_overlap);
+ tf = s->frames_stride_scaled + s->frames_stride_error;
+ ti = (int)tf;
+ s->frames_stride_error = tf - ti;
+ s->bytes_to_slide = ti * s->bytes_per_frame;
+
+ offset_in += fill_queue(af, data, offset_in);
+ }
+
+ // This filter can have a negative delay when scale > 1:
+ // output corresponding to some length of input can be decided and written
+ // after receiving only a part of that input.
+ af->delay = s->bytes_queued - s->bytes_to_slide;
+
+ data->audio = af->data->audio;
+ data->len = pout - (int8_t *)af->data->audio;
+ return data;
+}
+
+// Initialization and runtime control
+static int control(struct af_instance* af, int cmd, void* arg)
+{
+ af_scaletempo_t* s = af->setup;
+ switch(cmd){
+ case AF_CONTROL_REINIT:{
+ struct mp_audio* data = (struct mp_audio*)arg;
+ float srate = data->rate / 1000;
+ int nch = data->nch;
+ int bps;
+ int use_int = 0;
+ int frames_stride, frames_overlap;
+ int i, j;
+
+ mp_msg(MSGT_AFILTER, MSGL_V,
+ "[scaletempo] %.3f speed * %.3f scale_nominal = %.3f\n",
+ s->speed, s->scale_nominal, s->scale);
+
+ if (s->scale == 1.0) {
+ if (s->speed_tempo && s->speed_pitch)
+ return AF_DETACH;
+ memcpy(af->data, data, sizeof(struct mp_audio));
+ af->delay = 0;
+ af->mul = 1;
+ return af_test_output(af, data);
+ }
+
+ af->data->rate = data->rate;
+ af->data->nch = data->nch;
+ if ( data->format == AF_FORMAT_S16_LE
+ || data->format == AF_FORMAT_S16_BE ) {
+ use_int = 1;
+ af->data->format = AF_FORMAT_S16_NE;
+ af->data->bps = bps = 2;
+ } else {
+ af->data->format = AF_FORMAT_FLOAT_NE;
+ af->data->bps = bps = 4;
+ }
+
+ frames_stride = srate * s->ms_stride;
+ s->bytes_stride = frames_stride * bps * nch;
+ s->bytes_stride_scaled = s->scale * s->bytes_stride;
+ s->frames_stride_scaled = s->scale * frames_stride;
+ s->frames_stride_error = 0;
+ af->mul = (double)s->bytes_stride / s->bytes_stride_scaled;
+ af->delay = 0;
+
+ frames_overlap = frames_stride * s->percent_overlap;
+ if (frames_overlap <= 0) {
+ s->bytes_standing = s->bytes_stride;
+ s->samples_standing = s->bytes_standing / bps;
+ s->output_overlap = NULL;
+ s->bytes_overlap = 0;
+ } else {
+ s->samples_overlap = frames_overlap * nch;
+ s->bytes_overlap = frames_overlap * nch * bps;
+ s->bytes_standing = s->bytes_stride - s->bytes_overlap;
+ s->samples_standing = s->bytes_standing / bps;
+ s->buf_overlap = realloc(s->buf_overlap, s->bytes_overlap);
+ s->table_blend = realloc(s->table_blend, s->bytes_overlap * 4);
+ if(!s->buf_overlap || !s->table_blend) {
+ mp_msg(MSGT_AFILTER, MSGL_FATAL, "[scaletempo] Out of memory\n");
+ return AF_ERROR;
+ }
+ memset(s->buf_overlap, 0, s->bytes_overlap);
+ if (use_int) {
+ int32_t* pb = s->table_blend;
+ int64_t blend = 0;
+ for (i=0; i<frames_overlap; i++) {
+ int32_t v = blend / frames_overlap;
+ for (j=0; j<nch; j++) {
+ *pb++ = v;
+ }
+ blend += 65536; // 2^16
+ }
+ s->output_overlap = output_overlap_s16;
+ } else {
+ float* pb = s->table_blend;
+ for (i=0; i<frames_overlap; i++) {
+ float v = i / (float)frames_overlap;
+ for (j=0; j<nch; j++) {
+ *pb++ = v;
+ }
+ }
+ s->output_overlap = output_overlap_float;
+ }
+ }
+
+ s->frames_search = (frames_overlap > 1) ? srate * s->ms_search : 0;
+ if (s->frames_search <= 0) {
+ s->best_overlap_offset = NULL;
+ } else {
+ if (use_int) {
+ int64_t t = frames_overlap;
+ int32_t n = 8589934588LL / (t * t); // 4 * (2^31 - 1) / t^2
+ int32_t* pw;
+ s->buf_pre_corr = realloc(s->buf_pre_corr, s->bytes_overlap * 2 + UNROLL_PADDING);
+ s->table_window = realloc(s->table_window, s->bytes_overlap * 2 - nch * bps * 2);
+ if(!s->buf_pre_corr || !s->table_window) {
+ mp_msg(MSGT_AFILTER, MSGL_FATAL, "[scaletempo] Out of memory\n");
+ return AF_ERROR;
+ }
+ memset((char *)s->buf_pre_corr + s->bytes_overlap * 2, 0, UNROLL_PADDING);
+ pw = s->table_window;
+ for (i=1; i<frames_overlap; i++) {
+ int32_t v = ( i * (t - i) * n ) >> 15;
+ for (j=0; j<nch; j++) {
+ *pw++ = v;
+ }
+ }
+ s->best_overlap_offset = best_overlap_offset_s16;
+ } else {
+ float* pw;
+ s->buf_pre_corr = realloc(s->buf_pre_corr, s->bytes_overlap);
+ s->table_window = realloc(s->table_window, s->bytes_overlap - nch * bps);
+ if(!s->buf_pre_corr || !s->table_window) {
+ mp_msg(MSGT_AFILTER, MSGL_FATAL, "[scaletempo] Out of memory\n");
+ return AF_ERROR;
+ }
+ pw = s->table_window;
+ for (i=1; i<frames_overlap; i++) {
+ float v = i * (frames_overlap - i);
+ for (j=0; j<nch; j++) {
+ *pw++ = v;
+ }
+ }
+ s->best_overlap_offset = best_overlap_offset_float;
+ }
+ }
+
+ s->bytes_per_frame = bps * nch;
+ s->num_channels = nch;
+
+ s->bytes_queue
+ = (s->frames_search + frames_stride + frames_overlap) * bps * nch;
+ s->buf_queue = realloc(s->buf_queue, s->bytes_queue + UNROLL_PADDING);
+ if(!s->buf_queue) {
+ mp_msg(MSGT_AFILTER, MSGL_FATAL, "[scaletempo] Out of memory\n");
+ return AF_ERROR;
+ }
+
+ s->bytes_queued = 0;
+ s->bytes_to_slide = 0;
+
+ mp_msg (MSGT_AFILTER, MSGL_DBG2, "[scaletempo] "
+ "%.2f stride_in, %i stride_out, %i standing, "
+ "%i overlap, %i search, %i queue, %s mode\n",
+ s->frames_stride_scaled,
+ (int)(s->bytes_stride / nch / bps),
+ (int)(s->bytes_standing / nch / bps),
+ (int)(s->bytes_overlap / nch / bps),
+ s->frames_search,
+ (int)(s->bytes_queue / nch / bps),
+ (use_int?"s16":"float"));
+
+ return af_test_output(af, (struct mp_audio*)arg);
+ }
+ case AF_CONTROL_PLAYBACK_SPEED | AF_CONTROL_SET:{
+ if (s->speed_tempo) {
+ if (s->speed_pitch) {
+ break;
+ }
+ s->speed = *(float*)arg;
+ s->scale = s->speed * s->scale_nominal;
+ } else {
+ if (s->speed_pitch) {
+ s->speed = 1 / *(float*)arg;
+ s->scale = s->speed * s->scale_nominal;
+ break;
+ }
+ }
+ return AF_OK;
+ }
+ case AF_CONTROL_SCALETEMPO_AMOUNT | AF_CONTROL_SET:{
+ s->scale = *(float*)arg;
+ s->scale = s->speed * s->scale_nominal;
+ return AF_OK;
+ }
+ case AF_CONTROL_SCALETEMPO_AMOUNT | AF_CONTROL_GET:
+ *(float*)arg = s->scale;
+ return AF_OK;
+ case AF_CONTROL_COMMAND_LINE:{
+ strarg_t speed = {};
+ opt_t subopts[] = {
+ {"scale", OPT_ARG_FLOAT, &s->scale_nominal, NULL},
+ {"stride", OPT_ARG_FLOAT, &s->ms_stride, NULL},
+ {"overlap", OPT_ARG_FLOAT, &s->percent_overlap, NULL},
+ {"search", OPT_ARG_FLOAT, &s->ms_search, NULL},
+ {"speed", OPT_ARG_STR, &speed, NULL},
+ {NULL},
+ };
+ if (subopt_parse(arg, subopts) != 0) {
+ return AF_ERROR;
+ }
+ if (s->scale_nominal <= 0) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[scaletempo] %s: %s: scale > 0\n",
+ mp_gtext("error parsing command line"),
+ mp_gtext("value out of range"));
+ return AF_ERROR;
+ }
+ if (s->ms_stride <= 0) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[scaletempo] %s: %s: stride > 0\n",
+ mp_gtext("error parsing command line"),
+ mp_gtext("value out of range"));
+ return AF_ERROR;
+ }
+ if (s->percent_overlap < 0 || s->percent_overlap > 1) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR,
+ "[scaletempo] %s: %s: 0 <= overlap <= 1\n",
+ mp_gtext("error parsing command line"),
+ mp_gtext("value out of range"));
+ return AF_ERROR;
+ }
+ if (s->ms_search < 0) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[scaletempo] %s: %s: search >= 0\n",
+ mp_gtext("error parsing command line"),
+ mp_gtext("value out of range"));
+ return AF_ERROR;
+ }
+ if (speed.len > 0) {
+ if (strcmp(speed.str, "pitch") == 0) {
+ s->speed_tempo = 0;
+ s->speed_pitch = 1;
+ } else if (strcmp(speed.str, "tempo") == 0) {
+ s->speed_tempo = 1;
+ s->speed_pitch = 0;
+ } else if (strcmp(speed.str, "none") == 0) {
+ s->speed_tempo = 0;
+ s->speed_pitch = 0;
+ } else if (strcmp(speed.str, "both") == 0) {
+ s->speed_tempo = 1;
+ s->speed_pitch = 1;
+ } else {
+ mp_msg(MSGT_AFILTER, MSGL_ERR,
+ "[scaletempo] %s: %s: speed=[pitch|tempo|none|both]\n",
+ mp_gtext("error parsing command line"),
+ mp_gtext("value out of range"));
+ return AF_ERROR;
+ }
+ }
+ s->scale = s->speed * s->scale_nominal;
+ mp_msg(MSGT_AFILTER, MSGL_DBG2, "[scaletempo] %6.3f scale, %6.2f stride, %6.2f overlap, %6.2f search, speed = %s\n", s->scale_nominal, s->ms_stride, s->percent_overlap, s->ms_search, (s->speed_tempo?(s->speed_pitch?"tempo and speed":"tempo"):(s->speed_pitch?"pitch":"none")));
+ return AF_OK;
+ }
+ }
+ return AF_UNKNOWN;
+}
+
+// Deallocate memory
+static void uninit(struct af_instance* af)
+{
+ af_scaletempo_t* s = af->setup;
+ free(af->data->audio);
+ free(af->data);
+ free(s->buf_queue);
+ free(s->buf_overlap);
+ free(s->buf_pre_corr);
+ free(s->table_blend);
+ free(s->table_window);
+ free(af->setup);
+}
+
+// Allocate memory and set function pointers
+static int af_open(struct af_instance* af){
+ af_scaletempo_t* s;
+
+ af->control = control;
+ af->uninit = uninit;
+ af->play = play;
+ af->mul = 1;
+ af->data = calloc(1,sizeof(struct mp_audio));
+ af->setup = calloc(1,sizeof(af_scaletempo_t));
+ if(af->data == NULL || af->setup == NULL)
+ return AF_ERROR;
+
+ s = af->setup;
+ s->scale = s->speed = s->scale_nominal = 1.0;
+ s->speed_tempo = 1;
+ s->speed_pitch = 0;
+ s->ms_stride = 60;
+ s->percent_overlap = .20;
+ s->ms_search = 14;
+
+ return AF_OK;
+}
+
+// Description of this filter
+struct af_info af_info_scaletempo = {
+ "Scale audio tempo while maintaining pitch",
+ "scaletempo",
+ "Robert Juliano",
+ "",
+ AF_FLAGS_REENTRANT,
+ af_open
+};
diff --git a/audio/filter/af_sinesuppress.c b/audio/filter/af_sinesuppress.c
new file mode 100644
index 0000000000..36f7189f00
--- /dev/null
+++ b/audio/filter/af_sinesuppress.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2006 Michael Niedermayer
+ * Copyright (C) 2004 Alex Beregszaszi
+ * based upon af_extrastereo.c by Pierre Lombard
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <inttypes.h>
+#include <math.h>
+#include <limits.h>
+
+#include "af.h"
+
+// Data for specific instances of this filter
+typedef struct af_sinesuppress_s
+{
+ double freq;
+ double decay;
+ double real;
+ double imag;
+ double ref;
+ double pos;
+}af_sinesuppress_t;
+
+static struct mp_audio* play_s16(struct af_instance* af, struct mp_audio* data);
+//static struct mp_audio* play_float(struct af_instance* af, struct mp_audio* data);
+
+// Initialization and runtime control
+static int control(struct af_instance* af, int cmd, void* arg)
+{
+ af_sinesuppress_t* s = (af_sinesuppress_t*)af->setup;
+
+ switch(cmd){
+ case AF_CONTROL_REINIT:{
+ // Sanity check
+ if(!arg) return AF_ERROR;
+
+ af->data->rate = ((struct mp_audio*)arg)->rate;
+ af->data->nch = 1;
+#if 0
+ if (((struct mp_audio*)arg)->format == AF_FORMAT_FLOAT_NE)
+ {
+ af->data->format = AF_FORMAT_FLOAT_NE;
+ af->data->bps = 4;
+ af->play = play_float;
+ }// else
+#endif
+ {
+ af->data->format = AF_FORMAT_S16_NE;
+ af->data->bps = 2;
+ af->play = play_s16;
+ }
+
+ return af_test_output(af,(struct mp_audio*)arg);
+ }
+ case AF_CONTROL_COMMAND_LINE:{
+ float f1,f2;
+ sscanf((char*)arg,"%f:%f", &f1,&f2);
+ s->freq = f1;
+ s->decay = f2;
+ return AF_OK;
+ }
+ case AF_CONTROL_SS_FREQ | AF_CONTROL_SET:
+ s->freq = *(float*)arg;
+ return AF_OK;
+ case AF_CONTROL_SS_FREQ | AF_CONTROL_GET:
+ *(float*)arg = s->freq;
+ return AF_OK;
+ case AF_CONTROL_SS_DECAY | AF_CONTROL_SET:
+ s->decay = *(float*)arg;
+ return AF_OK;
+ case AF_CONTROL_SS_DECAY | AF_CONTROL_GET:
+ *(float*)arg = s->decay;
+ return AF_OK;
+ }
+ return AF_UNKNOWN;
+}
+
+// Deallocate memory
+static void uninit(struct af_instance* af)
+{
+ free(af->data);
+ free(af->setup);
+}
+
+// Filter data through filter
+static struct mp_audio* play_s16(struct af_instance* af, struct mp_audio* data)
+{
+ af_sinesuppress_t *s = af->setup;
+ register int i = 0;
+ int16_t *a = (int16_t*)data->audio; // Audio data
+ int len = data->len/2; // Number of samples
+
+ for (i = 0; i < len; i++)
+ {
+ double co= cos(s->pos);
+ double si= sin(s->pos);
+
+ s->real += co * a[i];
+ s->imag += si * a[i];
+ s->ref += co * co;
+
+ a[i] -= (s->real * co + s->imag * si) / s->ref;
+
+ s->real -= s->real * s->decay;
+ s->imag -= s->imag * s->decay;
+ s->ref -= s->ref * s->decay;
+
+ s->pos += 2 * M_PI * s->freq / data->rate;
+ }
+
+ mp_msg(MSGT_AFILTER, MSGL_V, "[sinesuppress] f:%8.2f: amp:%8.2f\n", s->freq, sqrt(s->real*s->real + s->imag*s->imag) / s->ref);
+
+ return data;
+}
+
+#if 0
+static struct mp_audio* play_float(struct af_instance* af, struct mp_audio* data)
+{
+ af_sinesuppress_t *s = af->setup;
+ register int i = 0;
+ float *a = (float*)data->audio; // Audio data
+ int len = data->len/4; // Number of samples
+ float avg, l, r;
+
+ for (i = 0; i < len; i+=2)
+ {
+ avg = (a[i] + a[i + 1]) / 2;
+
+/* l = avg + (s->mul * (a[i] - avg));
+ r = avg + (s->mul * (a[i + 1] - avg));*/
+
+ a[i] = af_softclip(l);
+ a[i + 1] = af_softclip(r);
+ }
+
+ return data;
+}
+#endif
+
+// Allocate memory and set function pointers
+static int af_open(struct af_instance* af){
+ af->control=control;
+ af->uninit=uninit;
+ af->play=play_s16;
+ af->mul=1;
+ af->data=calloc(1,sizeof(struct mp_audio));
+ af->setup=calloc(1,sizeof(af_sinesuppress_t));
+ if(af->data == NULL || af->setup == NULL)
+ return AF_ERROR;
+
+ ((af_sinesuppress_t*)af->setup)->freq = 50.0;
+ ((af_sinesuppress_t*)af->setup)->decay = 0.0001;
+ return AF_OK;
+}
+
+// Description of this filter
+struct af_info af_info_sinesuppress = {
+ "Sine Suppress",
+ "sinesuppress",
+ "Michael Niedermayer",
+ "",
+ 0,
+ af_open
+};
diff --git a/audio/filter/af_sub.c b/audio/filter/af_sub.c
new file mode 100644
index 0000000000..4af28d9141
--- /dev/null
+++ b/audio/filter/af_sub.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2002 Anders Johansson ajh@watri.uwa.edu.au
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* This filter adds a sub-woofer channels to the audio stream by
+ averaging the left and right channel and low-pass filter them. The
+ low-pass filter is implemented as a 4th order IIR Butterworth
+ filter, with a variable cutoff frequency between 10 and 300 Hz. The
+ filter gives 24dB/octave attenuation. There are two runtime
+ controls one for setting which channel to insert the sub-audio into
+ called AF_CONTROL_SUB_CH and one for setting the cutoff frequency
+ called AF_CONTROL_SUB_FC.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "af.h"
+#include "dsp.h"
+
+// Q value for low-pass filter
+#define Q 1.0
+
+// Analog domain biquad section
+typedef struct{
+ float a[3]; // Numerator coefficients
+ float b[3]; // Denominator coefficients
+} biquad_t;
+
+// S-parameters for designing 4th order Butterworth filter
+static biquad_t sp[2] = {{{1.0,0.0,0.0},{1.0,0.765367,1.0}},
+ {{1.0,0.0,0.0},{1.0,1.847759,1.0}}};
+
+// Data for specific instances of this filter
+typedef struct af_sub_s
+{
+ float w[2][4]; // Filter taps for low-pass filter
+ float q[2][2]; // Circular queues
+ float fc; // Cutoff frequency [Hz] for low-pass filter
+ float k; // Filter gain;
+ int ch; // Channel number which to insert the filtered data
+
+}af_sub_t;
+
+// Initialization and runtime control
+static int control(struct af_instance* af, int cmd, void* arg)
+{
+ af_sub_t* s = af->setup;
+
+ switch(cmd){
+ case AF_CONTROL_REINIT:{
+ // Sanity check
+ if(!arg) return AF_ERROR;
+
+ af->data->rate = ((struct mp_audio*)arg)->rate;
+ af->data->nch = max(s->ch+1,((struct mp_audio*)arg)->nch);
+ af->data->format = AF_FORMAT_FLOAT_NE;
+ af->data->bps = 4;
+
+ // Design low-pass filter
+ s->k = 1.0;
+ if((-1 == af_filter_szxform(sp[0].a, sp[0].b, Q, s->fc,
+ (float)af->data->rate, &s->k, s->w[0])) ||
+ (-1 == af_filter_szxform(sp[1].a, sp[1].b, Q, s->fc,
+ (float)af->data->rate, &s->k, s->w[1])))
+ return AF_ERROR;
+ return af_test_output(af,(struct mp_audio*)arg);
+ }
+ case AF_CONTROL_COMMAND_LINE:{
+ int ch=5;
+ float fc=60.0;
+ sscanf(arg,"%f:%i", &fc , &ch);
+ if(AF_OK != control(af,AF_CONTROL_SUB_CH | AF_CONTROL_SET, &ch))
+ return AF_ERROR;
+ return control(af,AF_CONTROL_SUB_FC | AF_CONTROL_SET, &fc);
+ }
+ case AF_CONTROL_SUB_CH | AF_CONTROL_SET: // Requires reinit
+ // Sanity check
+ if((*(int*)arg >= AF_NCH) || (*(int*)arg < 0)){
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[sub] Subwoofer channel number must be between "
+ " 0 and %i current value is %i\n", AF_NCH-1, *(int*)arg);
+ return AF_ERROR;
+ }
+ s->ch = *(int*)arg;
+ return AF_OK;
+ case AF_CONTROL_SUB_CH | AF_CONTROL_GET:
+ *(int*)arg = s->ch;
+ return AF_OK;
+ case AF_CONTROL_SUB_FC | AF_CONTROL_SET: // Requires reinit
+ // Sanity check
+ if((*(float*)arg > 300) || (*(float*)arg < 20)){
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[sub] Cutoff frequency must be between 20Hz and"
+ " 300Hz current value is %0.2f",*(float*)arg);
+ return AF_ERROR;
+ }
+ // Set cutoff frequency
+ s->fc = *(float*)arg;
+ return AF_OK;
+ case AF_CONTROL_SUB_FC | AF_CONTROL_GET:
+ *(float*)arg = s->fc;
+ return AF_OK;
+ }
+ return AF_UNKNOWN;
+}
+
+// Deallocate memory
+static void uninit(struct af_instance* af)
+{
+ free(af->data);
+ free(af->setup);
+}
+
+#ifndef IIR
+#define IIR(in,w,q,out) { \
+ float h0 = (q)[0]; \
+ float h1 = (q)[1]; \
+ float hn = (in) - h0 * (w)[0] - h1 * (w)[1]; \
+ out = hn + h0 * (w)[2] + h1 * (w)[3]; \
+ (q)[1] = h0; \
+ (q)[0] = hn; \
+}
+#endif
+
+// Filter data through filter
+static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
+{
+ struct mp_audio* c = data; // Current working data
+ af_sub_t* s = af->setup; // Setup for this instance
+ float* a = c->audio; // Audio data
+ int len = c->len/4; // Number of samples in current audio block
+ int nch = c->nch; // Number of channels
+ int ch = s->ch; // Channel in which to insert the sub audio
+ register int i;
+
+ // Run filter
+ for(i=0;i<len;i+=nch){
+ // Average left and right
+ register float x = 0.5 * (a[i] + a[i+1]);
+ IIR(x * s->k, s->w[0], s->q[0], x);
+ IIR(x , s->w[1], s->q[1], a[i+ch]);
+ }
+
+ return c;
+}
+
+// Allocate memory and set function pointers
+static int af_open(struct af_instance* af){
+ af_sub_t* s;
+ af->control=control;
+ af->uninit=uninit;
+ af->play=play;
+ af->mul=1;
+ af->data=calloc(1,sizeof(struct mp_audio));
+ af->setup=s=calloc(1,sizeof(af_sub_t));
+ if(af->data == NULL || af->setup == NULL)
+ return AF_ERROR;
+ // Set default values
+ s->ch = 5; // Channel nr 6
+ s->fc = 60; // Cutoff frequency 60Hz
+ return AF_OK;
+}
+
+// Description of this filter
+struct af_info af_info_sub = {
+ "Audio filter for adding a sub-base channel",
+ "sub",
+ "Anders",
+ "",
+ AF_FLAGS_NOT_REENTRANT,
+ af_open
+};
diff --git a/audio/filter/af_surround.c b/audio/filter/af_surround.c
new file mode 100644
index 0000000000..57288d6ba2
--- /dev/null
+++ b/audio/filter/af_surround.c
@@ -0,0 +1,273 @@
+/*
+ * Filter to do simple decoding of matrixed surround sound.
+ * This will provide a (basic) surround-sound effect from
+ * audio encoded for Dolby Surround, Pro Logic etc.
+ *
+ * original author: Steve Davies <steve@daviesfam.org>
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* The principle: Make rear channels by extracting anti-phase data
+ from the front channels, delay by 20ms and feed to rear in anti-phase
+*/
+
+
+/* SPLITREAR: Define to decode two distinct rear channels - this
+ doesn't work so well in practice because separation in a passive
+ matrix is not high. C (dialogue) to Ls and Rs 14dB or so - so
+ dialogue leaks to the rear. Still - give it a try and send
+ feedback. Comment this define for old behavior of a single
+ surround sent to rear in anti-phase */
+#define SPLITREAR 1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "af.h"
+#include "dsp.h"
+
+#define L 32 // Length of fir filter
+#define LD 65536 // Length of delay buffer
+
+// 32 Tap fir filter loop unrolled
+#define FIR(x,w,y) \
+ y = ( w[0] *x[0] +w[1] *x[1] +w[2] *x[2] +w[3] *x[3] \
+ + w[4] *x[4] +w[5] *x[5] +w[6] *x[6] +w[7] *x[7] \
+ + w[8] *x[8] +w[9] *x[9] +w[10]*x[10]+w[11]*x[11] \
+ + w[12]*x[12]+w[13]*x[13]+w[14]*x[14]+w[15]*x[15] \
+ + w[16]*x[16]+w[17]*x[17]+w[18]*x[18]+w[19]*x[19] \
+ + w[20]*x[20]+w[21]*x[21]+w[22]*x[22]+w[23]*x[23] \
+ + w[24]*x[24]+w[25]*x[25]+w[26]*x[26]+w[27]*x[27] \
+ + w[28]*x[28]+w[29]*x[29]+w[30]*x[30]+w[31]*x[31])
+
+// Add to circular queue macro + update index
+#ifdef SPLITREAR
+#define ADDQUE(qi,rq,lq,r,l)\
+ lq[qi]=lq[qi+L]=(l);\
+ rq[qi]=rq[qi+L]=(r);\
+ qi=(qi-1)&(L-1);
+#else
+#define ADDQUE(qi,lq,l)\
+ lq[qi]=lq[qi+L]=(l);\
+ qi=(qi-1)&(L-1);
+#endif
+
+// Macro for updating queue index in delay queues
+#define UPDATEQI(qi) qi=(qi+1)&(LD-1)
+
+// instance data
+typedef struct af_surround_s
+{
+ float lq[2*L]; // Circular queue for filtering left rear channel
+ float rq[2*L]; // Circular queue for filtering right rear channel
+ float w[L]; // FIR filter coefficients for surround sound 7kHz low-pass
+ float* dr; // Delay queue right rear channel
+ float* dl; // Delay queue left rear channel
+ float d; // Delay time
+ int i; // Position in circular buffer
+ int wi; // Write index for delay queue
+ int ri; // Read index for delay queue
+}af_surround_t;
+
+// Initialization and runtime control
+static int control(struct af_instance* af, int cmd, void* arg)
+{
+ af_surround_t *s = af->setup;
+ switch(cmd){
+ case AF_CONTROL_REINIT:{
+ float fc;
+ af->data->rate = ((struct mp_audio*)arg)->rate;
+ af->data->nch = ((struct mp_audio*)arg)->nch*2;
+ af->data->format = AF_FORMAT_FLOAT_NE;
+ af->data->bps = 4;
+
+ if (af->data->nch != 4){
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[surround] Only stereo input is supported.\n");
+ return AF_DETACH;
+ }
+ // Surround filer coefficients
+ fc = 2.0 * 7000.0/(float)af->data->rate;
+ if (-1 == af_filter_design_fir(L, s->w, &fc, LP|HAMMING, 0)){
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[surround] Unable to design low-pass filter.\n");
+ return AF_ERROR;
+ }
+
+ // Free previous delay queues
+ free(s->dl);
+ free(s->dr);
+ // Allocate new delay queues
+ s->dl = calloc(LD,af->data->bps);
+ s->dr = calloc(LD,af->data->bps);
+ if((NULL == s->dl) || (NULL == s->dr))
+ mp_msg(MSGT_AFILTER, MSGL_FATAL, "[delay] Out of memory\n");
+
+ // Initialize delay queue index
+ if(AF_OK != af_from_ms(1, &s->d, &s->wi, af->data->rate, 0.0, 1000.0))
+ return AF_ERROR;
+// printf("%i\n",s->wi);
+ s->ri = 0;
+
+ if((af->data->format != ((struct mp_audio*)arg)->format) ||
+ (af->data->bps != ((struct mp_audio*)arg)->bps)){
+ ((struct mp_audio*)arg)->format = af->data->format;
+ ((struct mp_audio*)arg)->bps = af->data->bps;
+ return AF_FALSE;
+ }
+ return AF_OK;
+ }
+ case AF_CONTROL_COMMAND_LINE:{
+ float d = 0;
+ sscanf((char*)arg,"%f",&d);
+ if ((d < 0) || (d > 1000)){
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[surround] Invalid delay time, valid time values"
+ " are 0ms to 1000ms current value is %0.3f ms\n",d);
+ return AF_ERROR;
+ }
+ s->d = d;
+ return AF_OK;
+ }
+ }
+ return AF_UNKNOWN;
+}
+
+// Deallocate memory
+static void uninit(struct af_instance* af)
+{
+ if(af->data)
+ free(af->data->audio);
+ free(af->data);
+ free(af->setup);
+}
+
+// The beginnings of an active matrix...
+static float steering_matrix[][12] = {
+// LL RL LR RR LS RS
+// LLs RLs LRs RRs LC RC
+ {.707, .0, .0, .707, .5, -.5,
+ .5878, -.3928, .3928, -.5878, .5, .5},
+};
+
+// Experimental moving average dominance
+//static int amp_L = 0, amp_R = 0, amp_C = 0, amp_S = 0;
+
+// Filter data through filter
+static struct mp_audio* play(struct af_instance* af, struct mp_audio* data){
+ af_surround_t* s = (af_surround_t*)af->setup;
+ float* m = steering_matrix[0];
+ float* in = data->audio; // Input audio data
+ float* out = NULL; // Output audio data
+ float* end = in + data->len / sizeof(float); // Loop end
+ int i = s->i; // Filter queue index
+ int ri = s->ri; // Read index for delay queue
+ int wi = s->wi; // Write index for delay queue
+
+ if (AF_OK != RESIZE_LOCAL_BUFFER(af, data))
+ return NULL;
+
+ out = af->data->audio;
+
+ while(in < end){
+ /* Dominance:
+ abs(in[0]) abs(in[1]);
+ abs(in[0]+in[1]) abs(in[0]-in[1]);
+ 10 * log( abs(in[0]) / (abs(in[1])|1) );
+ 10 * log( abs(in[0]+in[1]) / (abs(in[0]-in[1])|1) ); */
+
+ /* About volume balancing...
+ Surround encoding does the following:
+ Lt=L+.707*C+.707*S, Rt=R+.707*C-.707*S
+ So S should be extracted as:
+ (Lt-Rt)
+ But we are splitting the S to two output channels, so we
+ must take 3dB off as we split it:
+ Ls=Rs=.707*(Lt-Rt)
+ Trouble is, Lt could be +1, Rt -1, so possibility that S will
+ overflow. So to avoid that, we cut L/R by 3dB (*.707), and S by
+ 6dB (/2). This keeps the overall balance, but guarantees no
+ overflow. */
+
+ // Output front left and right
+ out[0] = m[0]*in[0] + m[1]*in[1];
+ out[1] = m[2]*in[0] + m[3]*in[1];
+
+ // Low-pass output @ 7kHz
+ FIR((&s->lq[i]), s->w, s->dl[wi]);
+
+ // Delay output by d ms
+ out[2] = s->dl[ri];
+
+#ifdef SPLITREAR
+ // Low-pass output @ 7kHz
+ FIR((&s->rq[i]), s->w, s->dr[wi]);
+
+ // Delay output by d ms
+ out[3] = s->dr[ri];
+#else
+ out[3] = -out[2];
+#endif
+
+ // Update delay queues indexes
+ UPDATEQI(ri);
+ UPDATEQI(wi);
+
+ // Calculate and save surround in circular queue
+#ifdef SPLITREAR
+ ADDQUE(i, s->rq, s->lq, m[6]*in[0]+m[7]*in[1], m[8]*in[0]+m[9]*in[1]);
+#else
+ ADDQUE(i, s->lq, m[4]*in[0]+m[5]*in[1]);
+#endif
+
+ // Next sample...
+ in = &in[data->nch];
+ out = &out[af->data->nch];
+ }
+
+ // Save indexes
+ s->i = i; s->ri = ri; s->wi = wi;
+
+ // Set output data
+ data->audio = af->data->audio;
+ data->len *= 2;
+ data->nch = af->data->nch;
+
+ return data;
+}
+
+static int af_open(struct af_instance* af){
+ af->control=control;
+ af->uninit=uninit;
+ af->play=play;
+ af->mul=2;
+ af->data=calloc(1,sizeof(struct mp_audio));
+ af->setup=calloc(1,sizeof(af_surround_t));
+ if(af->data == NULL || af->setup == NULL)
+ return AF_ERROR;
+ ((af_surround_t*)af->setup)->d = 20;
+ return AF_OK;
+}
+
+struct af_info af_info_surround =
+{
+ "Surround decoder filter",
+ "surround",
+ "Steve Davies <steve@daviesfam.org>",
+ "",
+ AF_FLAGS_NOT_REENTRANT,
+ af_open
+};
diff --git a/audio/filter/af_sweep.c b/audio/filter/af_sweep.c
new file mode 100644
index 0000000000..6d1106fefc
--- /dev/null
+++ b/audio/filter/af_sweep.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <math.h>
+
+#include "config.h"
+#include "af.h"
+
+typedef struct af_sweep_s{
+ double x;
+ double delta;
+}af_sweept;
+
+
+// Initialization and runtime control
+static int control(struct af_instance* af, int cmd, void* arg)
+{
+ af_sweept* s = (af_sweept*)af->setup;
+ struct mp_audio *data= (struct mp_audio*)arg;
+
+ switch(cmd){
+ case AF_CONTROL_REINIT:
+ af->data->nch = data->nch;
+ af->data->format = AF_FORMAT_S16_NE;
+ af->data->bps = 2;
+ af->data->rate = data->rate;
+
+ return AF_OK;
+ case AF_CONTROL_COMMAND_LINE:
+ sscanf((char*)arg,"%lf", &s->delta);
+ return AF_OK;
+/* case AF_CONTROL_RESAMPLE_RATE | AF_CONTROL_SET:
+ af->data->rate = *(int*)arg;
+ return AF_OK;*/
+ }
+ return AF_UNKNOWN;
+}
+
+// Deallocate memory
+static void uninit(struct af_instance* af)
+{
+ free(af->data);
+ free(af->setup);
+}
+
+// Filter data through filter
+static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
+{
+ af_sweept *s = af->setup;
+ int i, j;
+ int16_t *in = (int16_t*)data->audio;
+ int chans = data->nch;
+ int in_len = data->len/(2*chans);
+
+ for(i=0; i<in_len; i++){
+ for(j=0; j<chans; j++)
+ in[i*chans+j]= 32000*sin(s->x*s->x);
+ s->x += s->delta;
+ if(2*s->x*s->delta >= 3.141592) s->x=0;
+ }
+
+ return data;
+}
+
+static int af_open(struct af_instance* af){
+ af->control=control;
+ af->uninit=uninit;
+ af->play=play;
+ af->mul=1;
+ af->data=calloc(1,sizeof(struct mp_audio));
+ af->setup=calloc(1,sizeof(af_sweept));
+ return AF_OK;
+}
+
+struct af_info af_info_sweep = {
+ "sine sweep",
+ "sweep",
+ "Michael Niedermayer",
+ "",
+ AF_FLAGS_REENTRANT,
+ af_open
+};
diff --git a/audio/filter/af_tools.c b/audio/filter/af_tools.c
new file mode 100644
index 0000000000..0d5dc6c573
--- /dev/null
+++ b/audio/filter/af_tools.c
@@ -0,0 +1,110 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <math.h>
+#include <string.h>
+#include "af.h"
+
+/* Convert to gain value from dB. Returns AF_OK if of and AF_ERROR if
+ fail */
+int af_from_dB(int n, float* in, float* out, float k, float mi, float ma)
+{
+ int i = 0;
+ // Sanity check
+ if(!in || !out)
+ return AF_ERROR;
+
+ for(i=0;i<n;i++){
+ if(in[i]<=-200)
+ out[i]=0.0;
+ else
+ out[i]=pow(10.0,clamp(in[i],mi,ma)/k);
+ }
+ return AF_OK;
+}
+
+/* Convert from gain value to dB. Returns AF_OK if of and AF_ERROR if
+ fail */
+int af_to_dB(int n, float* in, float* out, float k)
+{
+ int i = 0;
+ // Sanity check
+ if(!in || !out)
+ return AF_ERROR;
+
+ for(i=0;i<n;i++){
+ if(in[i] == 0.0)
+ out[i]=-200.0;
+ else
+ out[i]=k*log10(in[i]);
+ }
+ return AF_OK;
+}
+
+/* Convert from ms to sample time */
+int af_from_ms(int n, float* in, int* out, int rate, float mi, float ma)
+{
+ int i = 0;
+ // Sanity check
+ if(!in || !out)
+ return AF_ERROR;
+
+ for(i=0;i<n;i++)
+ out[i]=(int)((float)rate * clamp(in[i],mi,ma)/1000.0);
+
+ return AF_OK;
+}
+
+/* Convert from sample time to ms */
+int af_to_ms(int n, int* in, float* out, int rate)
+{
+ int i = 0;
+ // Sanity check
+ if(!in || !out || !rate)
+ return AF_ERROR;
+
+ for(i=0;i<n;i++)
+ out[i]=1000.0 * (float)in[i]/((float)rate);
+
+ return AF_OK;
+}
+
+/* Helper function for testing the output format */
+int af_test_output(struct af_instance* af, struct mp_audio* out)
+{
+ if((af->data->format != out->format) ||
+ (af->data->bps != out->bps) ||
+ (af->data->rate != out->rate) ||
+ (af->data->nch != out->nch)){
+ memcpy(out,af->data,sizeof(struct mp_audio));
+ return AF_FALSE;
+ }
+ return AF_OK;
+}
+
+/* Soft clipping, the sound of a dream, thanks to Jon Wattes
+ post to Musicdsp.org */
+float af_softclip(float a)
+{
+ if (a >= M_PI/2)
+ return 1.0;
+ else if (a <= -M_PI/2)
+ return -1.0;
+ else
+ return sin(a);
+}
diff --git a/audio/filter/af_volnorm.c b/audio/filter/af_volnorm.c
new file mode 100644
index 0000000000..b4c204d305
--- /dev/null
+++ b/audio/filter/af_volnorm.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2004 Alex Beregszaszi & Pierre Lombard
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <inttypes.h>
+#include <math.h>
+#include <limits.h>
+
+#include "af.h"
+
+// Methods:
+// 1: uses a 1 value memory and coefficients new=a*old+b*cur (with a+b=1)
+// 2: uses several samples to smooth the variations (standard weighted mean
+// on past samples)
+
+// Size of the memory array
+// FIXME: should depend on the frequency of the data (should be a few seconds)
+#define NSAMPLES 128
+
+// If summing all the mem[].len is lower than MIN_SAMPLE_SIZE bytes, then we
+// choose to ignore the computed value as it's not significant enough
+// FIXME: should depend on the frequency of the data (0.5s maybe)
+#define MIN_SAMPLE_SIZE 32000
+
+// mul is the value by which the samples are scaled
+// and has to be in [MUL_MIN, MUL_MAX]
+#define MUL_INIT 1.0
+#define MUL_MIN 0.1
+#define MUL_MAX 5.0
+
+// Silence level
+// FIXME: should be relative to the level of the samples
+#define SIL_S16 (SHRT_MAX * 0.01)
+#define SIL_FLOAT (INT_MAX * 0.01) // FIXME
+
+// smooth must be in ]0.0, 1.0[
+#define SMOOTH_MUL 0.06
+#define SMOOTH_LASTAVG 0.06
+
+#define DEFAULT_TARGET 0.25
+
+// Data for specific instances of this filter
+typedef struct af_volume_s
+{
+ int method; // method used
+ float mul;
+ // method 1
+ float lastavg; // history value of the filter
+ // method 2
+ int idx;
+ struct {
+ float avg; // average level of the sample
+ int len; // sample size (weight)
+ } mem[NSAMPLES];
+ // "Ideal" level
+ float mid_s16;
+ float mid_float;
+}af_volnorm_t;
+
+// Initialization and runtime control
+static int control(struct af_instance* af, int cmd, void* arg)
+{
+ af_volnorm_t* s = (af_volnorm_t*)af->setup;
+
+ switch(cmd){
+ case AF_CONTROL_REINIT:
+ // Sanity check
+ if(!arg) return AF_ERROR;
+
+ af->data->rate = ((struct mp_audio*)arg)->rate;
+ af->data->nch = ((struct mp_audio*)arg)->nch;
+
+ if(((struct mp_audio*)arg)->format == (AF_FORMAT_S16_NE)){
+ af->data->format = AF_FORMAT_S16_NE;
+ af->data->bps = 2;
+ }else{
+ af->data->format = AF_FORMAT_FLOAT_NE;
+ af->data->bps = 4;
+ }
+ return af_test_output(af,(struct mp_audio*)arg);
+ case AF_CONTROL_COMMAND_LINE:{
+ int i = 0;
+ float target = DEFAULT_TARGET;
+ sscanf((char*)arg,"%d:%f", &i, &target);
+ if (i != 1 && i != 2)
+ return AF_ERROR;
+ s->method = i-1;
+ s->mid_s16 = ((float)SHRT_MAX) * target;
+ s->mid_float = ((float)INT_MAX) * target;
+ return AF_OK;
+ }
+ }
+ return AF_UNKNOWN;
+}
+
+// Deallocate memory
+static void uninit(struct af_instance* af)
+{
+ free(af->data);
+ free(af->setup);
+}
+
+static void method1_int16(af_volnorm_t *s, struct mp_audio *c)
+{
+ register int i = 0;
+ int16_t *data = (int16_t*)c->audio; // Audio data
+ int len = c->len/2; // Number of samples
+ float curavg = 0.0, newavg, neededmul;
+ int tmp;
+
+ for (i = 0; i < len; i++)
+ {
+ tmp = data[i];
+ curavg += tmp * tmp;
+ }
+ curavg = sqrt(curavg / (float) len);
+
+ // Evaluate an adequate 'mul' coefficient based on previous state, current
+ // samples level, etc
+
+ if (curavg > SIL_S16)
+ {
+ neededmul = s->mid_s16 / (curavg * s->mul);
+ s->mul = (1.0 - SMOOTH_MUL) * s->mul + SMOOTH_MUL * neededmul;
+
+ // clamp the mul coefficient
+ s->mul = clamp(s->mul, MUL_MIN, MUL_MAX);
+ }
+
+ // Scale & clamp the samples
+ for (i = 0; i < len; i++)
+ {
+ tmp = s->mul * data[i];
+ tmp = clamp(tmp, SHRT_MIN, SHRT_MAX);
+ data[i] = tmp;
+ }
+
+ // Evaulation of newavg (not 100% accurate because of values clamping)
+ newavg = s->mul * curavg;
+
+ // Stores computed values for future smoothing
+ s->lastavg = (1.0 - SMOOTH_LASTAVG) * s->lastavg + SMOOTH_LASTAVG * newavg;
+}
+
+static void method1_float(af_volnorm_t *s, struct mp_audio *c)
+{
+ register int i = 0;
+ float *data = (float*)c->audio; // Audio data
+ int len = c->len/4; // Number of samples
+ float curavg = 0.0, newavg, neededmul, tmp;
+
+ for (i = 0; i < len; i++)
+ {
+ tmp = data[i];
+ curavg += tmp * tmp;
+ }
+ curavg = sqrt(curavg / (float) len);
+
+ // Evaluate an adequate 'mul' coefficient based on previous state, current
+ // samples level, etc
+
+ if (curavg > SIL_FLOAT) // FIXME
+ {
+ neededmul = s->mid_float / (curavg * s->mul);
+ s->mul = (1.0 - SMOOTH_MUL) * s->mul + SMOOTH_MUL * neededmul;
+
+ // clamp the mul coefficient
+ s->mul = clamp(s->mul, MUL_MIN, MUL_MAX);
+ }
+
+ // Scale & clamp the samples
+ for (i = 0; i < len; i++)
+ data[i] *= s->mul;
+
+ // Evaulation of newavg (not 100% accurate because of values clamping)
+ newavg = s->mul * curavg;
+
+ // Stores computed values for future smoothing
+ s->lastavg = (1.0 - SMOOTH_LASTAVG) * s->lastavg + SMOOTH_LASTAVG * newavg;
+}
+
+static void method2_int16(af_volnorm_t *s, struct mp_audio *c)
+{
+ register int i = 0;
+ int16_t *data = (int16_t*)c->audio; // Audio data
+ int len = c->len/2; // Number of samples
+ float curavg = 0.0, newavg, avg = 0.0;
+ int tmp, totallen = 0;
+
+ for (i = 0; i < len; i++)
+ {
+ tmp = data[i];
+ curavg += tmp * tmp;
+ }
+ curavg = sqrt(curavg / (float) len);
+
+ // Evaluate an adequate 'mul' coefficient based on previous state, current
+ // samples level, etc
+ for (i = 0; i < NSAMPLES; i++)
+ {
+ avg += s->mem[i].avg * (float)s->mem[i].len;
+ totallen += s->mem[i].len;
+ }
+
+ if (totallen > MIN_SAMPLE_SIZE)
+ {
+ avg /= (float)totallen;
+ if (avg >= SIL_S16)
+ {
+ s->mul = s->mid_s16 / avg;
+ s->mul = clamp(s->mul, MUL_MIN, MUL_MAX);
+ }
+ }
+
+ // Scale & clamp the samples
+ for (i = 0; i < len; i++)
+ {
+ tmp = s->mul * data[i];
+ tmp = clamp(tmp, SHRT_MIN, SHRT_MAX);
+ data[i] = tmp;
+ }
+
+ // Evaulation of newavg (not 100% accurate because of values clamping)
+ newavg = s->mul * curavg;
+
+ // Stores computed values for future smoothing
+ s->mem[s->idx].len = len;
+ s->mem[s->idx].avg = newavg;
+ s->idx = (s->idx + 1) % NSAMPLES;
+}
+
+static void method2_float(af_volnorm_t *s, struct mp_audio *c)
+{
+ register int i = 0;
+ float *data = (float*)c->audio; // Audio data
+ int len = c->len/4; // Number of samples
+ float curavg = 0.0, newavg, avg = 0.0, tmp;
+ int totallen = 0;
+
+ for (i = 0; i < len; i++)
+ {
+ tmp = data[i];
+ curavg += tmp * tmp;
+ }
+ curavg = sqrt(curavg / (float) len);
+
+ // Evaluate an adequate 'mul' coefficient based on previous state, current
+ // samples level, etc
+ for (i = 0; i < NSAMPLES; i++)
+ {
+ avg += s->mem[i].avg * (float)s->mem[i].len;
+ totallen += s->mem[i].len;
+ }
+
+ if (totallen > MIN_SAMPLE_SIZE)
+ {
+ avg /= (float)totallen;
+ if (avg >= SIL_FLOAT)
+ {
+ s->mul = s->mid_float / avg;
+ s->mul = clamp(s->mul, MUL_MIN, MUL_MAX);
+ }
+ }
+
+ // Scale & clamp the samples
+ for (i = 0; i < len; i++)
+ data[i] *= s->mul;
+
+ // Evaulation of newavg (not 100% accurate because of values clamping)
+ newavg = s->mul * curavg;
+
+ // Stores computed values for future smoothing
+ s->mem[s->idx].len = len;
+ s->mem[s->idx].avg = newavg;
+ s->idx = (s->idx + 1) % NSAMPLES;
+}
+
+// Filter data through filter
+static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
+{
+ af_volnorm_t *s = af->setup;
+
+ if(af->data->format == (AF_FORMAT_S16_NE))
+ {
+ if (s->method)
+ method2_int16(s, data);
+ else
+ method1_int16(s, data);
+ }
+ else if(af->data->format == (AF_FORMAT_FLOAT_NE))
+ {
+ if (s->method)
+ method2_float(s, data);
+ else
+ method1_float(s, data);
+ }
+ return data;
+}
+
+// Allocate memory and set function pointers
+static int af_open(struct af_instance* af){
+ int i = 0;
+ af->control=control;
+ af->uninit=uninit;
+ af->play=play;
+ af->mul=1;
+ af->data=calloc(1,sizeof(struct mp_audio));
+ af->setup=calloc(1,sizeof(af_volnorm_t));
+ if(af->data == NULL || af->setup == NULL)
+ return AF_ERROR;
+
+ ((af_volnorm_t*)af->setup)->mul = MUL_INIT;
+ ((af_volnorm_t*)af->setup)->lastavg = ((float)SHRT_MAX) * DEFAULT_TARGET;
+ ((af_volnorm_t*)af->setup)->idx = 0;
+ ((af_volnorm_t*)af->setup)->mid_s16 = ((float)SHRT_MAX) * DEFAULT_TARGET;
+ ((af_volnorm_t*)af->setup)->mid_float = ((float)INT_MAX) * DEFAULT_TARGET;
+ for (i = 0; i < NSAMPLES; i++)
+ {
+ ((af_volnorm_t*)af->setup)->mem[i].len = 0;
+ ((af_volnorm_t*)af->setup)->mem[i].avg = 0;
+ }
+ return AF_OK;
+}
+
+// Description of this filter
+struct af_info af_info_volnorm = {
+ "Volume normalizer filter",
+ "volnorm",
+ "Alex Beregszaszi & Pierre Lombard",
+ "",
+ AF_FLAGS_NOT_REENTRANT,
+ af_open
+};
diff --git a/audio/filter/af_volume.c b/audio/filter/af_volume.c
new file mode 100644
index 0000000000..ecf181c8b8
--- /dev/null
+++ b/audio/filter/af_volume.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C)2002 Anders Johansson ajh@atri.curtin.edu.au
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* This audio filter changes the volume of the sound, and can be used
+ when the mixer doesn't support the PCM channel. It can handle
+ between 1 and AF_NCH channels. The volume can be adjusted between -60dB
+ to +20dB and is set on a per channels basis. The is accessed through
+ AF_CONTROL_VOLUME_LEVEL.
+
+ The filter has support for soft-clipping, it is enabled by
+ AF_CONTROL_VOLUME_SOFTCLIPP. It has also a probing feature which
+ can be used to measure the power in the audio stream, both an
+ instantaneous value and the maximum value can be probed. The
+ probing is enable by AF_CONTROL_VOLUME_PROBE_ON_OFF and is done on a
+ per channel basis. The result from the probing is obtained using
+ AF_CONTROL_VOLUME_PROBE_GET and AF_CONTROL_VOLUME_PROBE_GET_MAX. The
+ probed values are calculated in dB.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <inttypes.h>
+#include <math.h>
+#include <limits.h>
+
+#include "af.h"
+
+// Data for specific instances of this filter
+typedef struct af_volume_s
+{
+ int enable[AF_NCH]; // Enable/disable / channel
+ float pow[AF_NCH]; // Estimated power level [dB]
+ float max[AF_NCH]; // Max Power level [dB]
+ float level[AF_NCH]; // Gain level for each channel
+ float time; // Forgetting factor for power estimate
+ int soft; // Enable/disable soft clipping
+ int fast; // Use fix-point volume control
+}af_volume_t;
+
+// Initialization and runtime control
+static int control(struct af_instance* af, int cmd, void* arg)
+{
+ af_volume_t* s = (af_volume_t*)af->setup;
+
+ switch(cmd){
+ case AF_CONTROL_REINIT:
+ // Sanity check
+ if(!arg) return AF_ERROR;
+
+ af->data->rate = ((struct mp_audio*)arg)->rate;
+ af->data->nch = ((struct mp_audio*)arg)->nch;
+
+ if(s->fast && (((struct mp_audio*)arg)->format != (AF_FORMAT_FLOAT_NE))){
+ af->data->format = AF_FORMAT_S16_NE;
+ af->data->bps = 2;
+ }
+ else{
+ // Cutoff set to 10Hz for forgetting factor
+ float x = 2.0*M_PI*15.0/(float)af->data->rate;
+ float t = 2.0-cos(x);
+ s->time = 1.0 - (t - sqrt(t*t - 1));
+ mp_msg(MSGT_AFILTER, MSGL_DBG2, "[volume] Forgetting factor = %0.5f\n",s->time);
+ af->data->format = AF_FORMAT_FLOAT_NE;
+ af->data->bps = 4;
+ }
+ return af_test_output(af,(struct mp_audio*)arg);
+ case AF_CONTROL_COMMAND_LINE:{
+ float v=0.0;
+ float vol[AF_NCH];
+ int i;
+ sscanf((char*)arg,"%f:%i", &v, &s->soft);
+ for(i=0;i<AF_NCH;i++) vol[i]=v;
+ return control(af,AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET, vol);
+ }
+ case AF_CONTROL_POST_CREATE:
+ s->fast = ((((struct af_cfg*)arg)->force & AF_INIT_FORMAT_MASK) ==
+ AF_INIT_FLOAT) ? 0 : 1;
+ return AF_OK;
+ case AF_CONTROL_VOLUME_ON_OFF | AF_CONTROL_SET:
+ memcpy(s->enable,(int*)arg,AF_NCH*sizeof(int));
+ return AF_OK;
+ case AF_CONTROL_VOLUME_ON_OFF | AF_CONTROL_GET:
+ memcpy((int*)arg,s->enable,AF_NCH*sizeof(int));
+ return AF_OK;
+ case AF_CONTROL_VOLUME_SOFTCLIP | AF_CONTROL_SET:
+ s->soft = *(int*)arg;
+ return AF_OK;
+ case AF_CONTROL_VOLUME_SOFTCLIP | AF_CONTROL_GET:
+ *(int*)arg = s->soft;
+ return AF_OK;
+ case AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET:
+ return af_from_dB(AF_NCH,(float*)arg,s->level,20.0,-200.0,60.0);
+ case AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_GET:
+ return af_to_dB(AF_NCH,s->level,(float*)arg,20.0);
+ case AF_CONTROL_VOLUME_PROBE | AF_CONTROL_GET:
+ return af_to_dB(AF_NCH,s->pow,(float*)arg,10.0);
+ case AF_CONTROL_VOLUME_PROBE_MAX | AF_CONTROL_GET:
+ return af_to_dB(AF_NCH,s->max,(float*)arg,10.0);
+ case AF_CONTROL_PRE_DESTROY:{
+ float m = 0.0;
+ int i;
+ if(!s->fast){
+ for(i=0;i<AF_NCH;i++)
+ m=max(m,s->max[i]);
+ af_to_dB(1, &m, &m, 10.0);
+ mp_msg(MSGT_AFILTER, MSGL_INFO, "[volume] The maximum volume was %0.2fdB \n", m);
+ }
+ return AF_OK;
+ }
+ }
+ return AF_UNKNOWN;
+}
+
+// Deallocate memory
+static void uninit(struct af_instance* af)
+{
+ free(af->data);
+ free(af->setup);
+}
+
+// Filter data through filter
+static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
+{
+ struct mp_audio* c = data; // Current working data
+ af_volume_t* s = (af_volume_t*)af->setup; // Setup for this instance
+ register int nch = c->nch; // Number of channels
+ register int i = 0;
+
+ // Basic operation volume control only (used on slow machines)
+ if(af->data->format == (AF_FORMAT_S16_NE)){
+ int16_t* a = (int16_t*)c->audio; // Audio data
+ int len = c->len/2; // Number of samples
+ for (int ch = 0; ch < nch; ch++) {
+ int vol = 256.0 * s->level[ch];
+ if (s->enable[ch] && vol != 256) {
+ for(i=ch;i<len;i+=nch){
+ register int x = (a[i] * vol) >> 8;
+ a[i]=clamp(x,SHRT_MIN,SHRT_MAX);
+ }
+ }
+ }
+ }
+ // Machine is fast and data is floating point
+ else if(af->data->format == (AF_FORMAT_FLOAT_NE)){
+ float* a = (float*)c->audio; // Audio data
+ int len = c->len/4; // Number of samples
+ for (int ch = 0; ch < nch; ch++) {
+ // Volume control (fader)
+ if(s->enable[ch]){
+ float t = 1.0 - s->time;
+ for(i=ch;i<len;i+=nch){
+ register float x = a[i];
+ register float pow = x*x;
+ // Check maximum power value
+ if(pow > s->max[ch])
+ s->max[ch] = pow;
+ // Set volume
+ x *= s->level[ch];
+ // Peak meter
+ pow = x*x;
+ if(pow > s->pow[ch])
+ s->pow[ch] = pow;
+ else
+ s->pow[ch] = t*s->pow[ch] + pow*s->time; // LP filter
+ /* Soft clipping, the sound of a dream, thanks to Jon Wattes
+ post to Musicdsp.org */
+ if(s->soft)
+ x=af_softclip(x);
+ // Hard clipping
+ else
+ x=clamp(x,-1.0,1.0);
+ a[i] = x;
+ }
+ }
+ }
+ }
+ return c;
+}
+
+// Allocate memory and set function pointers
+static int af_open(struct af_instance* af){
+ int i = 0;
+ af->control=control;
+ af->uninit=uninit;
+ af->play=play;
+ af->mul=1;
+ af->data=calloc(1,sizeof(struct mp_audio));
+ af->setup=calloc(1,sizeof(af_volume_t));
+ if(af->data == NULL || af->setup == NULL)
+ return AF_ERROR;
+ // Enable volume control and set initial volume to 0dB.
+ for(i=0;i<AF_NCH;i++){
+ ((af_volume_t*)af->setup)->enable[i] = 1;
+ ((af_volume_t*)af->setup)->level[i] = 1.0;
+ }
+ return AF_OK;
+}
+
+// Description of this filter
+struct af_info af_info_volume = {
+ "Volume control audio filter",
+ "volume",
+ "Anders",
+ "",
+ AF_FLAGS_NOT_REENTRANT,
+ af_open
+};
diff --git a/audio/filter/control.h b/audio/filter/control.h
new file mode 100644
index 0000000000..323b9a3924
--- /dev/null
+++ b/audio/filter/control.h
@@ -0,0 +1,257 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPLAYER_CONTROL_H
+#define MPLAYER_CONTROL_H
+
+#include <sys/types.h>
+
+/*********************************************
+// Control info struct.
+//
+// This struct is the argument in a info call to a filter.
+*/
+
+// Argument types
+#define AF_CONTROL_TYPE_BOOL (0x0<<0)
+#define AF_CONTROL_TYPE_CHAR (0x1<<0)
+#define AF_CONTROL_TYPE_INT (0x2<<0)
+#define AF_CONTROL_TYPE_FLOAT (0x3<<0)
+#define AF_CONTROL_TYPE_STRUCT (0x4<<0)
+#define AF_CONTROL_TYPE_SPECIAL (0x5<<0) // a pointer to a function for example
+#define AF_CONTROL_TYPE_MASK (0x7<<0)
+// Argument geometry
+#define AF_CONTROL_GEOM_SCALAR (0x0<<3)
+#define AF_CONTROL_GEOM_ARRAY (0x1<<3)
+#define AF_CONTROL_GEOM_MATRIX (0x2<<3)
+#define AF_CONTROL_GEOM_MASK (0x3<<3)
+// Argument properties
+#define AF_CONTROL_PROP_READ (0x0<<5) // The argument can be read
+#define AF_CONTROL_PROP_WRITE (0x1<<5) // The argument can be written
+#define AF_CONTROL_PROP_SAVE (0x2<<5) // Can be saved
+#define AF_CONTROL_PROP_RUNTIME (0x4<<5) // Acessable during execution
+#define AF_CONTROL_PROP_CHANNEL (0x8<<5) // Argument is set per channel
+#define AF_CONTROL_PROP_MASK (0xF<<5)
+
+typedef struct af_control_info_s{
+ int def; // Control enumrification
+ char* name; // Name of argument
+ char* info; // Description of what it does
+ int flags; // Flags as defined above
+ float max; // Max and min value
+ float min; // (only aplicable on float and int)
+ int xdim; // 1st dimension
+ int ydim; // 2nd dimension (=0 for everything except matrix)
+ size_t sz; // Size of argument in bytes
+ int ch; // Channel number (for future use)
+ void* arg; // Data (for future use)
+}af_control_info_t;
+
+
+/*********************************************
+// Extended control used with arguments that operates on only one
+// channel at the time
+*/
+typedef struct af_control_ext_s{
+ void* arg; // Argument
+ int ch; // Chanel number
+}af_control_ext_t;
+
+/*********************************************
+// Control parameters
+*/
+
+/* The control system is divided into 3 levels
+ mandatory calls - all filters must answer to all of these
+ optional calls - are optional
+ filter specific calls - applies only to some filters
+*/
+
+#define AF_CONTROL_MANDATORY 0x10000000
+#define AF_CONTROL_OPTIONAL 0x20000000
+#define AF_CONTROL_FILTER_SPECIFIC 0x40000000
+
+// MANDATORY CALLS
+
+/* Reinitialize filter. The optional argument contains the new
+ configuration in form of a struct mp_audio struct. If the filter does not
+ support the new format the struct should be changed and AF_FALSE
+ should be returned. If the incoming and outgoing data streams are
+ identical the filter can return AF_DETACH. This will remove the
+ filter. */
+#define AF_CONTROL_REINIT 0x00000100 | AF_CONTROL_MANDATORY
+
+// OPTIONAL CALLS
+
+/* Called just after creation with the af_cfg for the stream in which
+ the filter resides as input parameter this call can be used by the
+ filter to initialize itself */
+#define AF_CONTROL_POST_CREATE 0x00000100 | AF_CONTROL_OPTIONAL
+
+// Called just before destruction of a filter
+#define AF_CONTROL_PRE_DESTROY 0x00000200 | AF_CONTROL_OPTIONAL
+
+/* Commandline parameters. If there were any commandline parameters
+ for this specific filter, they will be given as a char* in the
+ argument */
+#define AF_CONTROL_COMMAND_LINE 0x00000300 | AF_CONTROL_OPTIONAL
+
+
+// FILTER SPECIFIC CALLS
+
+// Basic operations: These can be ored with any of the below calls
+// Set argument
+#define AF_CONTROL_SET 0x00000000
+// Get argument
+#define AF_CONTROL_GET 0x00000001
+// Get info about the control, i.e fill in everything except argument
+#define AF_CONTROL_INFO 0x00000002
+
+// Resample
+
+// Set output rate in resample
+#define AF_CONTROL_RESAMPLE_RATE 0x00000100 | AF_CONTROL_FILTER_SPECIFIC
+
+// Enable sloppy resampling
+#define AF_CONTROL_RESAMPLE_SLOPPY 0x00000200 | AF_CONTROL_FILTER_SPECIFIC
+
+// Set resampling accuracy
+#define AF_CONTROL_RESAMPLE_ACCURACY 0x00000300 | AF_CONTROL_FILTER_SPECIFIC
+
+// Format
+
+#define AF_CONTROL_FORMAT_FMT 0x00000400 | AF_CONTROL_FILTER_SPECIFIC
+
+// Channels
+
+// Set number of output channels in channels
+#define AF_CONTROL_CHANNELS 0x00000600 | AF_CONTROL_FILTER_SPECIFIC
+
+// Set number of channel routes
+#define AF_CONTROL_CHANNELS_ROUTES 0x00000700 | AF_CONTROL_FILTER_SPECIFIC
+
+// Set channel routing pair, arg is int[2] and ch is used
+#define AF_CONTROL_CHANNELS_ROUTING 0x00000800 | AF_CONTROL_FILTER_SPECIFIC
+
+// Set nuber of channel routing pairs, arg is int*
+#define AF_CONTROL_CHANNELS_NR 0x00000900 | AF_CONTROL_FILTER_SPECIFIC
+
+// Set make af_channels into a router
+#define AF_CONTROL_CHANNELS_ROUTER 0x00000A00 | AF_CONTROL_FILTER_SPECIFIC
+
+// Volume
+
+// Turn volume control on and off, arg is int*
+#define AF_CONTROL_VOLUME_ON_OFF 0x00000B00 | AF_CONTROL_FILTER_SPECIFIC
+
+// Turn soft clipping of the volume on and off, arg is binary
+#define AF_CONTROL_VOLUME_SOFTCLIP 0x00000C00 | AF_CONTROL_FILTER_SPECIFIC
+
+// Set volume level, arg is a float* with the volume for all the channels
+#define AF_CONTROL_VOLUME_LEVEL 0x00000D00 | AF_CONTROL_FILTER_SPECIFIC
+
+// Probed power level for all channels, arg is a float*
+#define AF_CONTROL_VOLUME_PROBE 0x00000E00 | AF_CONTROL_FILTER_SPECIFIC
+
+// Maximum probed power level for all channels, arg is a float*
+#define AF_CONTROL_VOLUME_PROBE_MAX 0x00000F00 | AF_CONTROL_FILTER_SPECIFIC
+
+// Compressor/expander
+
+// Turn compressor/expander on and off
+#define AF_CONTROL_COMP_ON_OFF 0x00001000 | AF_CONTROL_FILTER_SPECIFIC
+
+// Compression/expansion threshold [dB]
+#define AF_CONTROL_COMP_THRESH 0x00001100 | AF_CONTROL_FILTER_SPECIFIC
+
+// Compression/expansion attack time [ms]
+#define AF_CONTROL_COMP_ATTACK 0x00001200 | AF_CONTROL_FILTER_SPECIFIC
+
+// Compression/expansion release time [ms]
+#define AF_CONTROL_COMP_RELEASE 0x00001300 | AF_CONTROL_FILTER_SPECIFIC
+
+// Compression/expansion gain level [dB]
+#define AF_CONTROL_COMP_RATIO 0x00001400 | AF_CONTROL_FILTER_SPECIFIC
+
+// Noise gate
+
+// Turn noise gate on an off
+#define AF_CONTROL_GATE_ON_OFF 0x00001500 | AF_CONTROL_FILTER_SPECIFIC
+
+// Noise gate threshold [dB]
+#define AF_CONTROL_GATE_THRESH 0x00001600 | AF_CONTROL_FILTER_SPECIFIC
+
+// Noise gate attack time [ms]
+#define AF_CONTROL_GATE_ATTACK 0x00001700 | AF_CONTROL_FILTER_SPECIFIC
+
+// Noise gate release time [ms]
+#define AF_CONTROL_GATE_RELEASE 0x00001800 | AF_CONTROL_FILTER_SPECIFIC
+
+// Noise gate release range level [dB]
+#define AF_CONTROL_GATE_RANGE 0x00001900 | AF_CONTROL_FILTER_SPECIFIC
+
+// Pan
+
+// Pan levels, arg is a control_ext with a float*
+#define AF_CONTROL_PAN_LEVEL 0x00001A00 | AF_CONTROL_FILTER_SPECIFIC
+
+// Number of outputs from pan, arg is int*
+#define AF_CONTROL_PAN_NOUT 0x00001B00 | AF_CONTROL_FILTER_SPECIFIC
+
+// Balance, arg is float*; range -1 (left) to 1 (right), 0 center
+#define AF_CONTROL_PAN_BALANCE 0x00001C00 | AF_CONTROL_FILTER_SPECIFIC
+
+// Set equalizer gain, arg is a control_ext with a float*
+#define AF_CONTROL_EQUALIZER_GAIN 0x00001D00 | AF_CONTROL_FILTER_SPECIFIC
+
+
+// Delay length in ms, arg is a control_ext with a float*
+#define AF_CONTROL_DELAY_LEN 0x00001E00 | AF_CONTROL_FILTER_SPECIFIC
+
+
+// Subwoofer
+
+// Channel number which to insert the filtered data, arg in int*
+#define AF_CONTROL_SUB_CH 0x00001F00 | AF_CONTROL_FILTER_SPECIFIC
+
+// Cutoff frequency [Hz] for lowpass filter, arg is float*
+#define AF_CONTROL_SUB_FC 0x00002000 | AF_CONTROL_FILTER_SPECIFIC
+
+
+// Export
+#define AF_CONTROL_EXPORT_SZ 0x00003000 | AF_CONTROL_FILTER_SPECIFIC
+
+
+// ExtraStereo Multiplier
+#define AF_CONTROL_ES_MUL 0x00003100 | AF_CONTROL_FILTER_SPECIFIC
+
+
+// Center
+
+// Channel number which to inster the filtered data, arg in int*
+#define AF_CONTROL_CENTER_CH 0x00003200 | AF_CONTROL_FILTER_SPECIFIC
+
+
+// SineSuppress
+#define AF_CONTROL_SS_FREQ 0x00003300 | AF_CONTROL_FILTER_SPECIFIC
+#define AF_CONTROL_SS_DECAY 0x00003400 | AF_CONTROL_FILTER_SPECIFIC
+
+#define AF_CONTROL_PLAYBACK_SPEED 0x00003500 | AF_CONTROL_FILTER_SPECIFIC
+#define AF_CONTROL_SCALETEMPO_AMOUNT 0x00003600 | AF_CONTROL_FILTER_SPECIFIC
+
+#endif /* MPLAYER_CONTROL_H */
diff --git a/audio/filter/dsp.h b/audio/filter/dsp.h
new file mode 100644
index 0000000000..561b86cfe0
--- /dev/null
+++ b/audio/filter/dsp.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2002 Anders Johansson ajh@atri.curtin.edu.au
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPLAYER_DSP_H
+#define MPLAYER_DSP_H
+
+/* Implementation of routines used for DSP */
+
+/* Size of floating point type used in routines */
+#define FLOAT_TYPE float
+
+#include "window.h"
+#include "filter.h"
+
+#endif /* MPLAYER_DSP_H */
diff --git a/audio/filter/equalizer.h b/audio/filter/equalizer.h
new file mode 100644
index 0000000000..4935401413
--- /dev/null
+++ b/audio/filter/equalizer.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2002 Anders Johansson ajh@atri.curtin.edu.au
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPLAYER_EQUALIZER_H
+#define MPLAYER_EQUALIZER_H
+
+/* Equalizer plugin header file defines struct used for setting or
+ getting the gain of a specific channel and frequency */
+
+typedef struct equalizer_s
+{
+ float gain; // Gain in dB -15 - 15
+ int channel; // Channel number 0 - 5
+ int band; // Frequency band 0 - 9
+}equalizer_t;
+
+/* The different frequency bands are:
+nr. center frequency
+0 31.25 Hz
+1 62.50 Hz
+2 125.0 Hz
+3 250.0 Hz
+4 500.0 Hz
+5 1.000 kHz
+6 2.000 kHz
+7 4.000 kHz
+8 8.000 kHz
+9 16.00 kHz
+*/
+
+#endif /* MPLAYER_EQUALIZER_H */
diff --git a/audio/filter/filter.c b/audio/filter/filter.c
new file mode 100644
index 0000000000..b272125fd8
--- /dev/null
+++ b/audio/filter/filter.c
@@ -0,0 +1,360 @@
+/*
+ * design and implementation of different types of digital filters
+ *
+ * Copyright (C) 2001 Anders Johansson ajh@atri.curtin.edu.au
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <string.h>
+#include <math.h>
+#include "dsp.h"
+
+/******************************************************************************
+* FIR filter implementations
+******************************************************************************/
+
+/* C implementation of FIR filter y=w*x
+
+ n number of filter taps, where mod(n,4)==0
+ w filter taps
+ x input signal must be a circular buffer which is indexed backwards
+*/
+inline FLOAT_TYPE af_filter_fir(register unsigned int n, const FLOAT_TYPE* w,
+ const FLOAT_TYPE* x)
+{
+ register FLOAT_TYPE y; // Output
+ y = 0.0;
+ do{
+ n--;
+ y+=w[n]*x[n];
+ }while(n != 0);
+ return y;
+}
+
+/******************************************************************************
+* FIR filter design
+******************************************************************************/
+
+/* Design FIR filter using the Window method
+
+ n filter length must be odd for HP and BS filters
+ w buffer for the filter taps (must be n long)
+ fc cutoff frequencies (1 for LP and HP, 2 for BP and BS)
+ 0 < fc < 1 where 1 <=> Fs/2
+ flags window and filter type as defined in filter.h
+ variables are ored together: i.e. LP|HAMMING will give a
+ low pass filter designed using a hamming window
+ opt beta constant used only when designing using kaiser windows
+
+ returns 0 if OK, -1 if fail
+*/
+int af_filter_design_fir(unsigned int n, FLOAT_TYPE* w, const FLOAT_TYPE* fc,
+ unsigned int flags, FLOAT_TYPE opt)
+{
+ unsigned int o = n & 1; // Indicator for odd filter length
+ unsigned int end = ((n + 1) >> 1) - o; // Loop end
+ unsigned int i; // Loop index
+
+ FLOAT_TYPE k1 = 2 * M_PI; // 2*pi*fc1
+ FLOAT_TYPE k2 = 0.5 * (FLOAT_TYPE)(1 - o);// Constant used if the filter has even length
+ FLOAT_TYPE k3; // 2*pi*fc2 Constant used in BP and BS design
+ FLOAT_TYPE g = 0.0; // Gain
+ FLOAT_TYPE t1,t2,t3; // Temporary variables
+ FLOAT_TYPE fc1,fc2; // Cutoff frequencies
+
+ // Sanity check
+ if(!w || (n == 0)) return -1;
+
+ // Get window coefficients
+ switch(flags & WINDOW_MASK){
+ case(BOXCAR):
+ af_window_boxcar(n,w); break;
+ case(TRIANG):
+ af_window_triang(n,w); break;
+ case(HAMMING):
+ af_window_hamming(n,w); break;
+ case(HANNING):
+ af_window_hanning(n,w); break;
+ case(BLACKMAN):
+ af_window_blackman(n,w); break;
+ case(FLATTOP):
+ af_window_flattop(n,w); break;
+ case(KAISER):
+ af_window_kaiser(n,w,opt); break;
+ default:
+ return -1;
+ }
+
+ if(flags & (LP | HP)){
+ fc1=*fc;
+ // Cutoff frequency must be < 0.5 where 0.5 <=> Fs/2
+ fc1 = ((fc1 <= 1.0) && (fc1 > 0.0)) ? fc1/2 : 0.25;
+ k1 *= fc1;
+
+ if(flags & LP){ // Low pass filter
+
+ // If the filter length is odd, there is one point which is exactly
+ // in the middle. The value at this point is 2*fCutoff*sin(x)/x,
+ // where x is zero. To make sure nothing strange happens, we set this
+ // value separately.
+ if (o){
+ w[end] = fc1 * w[end] * 2.0;
+ g=w[end];
+ }
+
+ // Create filter
+ for (i=0 ; i<end ; i++){
+ t1 = (FLOAT_TYPE)(i+1) - k2;
+ w[end-i-1] = w[n-end+i] = w[end-i-1] * sin(k1 * t1)/(M_PI * t1); // Sinc
+ g += 2*w[end-i-1]; // Total gain in filter
+ }
+ }
+ else{ // High pass filter
+ if (!o) // High pass filters must have odd length
+ return -1;
+ w[end] = 1.0 - (fc1 * w[end] * 2.0);
+ g= w[end];
+
+ // Create filter
+ for (i=0 ; i<end ; i++){
+ t1 = (FLOAT_TYPE)(i+1);
+ w[end-i-1] = w[n-end+i] = -1 * w[end-i-1] * sin(k1 * t1)/(M_PI * t1); // Sinc
+ g += ((i&1) ? (2*w[end-i-1]) : (-2*w[end-i-1])); // Total gain in filter
+ }
+ }
+ }
+
+ if(flags & (BP | BS)){
+ fc1=fc[0];
+ fc2=fc[1];
+ // Cutoff frequencies must be < 1.0 where 1.0 <=> Fs/2
+ fc1 = ((fc1 <= 1.0) && (fc1 > 0.0)) ? fc1/2 : 0.25;
+ fc2 = ((fc2 <= 1.0) && (fc2 > 0.0)) ? fc2/2 : 0.25;
+ k3 = k1 * fc2; // 2*pi*fc2
+ k1 *= fc1; // 2*pi*fc1
+
+ if(flags & BP){ // Band pass
+ // Calculate center tap
+ if (o){
+ g=w[end]*(fc1+fc2);
+ w[end] = (fc2 - fc1) * w[end] * 2.0;
+ }
+
+ // Create filter
+ for (i=0 ; i<end ; i++){
+ t1 = (FLOAT_TYPE)(i+1) - k2;
+ t2 = sin(k3 * t1)/(M_PI * t1); // Sinc fc2
+ t3 = sin(k1 * t1)/(M_PI * t1); // Sinc fc1
+ g += w[end-i-1] * (t3 + t2); // Total gain in filter
+ w[end-i-1] = w[n-end+i] = w[end-i-1] * (t2 - t3);
+ }
+ }
+ else{ // Band stop
+ if (!o) // Band stop filters must have odd length
+ return -1;
+ w[end] = 1.0 - (fc2 - fc1) * w[end] * 2.0;
+ g= w[end];
+
+ // Create filter
+ for (i=0 ; i<end ; i++){
+ t1 = (FLOAT_TYPE)(i+1);
+ t2 = sin(k1 * t1)/(M_PI * t1); // Sinc fc1
+ t3 = sin(k3 * t1)/(M_PI * t1); // Sinc fc2
+ w[end-i-1] = w[n-end+i] = w[end-i-1] * (t2 - t3);
+ g += 2*w[end-i-1]; // Total gain in filter
+ }
+ }
+ }
+
+ // Normalize gain
+ g=1/g;
+ for (i=0; i<n; i++)
+ w[i] *= g;
+
+ return 0;
+}
+
+/******************************************************************************
+* IIR filter design
+******************************************************************************/
+
+/* Helper functions for the bilinear transform */
+
+/* Pre-warp the coefficients of a numerator or denominator.
+ Note that a0 is assumed to be 1, so there is no wrapping
+ of it.
+*/
+static void af_filter_prewarp(FLOAT_TYPE* a, FLOAT_TYPE fc, FLOAT_TYPE fs)
+{
+ FLOAT_TYPE wp;
+ wp = 2.0 * fs * tan(M_PI * fc / fs);
+ a[2] = a[2]/(wp * wp);
+ a[1] = a[1]/wp;
+}
+
+/* Transform the numerator and denominator coefficients of s-domain
+ biquad section into corresponding z-domain coefficients.
+
+ The transfer function for z-domain is:
+
+ 1 + alpha1 * z^(-1) + alpha2 * z^(-2)
+ H(z) = -------------------------------------
+ 1 + beta1 * z^(-1) + beta2 * z^(-2)
+
+ Store the 4 IIR coefficients in array pointed by coef in following
+ order:
+ beta1, beta2 (denominator)
+ alpha1, alpha2 (numerator)
+
+ Arguments:
+ a - s-domain numerator coefficients
+ b - s-domain denominator coefficients
+ k - filter gain factor. Initially set to 1 and modified by each
+ biquad section in such a way, as to make it the
+ coefficient by which to multiply the overall filter gain
+ in order to achieve a desired overall filter gain,
+ specified in initial value of k.
+ fs - sampling rate (Hz)
+ coef - array of z-domain coefficients to be filled in.
+
+ Return: On return, set coef z-domain coefficients and k to the gain
+ required to maintain overall gain = 1.0;
+*/
+static void af_filter_bilinear(const FLOAT_TYPE* a, const FLOAT_TYPE* b, FLOAT_TYPE* k,
+ FLOAT_TYPE fs, FLOAT_TYPE *coef)
+{
+ FLOAT_TYPE ad, bd;
+
+ /* alpha (Numerator in s-domain) */
+ ad = 4. * a[2] * fs * fs + 2. * a[1] * fs + a[0];
+ /* beta (Denominator in s-domain) */
+ bd = 4. * b[2] * fs * fs + 2. * b[1] * fs + b[0];
+
+ /* Update gain constant for this section */
+ *k *= ad/bd;
+
+ /* Denominator */
+ *coef++ = (2. * b[0] - 8. * b[2] * fs * fs)/bd; /* beta1 */
+ *coef++ = (4. * b[2] * fs * fs - 2. * b[1] * fs + b[0])/bd; /* beta2 */
+
+ /* Numerator */
+ *coef++ = (2. * a[0] - 8. * a[2] * fs * fs)/ad; /* alpha1 */
+ *coef = (4. * a[2] * fs * fs - 2. * a[1] * fs + a[0])/ad; /* alpha2 */
+}
+
+
+
+/* IIR filter design using bilinear transform and prewarp. Transforms
+ 2nd order s domain analog filter into a digital IIR biquad link. To
+ create a filter fill in a, b, Q and fs and make space for coef and k.
+
+
+ Example Butterworth design:
+
+ Below are Butterworth polynomials, arranged as a series of 2nd
+ order sections:
+
+ Note: n is filter order.
+
+ n Polynomials
+ -------------------------------------------------------------------
+ 2 s^2 + 1.4142s + 1
+ 4 (s^2 + 0.765367s + 1) * (s^2 + 1.847759s + 1)
+ 6 (s^2 + 0.5176387s + 1) * (s^2 + 1.414214 + 1) * (s^2 + 1.931852s + 1)
+
+ For n=4 we have following equation for the filter transfer function:
+ 1 1
+ T(s) = --------------------------- * ----------------------------
+ s^2 + (1/Q) * 0.765367s + 1 s^2 + (1/Q) * 1.847759s + 1
+
+ The filter consists of two 2nd order sections since highest s power
+ is 2. Now we can take the coefficients, or the numbers by which s
+ is multiplied and plug them into a standard formula to be used by
+ bilinear transform.
+
+ Our standard form for each 2nd order section is:
+
+ a2 * s^2 + a1 * s + a0
+ H(s) = ----------------------
+ b2 * s^2 + b1 * s + b0
+
+ Note that Butterworth numerator is 1 for all filter sections, which
+ means s^2 = 0 and s^1 = 0
+
+ Let's convert standard Butterworth polynomials into this form:
+
+ 0 + 0 + 1 0 + 0 + 1
+ --------------------------- * --------------------------
+ 1 + ((1/Q) * 0.765367) + 1 1 + ((1/Q) * 1.847759) + 1
+
+ Section 1:
+ a2 = 0; a1 = 0; a0 = 1;
+ b2 = 1; b1 = 0.765367; b0 = 1;
+
+ Section 2:
+ a2 = 0; a1 = 0; a0 = 1;
+ b2 = 1; b1 = 1.847759; b0 = 1;
+
+ Q is filter quality factor or resonance, in the range of 1 to
+ 1000. The overall filter Q is a product of all 2nd order stages.
+ For example, the 6th order filter (3 stages, or biquads) with
+ individual Q of 2 will have filter Q = 2 * 2 * 2 = 8.
+
+
+ Arguments:
+ a - s-domain numerator coefficients, a[1] is always assumed to be 1.0
+ b - s-domain denominator coefficients
+ Q - Q value for the filter
+ k - filter gain factor. Initially set to 1 and modified by each
+ biquad section in such a way, as to make it the
+ coefficient by which to multiply the overall filter gain
+ in order to achieve a desired overall filter gain,
+ specified in initial value of k.
+ fs - sampling rate (Hz)
+ coef - array of z-domain coefficients to be filled in.
+
+ Note: Upon return from each call, the k argument will be set to a
+ value, by which to multiply our actual signal in order for the gain
+ to be one. On second call to szxform() we provide k that was
+ changed by the previous section. During actual audio filtering
+ k can be used for gain compensation.
+
+ return -1 if fail 0 if success.
+*/
+int af_filter_szxform(const FLOAT_TYPE* a, const FLOAT_TYPE* b, FLOAT_TYPE Q, FLOAT_TYPE fc,
+ FLOAT_TYPE fs, FLOAT_TYPE *k, FLOAT_TYPE *coef)
+{
+ FLOAT_TYPE at[3];
+ FLOAT_TYPE bt[3];
+
+ if(!a || !b || !k || !coef || (Q>1000.0 || Q< 1.0))
+ return -1;
+
+ memcpy(at,a,3*sizeof(FLOAT_TYPE));
+ memcpy(bt,b,3*sizeof(FLOAT_TYPE));
+
+ bt[1]/=Q;
+
+ /* Calculate a and b and overwrite the original values */
+ af_filter_prewarp(at, fc, fs);
+ af_filter_prewarp(bt, fc, fs);
+ /* Execute bilinear transform */
+ af_filter_bilinear(at, bt, k, fs, coef);
+
+ return 0;
+}
diff --git a/audio/filter/filter.h b/audio/filter/filter.h
new file mode 100644
index 0000000000..aed33352c2
--- /dev/null
+++ b/audio/filter/filter.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2001 Anders Johansson ajh@atri.curtin.edu.au
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#if !defined MPLAYER_DSP_H
+# error Never use filter.h directly; include dsp.h instead.
+#endif
+
+#ifndef MPLAYER_FILTER_H
+#define MPLAYER_FILTER_H
+
+
+// Design and implementation of different types of digital filters
+
+
+// Flags used for filter design
+
+// Filter characteristics
+#define LP 0x00010000 // Low pass
+#define HP 0x00020000 // High pass
+#define BP 0x00040000 // Band pass
+#define BS 0x00080000 // Band stop
+#define TYPE_MASK 0x000F0000
+
+// Window types
+#define BOXCAR 0x00000001
+#define TRIANG 0x00000002
+#define HAMMING 0x00000004
+#define HANNING 0x00000008
+#define BLACKMAN 0x00000010
+#define FLATTOP 0x00000011
+#define KAISER 0x00000012
+#define WINDOW_MASK 0x0000001F
+
+// Parallel filter design
+#define FWD 0x00000001 // Forward indexing of polyphase filter
+#define REW 0x00000002 // Reverse indexing of polyphase filter
+#define ODD 0x00000010 // Make filter HP
+
+// Exported functions
+FLOAT_TYPE af_filter_fir(unsigned int n, const FLOAT_TYPE* w, const FLOAT_TYPE* x);
+
+int af_filter_design_fir(unsigned int n, FLOAT_TYPE* w, const FLOAT_TYPE* fc,
+ unsigned int flags, FLOAT_TYPE opt);
+
+int af_filter_szxform(const FLOAT_TYPE* a, const FLOAT_TYPE* b, FLOAT_TYPE Q,
+ FLOAT_TYPE fc, FLOAT_TYPE fs, FLOAT_TYPE *k,
+ FLOAT_TYPE *coef);
+
+/* Add new data to circular queue designed to be used with a FIR
+ filter. xq is the circular queue, in pointing at the new sample, xi
+ current index for xq and n the length of the filter. xq must be n*2
+ long.
+*/
+#define af_filter_updateq(n,xi,xq,in)\
+ xq[xi]=(xq)[(xi)+(n)]=*(in);\
+ xi=(++(xi))&((n)-1);
+
+#endif /* MPLAYER_FILTER_H */
diff --git a/audio/filter/window.c b/audio/filter/window.c
new file mode 100644
index 0000000000..a970bdcbea
--- /dev/null
+++ b/audio/filter/window.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2001 Anders Johansson ajh@atri.curtin.edu.au
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* Calculates a number of window functions. The following window
+ functions are currently implemented: Boxcar, Triang, Hanning,
+ Hamming, Blackman, Flattop and Kaiser. In the function call n is
+ the number of filter taps and w the buffer in which the filter
+ coefficients will be stored.
+*/
+
+#include <math.h>
+#include "dsp.h"
+
+/*
+// Boxcar
+//
+// n window length
+// w buffer for the window parameters
+*/
+void af_window_boxcar(int n, FLOAT_TYPE* w)
+{
+ int i;
+ // Calculate window coefficients
+ for (i=0 ; i<n ; i++)
+ w[i] = 1.0;
+}
+
+
+/*
+// Triang a.k.a Bartlett
+//
+// | (N-1)|
+// 2 * |k - -----|
+// | 2 |
+// w = 1.0 - ---------------
+// N+1
+// n window length
+// w buffer for the window parameters
+*/
+void af_window_triang(int n, FLOAT_TYPE* w)
+{
+ FLOAT_TYPE k1 = (FLOAT_TYPE)(n & 1);
+ FLOAT_TYPE k2 = 1/((FLOAT_TYPE)n + k1);
+ int end = (n + 1) >> 1;
+ int i;
+
+ // Calculate window coefficients
+ for (i=0 ; i<end ; i++)
+ w[i] = w[n-i-1] = (2.0*((FLOAT_TYPE)(i+1))-(1.0-k1))*k2;
+}
+
+
+/*
+// Hanning
+// 2*pi*k
+// w = 0.5 - 0.5*cos(------), where 0 < k <= N
+// N+1
+// n window length
+// w buffer for the window parameters
+*/
+void af_window_hanning(int n, FLOAT_TYPE* w)
+{
+ int i;
+ FLOAT_TYPE k = 2*M_PI/((FLOAT_TYPE)(n+1)); // 2*pi/(N+1)
+
+ // Calculate window coefficients
+ for (i=0; i<n; i++)
+ *w++ = 0.5*(1.0 - cos(k*(FLOAT_TYPE)(i+1)));
+}
+
+/*
+// Hamming
+// 2*pi*k
+// w(k) = 0.54 - 0.46*cos(------), where 0 <= k < N
+// N-1
+//
+// n window length
+// w buffer for the window parameters
+*/
+void af_window_hamming(int n,FLOAT_TYPE* w)
+{
+ int i;
+ FLOAT_TYPE k = 2*M_PI/((FLOAT_TYPE)(n-1)); // 2*pi/(N-1)
+
+ // Calculate window coefficients
+ for (i=0; i<n; i++)
+ *w++ = 0.54 - 0.46*cos(k*(FLOAT_TYPE)i);
+}
+
+/*
+// Blackman
+// 2*pi*k 4*pi*k
+// w(k) = 0.42 - 0.5*cos(------) + 0.08*cos(------), where 0 <= k < N
+// N-1 N-1
+//
+// n window length
+// w buffer for the window parameters
+*/
+void af_window_blackman(int n,FLOAT_TYPE* w)
+{
+ int i;
+ FLOAT_TYPE k1 = 2*M_PI/((FLOAT_TYPE)(n-1)); // 2*pi/(N-1)
+ FLOAT_TYPE k2 = 2*k1; // 4*pi/(N-1)
+
+ // Calculate window coefficients
+ for (i=0; i<n; i++)
+ *w++ = 0.42 - 0.50*cos(k1*(FLOAT_TYPE)i) + 0.08*cos(k2*(FLOAT_TYPE)i);
+}
+
+/*
+// Flattop
+// 2*pi*k 4*pi*k
+// w(k) = 0.2810638602 - 0.5208971735*cos(------) + 0.1980389663*cos(------), where 0 <= k < N
+// N-1 N-1
+//
+// n window length
+// w buffer for the window parameters
+*/
+void af_window_flattop(int n,FLOAT_TYPE* w)
+{
+ int i;
+ FLOAT_TYPE k1 = 2*M_PI/((FLOAT_TYPE)(n-1)); // 2*pi/(N-1)
+ FLOAT_TYPE k2 = 2*k1; // 4*pi/(N-1)
+
+ // Calculate window coefficients
+ for (i=0; i<n; i++)
+ *w++ = 0.2810638602 - 0.5208971735*cos(k1*(FLOAT_TYPE)i)
+ + 0.1980389663*cos(k2*(FLOAT_TYPE)i);
+}
+
+/* Computes the 0th order modified Bessel function of the first kind.
+// (Needed to compute Kaiser window)
+//
+// y = sum( (x/(2*n))^2 )
+// n
+*/
+#define BIZ_EPSILON 1E-21 // Max error acceptable
+
+static FLOAT_TYPE besselizero(FLOAT_TYPE x)
+{
+ FLOAT_TYPE temp;
+ FLOAT_TYPE sum = 1.0;
+ FLOAT_TYPE u = 1.0;
+ FLOAT_TYPE halfx = x/2.0;
+ int n = 1;
+
+ do {
+ temp = halfx/(FLOAT_TYPE)n;
+ u *=temp * temp;
+ sum += u;
+ n++;
+ } while (u >= BIZ_EPSILON * sum);
+ return sum;
+}
+
+/*
+// Kaiser
+//
+// n window length
+// w buffer for the window parameters
+// b beta parameter of Kaiser window, Beta >= 1
+//
+// Beta trades the rejection of the low pass filter against the
+// transition width from passband to stop band. Larger Beta means a
+// slower transition and greater stop band rejection. See Rabiner and
+// Gold (Theory and Application of DSP) under Kaiser windows for more
+// about Beta. The following table from Rabiner and Gold gives some
+// feel for the effect of Beta:
+//
+// All ripples in dB, width of transition band = D*N where N = window
+// length
+//
+// BETA D PB RIP SB RIP
+// 2.120 1.50 +-0.27 -30
+// 3.384 2.23 0.0864 -40
+// 4.538 2.93 0.0274 -50
+// 5.658 3.62 0.00868 -60
+// 6.764 4.32 0.00275 -70
+// 7.865 5.0 0.000868 -80
+// 8.960 5.7 0.000275 -90
+// 10.056 6.4 0.000087 -100
+*/
+void af_window_kaiser(int n, FLOAT_TYPE* w, FLOAT_TYPE b)
+{
+ FLOAT_TYPE tmp;
+ FLOAT_TYPE k1 = 1.0/besselizero(b);
+ int k2 = 1 - (n & 1);
+ int end = (n + 1) >> 1;
+ int i;
+
+ // Calculate window coefficients
+ for (i=0 ; i<end ; i++){
+ tmp = (FLOAT_TYPE)(2*i + k2) / ((FLOAT_TYPE)n - 1.0);
+ w[end-(1&(!k2))+i] = w[end-1-i] = k1 * besselizero(b*sqrt(1.0 - tmp*tmp));
+ }
+}
diff --git a/audio/filter/window.h b/audio/filter/window.h
new file mode 100644
index 0000000000..1c179b7902
--- /dev/null
+++ b/audio/filter/window.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2001 Anders Johansson ajh@atri.curtin.edu.au
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* Calculates a number of window functions. The following window
+ functions are currently implemented: Boxcar, Triang, Hanning,
+ Hamming, Blackman, Flattop and Kaiser. In the function call n is
+ the number of filter taps and w the buffer in which the filter
+ coefficients will be stored.
+*/
+
+#if !defined MPLAYER_DSP_H
+# error Never use window.h directly; include dsp.h instead.
+#endif
+
+#ifndef MPLAYER_WINDOW_H
+#define MPLAYER_WINDOW_H
+
+void af_window_boxcar(int n, FLOAT_TYPE* w);
+void af_window_triang(int n, FLOAT_TYPE* w);
+void af_window_hanning(int n, FLOAT_TYPE* w);
+void af_window_hamming(int n, FLOAT_TYPE* w);
+void af_window_blackman(int n, FLOAT_TYPE* w);
+void af_window_flattop(int n, FLOAT_TYPE* w);
+void af_window_kaiser(int n, FLOAT_TYPE* w, FLOAT_TYPE b);
+
+#endif /* MPLAYER_WINDOW_H */