gst_plugins_base/gst/audioconvert/gstchannelmix.c
branchRCL_3
changeset 30 7e817e7e631c
parent 29 567bb019e3e3
equal deleted inserted replaced
29:567bb019e3e3 30:7e817e7e631c
     1 /* GStreamer
     1 /* GStreamer
     2  * Copyright (C) 2004 Ronald Bultje <rbultje@ronald.bitfreak.net>
     2  * Copyright (C) 2004 Ronald Bultje <rbultje@ronald.bitfreak.net>
     3  * Copyright (C) 2008 Sebastian Dröge <slomo@circular-chaos.org>
       
     4  *
     3  *
     5  * gstchannelmix.c: setup of channel conversion matrices
     4  * gstchannelmix.c: setup of channel conversion matrices
     6  *
     5  *
     7  * This library is free software; you can redistribute it and/or
     6  * This library is free software; you can redistribute it and/or
     8  * modify it under the terms of the GNU Library General Public
     7  * modify it under the terms of the GNU Library General Public
   113     GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}}, { {
   112     GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}}, { {
   114     GST_AUDIO_CHANNEL_POSITION_INVALID}}
   113     GST_AUDIO_CHANNEL_POSITION_INVALID}}
   115   };
   114   };
   116   gint c;
   115   gint c;
   117 
   116 
   118   /* conversions from compatible (but not the same) channel schemes */
   117   /* conversions from compatible (but not the same) channel schemes. This
       
   118    * goes two ways: if the sink has both pos1[0,1] and src has pos2[0] or
       
   119    * if the src has both pos1[0,1] and sink has pos2[0], then we do the
       
   120    * conversion. We hereby assume that the existance of pos1[0,1] and
       
   121    * pos2[0] are mututally exclusive. There are no checks for that,
       
   122    * unfortunately. This shouldn't lead to issues (like crashes or so),
       
   123    * though. */
   119   for (c = 0; conv[c].pos1[0] != GST_AUDIO_CHANNEL_POSITION_INVALID; c++) {
   124   for (c = 0; conv[c].pos1[0] != GST_AUDIO_CHANNEL_POSITION_INVALID; c++) {
   120     gint pos1_0 = -1, pos1_1 = -1, pos1_2 = -1;
   125     gint pos1_0 = -1, pos1_1 = -1, pos2_0 = -1, n;
   121     gint pos2_0 = -1, pos2_1 = -1, pos2_2 = -1;
   126 
   122     gint n;
   127     /* Try to go from the given 2 channels to the given 1 channel */
   123 
       
   124     for (n = 0; n < this->in.channels; n++) {
   128     for (n = 0; n < this->in.channels; n++) {
   125       if (this->in.pos[n] == conv[c].pos1[0])
   129       if (this->in.pos[n] == conv[c].pos1[0])
   126         pos1_0 = n;
   130         pos1_0 = n;
   127       else if (this->in.pos[n] == conv[c].pos1[1])
   131       else if (this->in.pos[n] == conv[c].pos1[1])
   128         pos1_1 = n;
   132         pos1_1 = n;
   129       else if (this->in.pos[n] == conv[c].pos2[0])
   133     }
   130         pos1_2 = n;
   134     for (n = 0; n < this->out.channels; n++) {
   131     }
   135       if (this->out.pos[n] == conv[c].pos2[0])
       
   136         pos2_0 = n;
       
   137     }
       
   138 
       
   139     if (pos1_0 != -1 && pos1_1 != -1 && pos2_0 != -1) {
       
   140       this->matrix[pos1_0][pos2_0] = 1.0;
       
   141       this->matrix[pos1_1][pos2_0] = 1.0;
       
   142     }
       
   143 
       
   144     /* Try to go from the given 1 channel to the given 2 channels */
       
   145     pos1_0 = -1;
       
   146     pos1_1 = -1;
       
   147     pos2_0 = -1;
       
   148 
   132     for (n = 0; n < this->out.channels; n++) {
   149     for (n = 0; n < this->out.channels; n++) {
   133       if (this->out.pos[n] == conv[c].pos1[0])
   150       if (this->out.pos[n] == conv[c].pos1[0])
       
   151         pos1_0 = n;
       
   152       else if (this->out.pos[n] == conv[c].pos1[1])
       
   153         pos1_1 = n;
       
   154     }
       
   155     for (n = 0; n < this->in.channels; n++) {
       
   156       if (this->in.pos[n] == conv[c].pos2[0])
   134         pos2_0 = n;
   157         pos2_0 = n;
   135       else if (this->out.pos[n] == conv[c].pos1[1])
   158     }
   136         pos2_1 = n;
   159 
   137       else if (this->out.pos[n] == conv[c].pos2[0])
   160     if (pos1_0 != -1 && pos1_1 != -1 && pos2_0 != -1) {
   138         pos2_2 = n;
   161       this->matrix[pos2_0][pos1_0] = 1.0;
   139     }
   162       this->matrix[pos2_0][pos1_1] = 1.0;
   140 
   163     }
   141     /* The general idea here is to fill in channels from the same position
       
   142      * as good as possible. This means mixing left<->center and right<->center.
       
   143      */
       
   144 
       
   145     /* left -> center */
       
   146     if (pos1_0 != -1 && pos1_2 == -1 && pos2_0 == -1 && pos2_2 != -1)
       
   147       this->matrix[pos1_0][pos2_2] = 1.0;
       
   148     else if (pos1_0 != -1 && pos1_2 != -1 && pos2_0 == -1 && pos2_2 != -1)
       
   149       this->matrix[pos1_0][pos2_2] = 0.5;
       
   150     else if (pos1_0 != -1 && pos1_2 == -1 && pos2_0 != -1 && pos2_2 != -1)
       
   151       this->matrix[pos1_0][pos2_2] = 1.0;
       
   152 
       
   153     /* right -> center */
       
   154     if (pos1_1 != -1 && pos1_2 == -1 && pos2_1 == -1 && pos2_2 != -1)
       
   155       this->matrix[pos1_1][pos2_2] = 1.0;
       
   156     else if (pos1_1 != -1 && pos1_2 != -1 && pos2_1 == -1 && pos2_2 != -1)
       
   157       this->matrix[pos1_1][pos2_2] = 0.5;
       
   158     else if (pos1_1 != -1 && pos1_2 == -1 && pos2_1 != -1 && pos2_2 != -1)
       
   159       this->matrix[pos1_1][pos2_2] = 1.0;
       
   160 
       
   161     /* center -> left */
       
   162     if (pos1_2 != -1 && pos1_0 == -1 && pos2_2 == -1 && pos2_0 != -1)
       
   163       this->matrix[pos1_2][pos2_0] = 1.0;
       
   164     else if (pos1_2 != -1 && pos1_0 != -1 && pos2_2 == -1 && pos2_0 != -1)
       
   165       this->matrix[pos1_2][pos2_0] = 0.5;
       
   166     else if (pos1_2 != -1 && pos1_0 == -1 && pos2_2 != -1 && pos2_0 != -1)
       
   167       this->matrix[pos1_2][pos2_0] = 1.0;
       
   168 
       
   169     /* center -> right */
       
   170     if (pos1_2 != -1 && pos1_1 == -1 && pos2_2 == -1 && pos2_1 != -1)
       
   171       this->matrix[pos1_2][pos2_1] = 1.0;
       
   172     else if (pos1_2 != -1 && pos1_1 != -1 && pos2_2 == -1 && pos2_1 != -1)
       
   173       this->matrix[pos1_2][pos2_1] = 0.5;
       
   174     else if (pos1_2 != -1 && pos1_1 == -1 && pos2_2 != -1 && pos2_1 != -1)
       
   175       this->matrix[pos1_2][pos2_1] = 1.0;
       
   176   }
   164   }
   177 }
   165 }
   178 
   166 
   179 /*
   167 /*
   180  * Detect and fill in channels not handled by the
   168  * Detect and fill in channels not handled by the
   194   gint n;
   182   gint n;
   195 
   183 
   196   for (n = 0; n < caps->channels; n++) {
   184   for (n = 0; n < caps->channels; n++) {
   197     switch (caps->pos[n]) {
   185     switch (caps->pos[n]) {
   198       case GST_AUDIO_CHANNEL_POSITION_FRONT_MONO:
   186       case GST_AUDIO_CHANNEL_POSITION_FRONT_MONO:
   199         f[1] = n;
   187       case GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT:
       
   188       case GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT:
   200         *has_f = TRUE;
   189         *has_f = TRUE;
   201         break;
   190         if (f[0] == -1)
   202       case GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT:
   191           f[0] = n;
   203         f[0] = n;
   192         else
   204         *has_f = TRUE;
   193           f[1] = n;
   205         break;
       
   206       case GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT:
       
   207         f[2] = n;
       
   208         *has_f = TRUE;
       
   209         break;
   194         break;
   210       case GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER:
   195       case GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER:
   211         c[1] = n;
   196       case GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:
       
   197       case GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER:
   212         *has_c = TRUE;
   198         *has_c = TRUE;
   213         break;
   199         if (c[0] == -1)
   214       case GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:
   200           c[0] = n;
   215         c[0] = n;
   201         else
   216         *has_c = TRUE;
   202           c[1] = n;
   217         break;
       
   218       case GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER:
       
   219         c[2] = n;
       
   220         *has_c = TRUE;
       
   221         break;
   203         break;
   222       case GST_AUDIO_CHANNEL_POSITION_REAR_CENTER:
   204       case GST_AUDIO_CHANNEL_POSITION_REAR_CENTER:
   223         r[1] = n;
   205       case GST_AUDIO_CHANNEL_POSITION_REAR_LEFT:
       
   206       case GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT:
   224         *has_r = TRUE;
   207         *has_r = TRUE;
   225         break;
   208         if (r[0] == -1)
   226       case GST_AUDIO_CHANNEL_POSITION_REAR_LEFT:
   209           r[0] = n;
   227         r[0] = n;
   210         else
   228         *has_r = TRUE;
   211           r[1] = n;
   229         break;
       
   230       case GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT:
       
   231         r[2] = n;
       
   232         *has_r = TRUE;
       
   233         break;
   212         break;
   234       case GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT:
   213       case GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT:
   235         s[0] = n;
   214       case GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT:
   236         *has_s = TRUE;
   215         *has_s = TRUE;
   237         break;
   216         if (s[0] == -1)
   238       case GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT:
   217           s[0] = n;
   239         s[2] = n;
   218         else
   240         *has_s = TRUE;
   219           s[1] = n;
   241         break;
   220         break;
   242       case GST_AUDIO_CHANNEL_POSITION_LFE:
   221       case GST_AUDIO_CHANNEL_POSITION_LFE:
   243         *has_b = TRUE;
   222         *has_b = TRUE;
   244         b[1] = n;
   223         b[0] = n;
   245         break;
   224         break;
   246       default:
   225       default:
   247         break;
   226         break;
   248     }
   227     }
   249   }
   228   }
   250 }
   229 }
   251 
   230 
   252 static void
   231 static void
   253 gst_channel_mix_fill_one_other (gfloat ** matrix,
   232 gst_channel_mix_fill_one_other (gfloat ** matrix,
   254     AudioConvertFmt * from_caps, gint * from_idx,
   233     AudioConvertFmt * from_caps, gint * from_idx,
   255     AudioConvertFmt * to_caps, gint * to_idx, gfloat ratio)
   234     GstAudioChannelPosition from_pos_l,
   256 {
   235     GstAudioChannelPosition from_pos_r,
   257 
   236     GstAudioChannelPosition from_pos_c,
   258   /* src & dst have center => passthrough */
   237     AudioConvertFmt * to_caps, gint * to_idx,
   259   if (from_idx[1] != -1 && to_idx[1] != -1) {
   238     GstAudioChannelPosition to_pos_l,
   260     matrix[from_idx[1]][to_idx[1]] = ratio;
   239     GstAudioChannelPosition to_pos_r,
   261   }
   240     GstAudioChannelPosition to_pos_c, gfloat ratio)
   262 
   241 {
   263   /* src & dst have left => passthrough */
   242   gfloat in_r, out_r[2] = { 0.f, 0.f };
   264   if (from_idx[0] != -1 && to_idx[0] != -1) {
   243 
   265     matrix[from_idx[0]][to_idx[0]] = ratio;
   244   /*
   266   }
   245    * The idea is that we add up from the input (which means that if we
   267 
   246    * have stereo input, we divide their sum by two) and put that in
   268   /* src & dst have right => passthrough */
   247    * the matrix for their output ratio (given in $ratio).
   269   if (from_idx[2] != -1 && to_idx[2] != -1) {
   248    * For left channels, we need to invert the signal sign (* -1).
   270     matrix[from_idx[2]][to_idx[2]] = ratio;
   249    */
   271   }
   250 
   272 
   251   if (from_caps->pos[from_idx[0]] == from_pos_c)
   273   /* src has left & dst has center => put into center */
   252     in_r = 1.0;
   274   if (from_idx[0] != -1 && to_idx[1] != -1 && from_idx[1] != -1) {
   253   else
   275     matrix[from_idx[0]][to_idx[1]] = 0.5 * ratio;
   254     in_r = 0.5;
   276   } else if (from_idx[0] != -1 && to_idx[1] != -1 && from_idx[1] == -1) {
   255 
   277     matrix[from_idx[0]][to_idx[1]] = ratio;
   256   if (to_caps->pos[to_idx[0]] == to_pos_l)
   278   }
   257     out_r[0] = in_r * -ratio;
   279 
   258   else
   280   /* src has right & dst has center => put into center */
   259     out_r[0] = in_r * ratio;
   281   if (from_idx[2] != -1 && to_idx[1] != -1 && from_idx[1] != -1) {
   260 
   282     matrix[from_idx[2]][to_idx[1]] = 0.5 * ratio;
   261   if (to_idx[1] != -1) {
   283   } else if (from_idx[2] != -1 && to_idx[1] != -1 && from_idx[1] == -1) {
   262     if (to_caps->pos[to_idx[1]] == to_pos_l)
   284     matrix[from_idx[2]][to_idx[1]] = ratio;
   263       out_r[1] = in_r * -ratio;
   285   }
   264     else
   286 
   265       out_r[1] = in_r * ratio;
   287   /* src has center & dst has left => passthrough */
   266   }
   288   if (from_idx[1] != -1 && to_idx[0] != -1 && from_idx[0] != -1) {
   267 
   289     matrix[from_idx[1]][to_idx[0]] = 0.5 * ratio;
   268   matrix[from_idx[0]][to_idx[0]] = out_r[0];
   290   } else if (from_idx[1] != -1 && to_idx[0] != -1 && from_idx[0] == -1) {
   269   if (to_idx[1] != -1)
   291     matrix[from_idx[1]][to_idx[0]] = ratio;
   270     matrix[from_idx[0]][to_idx[1]] = out_r[1];
   292   }
   271   if (from_idx[1] != -1) {
   293 
   272     matrix[from_idx[1]][to_idx[0]] = out_r[0];
   294   /* src has center & dst has right => passthrough */
   273     if (to_idx[1] != -1)
   295   if (from_idx[1] != -1 && to_idx[2] != -1 && from_idx[2] != -1) {
   274       matrix[from_idx[1]][to_idx[1]] = out_r[1];
   296     matrix[from_idx[1]][to_idx[2]] = 0.5 * ratio;
   275   }
   297   } else if (from_idx[1] != -1 && to_idx[2] != -1 && from_idx[2] == -1) {
   276 }
   298     matrix[from_idx[1]][to_idx[2]] = ratio;
       
   299   }
       
   300 }
       
   301 
       
   302 #define RATIO_CENTER_FRONT (1.0 / sqrt (2.0))
       
   303 #define RATIO_CENTER_SIDE (1.0 / 2.0)
       
   304 #define RATIO_CENTER_REAR (1.0 / sqrt (8.0))
       
   305 
   277 
   306 #define RATIO_FRONT_CENTER (1.0 / sqrt (2.0))
   278 #define RATIO_FRONT_CENTER (1.0 / sqrt (2.0))
   307 #define RATIO_FRONT_SIDE (1.0 / sqrt (2.0))
   279 #define RATIO_FRONT_REAR (1.0 / sqrt (2.0))
   308 #define RATIO_FRONT_REAR (1.0 / 2.0)
   280 #define RATIO_FRONT_BASS (1.0)
   309 
   281 #define RATIO_REAR_BASS (1.0 / sqrt (2.0))
   310 #define RATIO_SIDE_CENTER (1.0 / 2.0)
       
   311 #define RATIO_SIDE_FRONT (1.0 / sqrt (2.0))
       
   312 #define RATIO_SIDE_REAR (1.0 / sqrt (2.0))
       
   313 
       
   314 #define RATIO_CENTER_BASS (1.0 / sqrt (2.0))
   282 #define RATIO_CENTER_BASS (1.0 / sqrt (2.0))
   315 #define RATIO_FRONT_BASS (1.0)
       
   316 #define RATIO_SIDE_BASS (1.0 / sqrt (2.0))
       
   317 #define RATIO_REAR_BASS (1.0 / sqrt (2.0))
       
   318 
   283 
   319 static void
   284 static void
   320 gst_channel_mix_fill_others (AudioConvertCtx * this)
   285 gst_channel_mix_fill_others (AudioConvertCtx * this)
   321 {
   286 {
   322   gboolean in_has_front = FALSE, out_has_front = FALSE,
   287   gboolean in_has_front = FALSE, out_has_front = FALSE,
   323       in_has_center = FALSE, out_has_center = FALSE,
   288       in_has_center = FALSE, out_has_center = FALSE,
   324       in_has_rear = FALSE, out_has_rear = FALSE,
   289       in_has_rear = FALSE, out_has_rear = FALSE,
   325       in_has_side = FALSE, out_has_side = FALSE,
   290       in_has_side = FALSE, out_has_side = FALSE,
   326       in_has_bass = FALSE, out_has_bass = FALSE;
   291       in_has_bass = FALSE, out_has_bass = FALSE;
   327   /* LEFT, RIGHT, MONO */
   292   gint in_f[2] = { -1, -1 }, out_f[2] = {
   328   gint in_f[3] = { -1, -1, -1 };
   293   -1, -1}, in_c[2] = {
   329   gint out_f[3] = { -1, -1, -1 };
   294   -1, -1}, out_c[2] = {
   330   /* LOC, ROC, CENTER */
   295   -1, -1}, in_r[2] = {
   331   gint in_c[3] = { -1, -1, -1 };
   296   -1, -1}, out_r[2] = {
   332   gint out_c[3] = { -1, -1, -1 };
   297   -1, -1}, in_s[2] = {
   333   /* RLEFT, RRIGHT, RCENTER */
   298   -1, -1}, out_s[2] = {
   334   gint in_r[3] = { -1, -1, -1 };
   299   -1, -1}, in_b[2] = {
   335   gint out_r[3] = { -1, -1, -1 };
   300   -1, -1}, out_b[2] = {
   336   /* SLEFT, INVALID, SRIGHT */
   301   -1, -1};
   337   gint in_s[3] = { -1, -1, -1 };
       
   338   gint out_s[3] = { -1, -1, -1 };
       
   339   /* INVALID, LFE, INVALID */
       
   340   gint in_b[3] = { -1, -1, -1 };
       
   341   gint out_b[3] = { -1, -1, -1 };
       
   342 
   302 
   343   /* First see where (if at all) the various channels from/to
   303   /* First see where (if at all) the various channels from/to
   344    * which we want to convert are located in our matrix/array. */
   304    * which we want to convert are located in our matrix/array. */
   345   gst_channel_mix_detect_pos (&this->in,
   305   gst_channel_mix_detect_pos (&this->in,
   346       in_f, &in_has_front,
   306       in_f, &in_has_front,
   349   gst_channel_mix_detect_pos (&this->out,
   309   gst_channel_mix_detect_pos (&this->out,
   350       out_f, &out_has_front,
   310       out_f, &out_has_front,
   351       out_c, &out_has_center, out_r, &out_has_rear,
   311       out_c, &out_has_center, out_r, &out_has_rear,
   352       out_s, &out_has_side, out_b, &out_has_bass);
   312       out_s, &out_has_side, out_b, &out_has_bass);
   353 
   313 
   354   /* The general idea here is:
   314   /* center/front */
   355    * - if the source has a channel that the destination doesn't have mix
       
   356    *   it into the nearest available destination channel
       
   357    * - if the destination has a channel that the source doesn't have mix
       
   358    *   the nearest source channel into the destination channel
       
   359    *
       
   360    * The ratio for the mixing becomes lower as the distance between the
       
   361    * channels gets larger
       
   362    */
       
   363 
       
   364   /* center <-> front/side/rear */
       
   365   if (!in_has_center && in_has_front && out_has_center) {
   315   if (!in_has_center && in_has_front && out_has_center) {
   366     gst_channel_mix_fill_one_other (this->matrix,
   316     gst_channel_mix_fill_one_other (this->matrix,
   367         &this->in, in_f, &this->out, out_c, RATIO_CENTER_FRONT);
   317         &this->in, in_f,
   368   } else if (!in_has_center && !in_has_front && in_has_side && out_has_center) {
   318         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
   369     gst_channel_mix_fill_one_other (this->matrix,
   319         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
   370         &this->in, in_s, &this->out, out_c, RATIO_CENTER_SIDE);
   320         GST_AUDIO_CHANNEL_POSITION_FRONT_MONO,
   371   } else if (!in_has_center && !in_has_front && !in_has_side && in_has_rear
   321         &this->out, out_c,
   372       && out_has_center) {
   322         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
   373     gst_channel_mix_fill_one_other (this->matrix, &this->in, in_r, &this->out,
   323         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
   374         out_c, RATIO_CENTER_REAR);
   324         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, RATIO_FRONT_CENTER);
   375   } else if (in_has_center && !out_has_center && out_has_front) {
   325   } else if (in_has_center && !out_has_center && out_has_front) {
   376     gst_channel_mix_fill_one_other (this->matrix,
   326     gst_channel_mix_fill_one_other (this->matrix,
   377         &this->in, in_c, &this->out, out_f, RATIO_CENTER_FRONT);
   327         &this->in, in_c,
   378   } else if (in_has_center && !out_has_center && !out_has_front && out_has_side) {
   328         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
       
   329         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
       
   330         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
       
   331         &this->out, out_f,
       
   332         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
       
   333         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
       
   334         GST_AUDIO_CHANNEL_POSITION_FRONT_MONO, RATIO_FRONT_CENTER);
       
   335   }
       
   336 
       
   337   /* rear/front */
       
   338   if (!in_has_rear && in_has_front && out_has_rear) {
   379     gst_channel_mix_fill_one_other (this->matrix,
   339     gst_channel_mix_fill_one_other (this->matrix,
   380         &this->in, in_c, &this->out, out_s, RATIO_CENTER_SIDE);
   340         &this->in, in_f,
   381   } else if (in_has_center && !out_has_center && !out_has_front && !out_has_side
   341         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
   382       && out_has_rear) {
   342         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
   383     gst_channel_mix_fill_one_other (this->matrix, &this->in, in_c, &this->out,
   343         GST_AUDIO_CHANNEL_POSITION_FRONT_MONO,
   384         out_r, RATIO_CENTER_REAR);
   344         &this->out, out_r,
   385   }
   345         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
   386 
   346         GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
   387   /* front <-> center/side/rear */
   347         GST_AUDIO_CHANNEL_POSITION_REAR_CENTER, RATIO_FRONT_REAR);
   388   if (!in_has_front && in_has_center && !in_has_side && out_has_front) {
   348   } else if (in_has_rear && !out_has_rear && out_has_front) {
   389     gst_channel_mix_fill_one_other (this->matrix,
   349     gst_channel_mix_fill_one_other (this->matrix,
   390         &this->in, in_c, &this->out, out_f, RATIO_CENTER_FRONT);
   350         &this->in, in_r,
   391   } else if (!in_has_front && !in_has_center && in_has_side && out_has_front) {
   351         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
   392     gst_channel_mix_fill_one_other (this->matrix,
   352         GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
   393         &this->in, in_s, &this->out, out_f, RATIO_FRONT_SIDE);
   353         GST_AUDIO_CHANNEL_POSITION_REAR_CENTER,
   394   } else if (!in_has_front && in_has_center && in_has_side && out_has_front) {
   354         &this->out, out_f,
   395     gst_channel_mix_fill_one_other (this->matrix,
   355         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
   396         &this->in, in_c, &this->out, out_f, 0.5 * RATIO_CENTER_FRONT);
   356         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
   397     gst_channel_mix_fill_one_other (this->matrix,
   357         GST_AUDIO_CHANNEL_POSITION_FRONT_MONO, RATIO_FRONT_REAR);
   398         &this->in, in_s, &this->out, out_f, 0.5 * RATIO_FRONT_SIDE);
   358   }
   399   } else if (!in_has_front && !in_has_center && !in_has_side && in_has_rear
   359 
   400       && out_has_front) {
   360   /* bass/any */
   401     gst_channel_mix_fill_one_other (this->matrix, &this->in, in_r, &this->out,
       
   402         out_f, RATIO_FRONT_REAR);
       
   403   } else if (in_has_front && out_has_center && !out_has_side && !out_has_front) {
       
   404     gst_channel_mix_fill_one_other (this->matrix,
       
   405         &this->in, in_f, &this->out, out_c, RATIO_CENTER_FRONT);
       
   406   } else if (in_has_front && !out_has_center && out_has_side && !out_has_front) {
       
   407     gst_channel_mix_fill_one_other (this->matrix,
       
   408         &this->in, in_f, &this->out, out_s, RATIO_FRONT_SIDE);
       
   409   } else if (in_has_front && out_has_center && out_has_side && !out_has_front) {
       
   410     gst_channel_mix_fill_one_other (this->matrix,
       
   411         &this->in, in_f, &this->out, out_c, 0.5 * RATIO_CENTER_FRONT);
       
   412     gst_channel_mix_fill_one_other (this->matrix,
       
   413         &this->in, in_f, &this->out, out_s, 0.5 * RATIO_FRONT_SIDE);
       
   414   } else if (in_has_front && !out_has_center && !out_has_side && !out_has_front
       
   415       && out_has_rear) {
       
   416     gst_channel_mix_fill_one_other (this->matrix, &this->in, in_f, &this->out,
       
   417         out_r, RATIO_FRONT_REAR);
       
   418   }
       
   419 
       
   420   /* side <-> center/front/rear */
       
   421   if (!in_has_side && in_has_front && !in_has_rear && out_has_side) {
       
   422     gst_channel_mix_fill_one_other (this->matrix,
       
   423         &this->in, in_f, &this->out, out_s, RATIO_FRONT_SIDE);
       
   424   } else if (!in_has_side && !in_has_front && in_has_rear && out_has_side) {
       
   425     gst_channel_mix_fill_one_other (this->matrix,
       
   426         &this->in, in_r, &this->out, out_s, RATIO_SIDE_REAR);
       
   427   } else if (!in_has_side && in_has_front && in_has_rear && out_has_side) {
       
   428     gst_channel_mix_fill_one_other (this->matrix,
       
   429         &this->in, in_f, &this->out, out_s, 0.5 * RATIO_FRONT_SIDE);
       
   430     gst_channel_mix_fill_one_other (this->matrix,
       
   431         &this->in, in_r, &this->out, out_s, 0.5 * RATIO_SIDE_REAR);
       
   432   } else if (!in_has_side && !in_has_front && !in_has_rear && in_has_center
       
   433       && out_has_side) {
       
   434     gst_channel_mix_fill_one_other (this->matrix, &this->in, in_c, &this->out,
       
   435         out_s, RATIO_CENTER_SIDE);
       
   436   } else if (in_has_side && out_has_front && !out_has_rear && !out_has_side) {
       
   437     gst_channel_mix_fill_one_other (this->matrix,
       
   438         &this->in, in_s, &this->out, out_f, RATIO_FRONT_SIDE);
       
   439   } else if (in_has_side && !out_has_front && out_has_rear && !out_has_side) {
       
   440     gst_channel_mix_fill_one_other (this->matrix,
       
   441         &this->in, in_s, &this->out, out_r, RATIO_SIDE_REAR);
       
   442   } else if (in_has_side && out_has_front && out_has_rear && !out_has_side) {
       
   443     gst_channel_mix_fill_one_other (this->matrix,
       
   444         &this->in, in_s, &this->out, out_f, 0.5 * RATIO_FRONT_SIDE);
       
   445     gst_channel_mix_fill_one_other (this->matrix,
       
   446         &this->in, in_s, &this->out, out_r, 0.5 * RATIO_SIDE_REAR);
       
   447   } else if (in_has_side && !out_has_front && !out_has_rear && out_has_center
       
   448       && !out_has_side) {
       
   449     gst_channel_mix_fill_one_other (this->matrix, &this->in, in_s, &this->out,
       
   450         out_c, RATIO_CENTER_SIDE);
       
   451   }
       
   452 
       
   453   /* rear <-> center/front/side */
       
   454   if (!in_has_rear && in_has_side && out_has_rear) {
       
   455     gst_channel_mix_fill_one_other (this->matrix,
       
   456         &this->in, in_s, &this->out, out_r, RATIO_SIDE_REAR);
       
   457   } else if (!in_has_rear && !in_has_side && in_has_front && out_has_rear) {
       
   458     gst_channel_mix_fill_one_other (this->matrix,
       
   459         &this->in, in_f, &this->out, out_r, RATIO_FRONT_REAR);
       
   460   } else if (!in_has_rear && !in_has_side && !in_has_front && in_has_center
       
   461       && out_has_rear) {
       
   462     gst_channel_mix_fill_one_other (this->matrix, &this->in, in_c, &this->out,
       
   463         out_r, RATIO_CENTER_REAR);
       
   464   } else if (in_has_rear && !out_has_rear && out_has_side) {
       
   465     gst_channel_mix_fill_one_other (this->matrix,
       
   466         &this->in, in_r, &this->out, out_s, RATIO_SIDE_REAR);
       
   467   } else if (in_has_rear && !out_has_rear && !out_has_side && out_has_front) {
       
   468     gst_channel_mix_fill_one_other (this->matrix,
       
   469         &this->in, in_r, &this->out, out_f, RATIO_FRONT_REAR);
       
   470   } else if (in_has_rear && !out_has_rear && !out_has_side && !out_has_front
       
   471       && out_has_center) {
       
   472     gst_channel_mix_fill_one_other (this->matrix, &this->in, in_r, &this->out,
       
   473         out_c, RATIO_CENTER_REAR);
       
   474   }
       
   475 
       
   476   /* bass <-> any */
       
   477   if (in_has_bass && !out_has_bass) {
   361   if (in_has_bass && !out_has_bass) {
       
   362     if (out_has_front) {
       
   363       gst_channel_mix_fill_one_other (this->matrix,
       
   364           &this->in, in_b,
       
   365           GST_AUDIO_CHANNEL_POSITION_INVALID,
       
   366           GST_AUDIO_CHANNEL_POSITION_INVALID,
       
   367           GST_AUDIO_CHANNEL_POSITION_LFE,
       
   368           &this->out, out_f,
       
   369           GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
       
   370           GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
       
   371           GST_AUDIO_CHANNEL_POSITION_FRONT_MONO, RATIO_FRONT_BASS);
       
   372     }
   478     if (out_has_center) {
   373     if (out_has_center) {
   479       gst_channel_mix_fill_one_other (this->matrix,
   374       gst_channel_mix_fill_one_other (this->matrix,
   480           &this->in, in_b, &this->out, out_c, RATIO_CENTER_BASS);
   375           &this->in, in_b,
   481     }
   376           GST_AUDIO_CHANNEL_POSITION_INVALID,
   482     if (out_has_front) {
   377           GST_AUDIO_CHANNEL_POSITION_INVALID,
   483       gst_channel_mix_fill_one_other (this->matrix,
   378           GST_AUDIO_CHANNEL_POSITION_LFE,
   484           &this->in, in_b, &this->out, out_f, RATIO_FRONT_BASS);
   379           &this->out, out_c,
   485     }
   380           GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
   486     if (out_has_side) {
   381           GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
   487       gst_channel_mix_fill_one_other (this->matrix,
   382           GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, RATIO_CENTER_BASS);
   488           &this->in, in_b, &this->out, out_s, RATIO_SIDE_BASS);
       
   489     }
   383     }
   490     if (out_has_rear) {
   384     if (out_has_rear) {
   491       gst_channel_mix_fill_one_other (this->matrix,
   385       gst_channel_mix_fill_one_other (this->matrix,
   492           &this->in, in_b, &this->out, out_r, RATIO_REAR_BASS);
   386           &this->in, in_b,
       
   387           GST_AUDIO_CHANNEL_POSITION_INVALID,
       
   388           GST_AUDIO_CHANNEL_POSITION_INVALID,
       
   389           GST_AUDIO_CHANNEL_POSITION_LFE,
       
   390           &this->out, out_r,
       
   391           GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
       
   392           GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
       
   393           GST_AUDIO_CHANNEL_POSITION_REAR_CENTER, RATIO_REAR_BASS);
   493     }
   394     }
   494   } else if (!in_has_bass && out_has_bass) {
   395   } else if (!in_has_bass && out_has_bass) {
       
   396     if (in_has_front) {
       
   397       gst_channel_mix_fill_one_other (this->matrix,
       
   398           &this->in, in_f,
       
   399           GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
       
   400           GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
       
   401           GST_AUDIO_CHANNEL_POSITION_FRONT_MONO,
       
   402           &this->out, out_b,
       
   403           GST_AUDIO_CHANNEL_POSITION_INVALID,
       
   404           GST_AUDIO_CHANNEL_POSITION_INVALID,
       
   405           GST_AUDIO_CHANNEL_POSITION_LFE, RATIO_FRONT_BASS);
       
   406     }
   495     if (in_has_center) {
   407     if (in_has_center) {
   496       gst_channel_mix_fill_one_other (this->matrix,
   408       gst_channel_mix_fill_one_other (this->matrix,
   497           &this->in, in_c, &this->out, out_b, RATIO_CENTER_BASS);
   409           &this->in, in_c,
   498     }
   410           GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
   499     if (in_has_front) {
   411           GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
   500       gst_channel_mix_fill_one_other (this->matrix,
   412           GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
   501           &this->in, in_f, &this->out, out_b, RATIO_FRONT_BASS);
   413           &this->out, out_b,
   502     }
   414           GST_AUDIO_CHANNEL_POSITION_INVALID,
   503     if (in_has_side) {
   415           GST_AUDIO_CHANNEL_POSITION_INVALID,
   504       gst_channel_mix_fill_one_other (this->matrix,
   416           GST_AUDIO_CHANNEL_POSITION_LFE, RATIO_CENTER_BASS);
   505           &this->in, in_s, &this->out, out_b, RATIO_REAR_BASS);
       
   506     }
   417     }
   507     if (in_has_rear) {
   418     if (in_has_rear) {
   508       gst_channel_mix_fill_one_other (this->matrix,
   419       gst_channel_mix_fill_one_other (this->matrix,
   509           &this->in, in_r, &this->out, out_b, RATIO_REAR_BASS);
   420           &this->in, in_r,
   510     }
   421           GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
   511   }
   422           GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
       
   423           GST_AUDIO_CHANNEL_POSITION_REAR_CENTER,
       
   424           &this->out, out_b,
       
   425           GST_AUDIO_CHANNEL_POSITION_INVALID,
       
   426           GST_AUDIO_CHANNEL_POSITION_INVALID,
       
   427           GST_AUDIO_CHANNEL_POSITION_LFE, RATIO_REAR_BASS);
       
   428     }
       
   429   }
       
   430 
       
   431   /* FIXME: side */
   512 }
   432 }
   513 
   433 
   514 /*
   434 /*
   515  * Normalize output values.
   435  * Normalize output values.
   516  */
   436  */
   531       top = sum;
   451       top = sum;
   532     }
   452     }
   533   }
   453   }
   534 
   454 
   535   /* normalize to this */
   455   /* normalize to this */
   536   if (top == 0.0)
       
   537     return;
       
   538 
       
   539   for (j = 0; j < this->out.channels; j++) {
   456   for (j = 0; j < this->out.channels; j++) {
   540     for (i = 0; i < this->in.channels; i++) {
   457     for (i = 0; i < this->in.channels; i++) {
   541       this->matrix[i][j] /= top;
   458       this->matrix[i][j] /= top;
   542     }
   459     }
   543   }
   460   }
   544 }
   461 }
   545 
   462 
   546 static gboolean
       
   547 gst_channel_mix_fill_special (AudioConvertCtx * this)
       
   548 {
       
   549   AudioConvertFmt *in = &this->in, *out = &this->out;
       
   550 
       
   551   /* Special, standard conversions here */
       
   552 
       
   553   /* Mono<->Stereo, just a fast-path */
       
   554   if (in->channels == 2 && out->channels == 1 &&
       
   555       ((in->pos[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT &&
       
   556               in->pos[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT) ||
       
   557           (in->pos[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT &&
       
   558               in->pos[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT)) &&
       
   559       out->pos[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_MONO) {
       
   560     this->matrix[0][0] = 0.5;
       
   561     this->matrix[1][0] = 0.5;
       
   562     return TRUE;
       
   563   } else if (in->channels == 1 && out->channels == 2 &&
       
   564       ((out->pos[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT &&
       
   565               out->pos[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT) ||
       
   566           (out->pos[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT &&
       
   567               out->pos[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT)) &&
       
   568       in->pos[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_MONO) {
       
   569     this->matrix[0][0] = 1.0;
       
   570     this->matrix[0][1] = 1.0;
       
   571     return TRUE;
       
   572   }
       
   573 
       
   574   /* TODO: 5.1 <-> Stereo and other standard conversions */
       
   575 
       
   576   return FALSE;
       
   577 }
       
   578 
       
   579 /*
   463 /*
   580  * Automagically generate conversion matrix.
   464  * Automagically generate conversion matrix.
   581  */
   465  */
   582 
   466 
   583 static void
   467 static void
   584 gst_channel_mix_fill_matrix (AudioConvertCtx * this)
   468 gst_channel_mix_fill_matrix (AudioConvertCtx * this)
   585 {
   469 {
   586   if (gst_channel_mix_fill_special (this))
       
   587     return;
       
   588 
       
   589   gst_channel_mix_fill_identical (this);
   470   gst_channel_mix_fill_identical (this);
   590 
   471   gst_channel_mix_fill_compatible (this);
   591   if (!this->in.unpositioned_layout) {
   472   gst_channel_mix_fill_others (this);
   592     gst_channel_mix_fill_compatible (this);
   473   gst_channel_mix_fill_normalize (this);
   593     gst_channel_mix_fill_others (this);
       
   594     gst_channel_mix_fill_normalize (this);
       
   595   }
       
   596 }
   474 }
   597 
   475 
   598 /* only call after this->out and this->in are filled in */
   476 /* only call after this->out and this->in are filled in */
   599 #ifdef __SYMBIAN32__
   477 #ifdef __SYMBIAN32__
   600 EXPORT_C
   478 EXPORT_C
   602 
   480 
   603 void
   481 void
   604 gst_channel_mix_setup_matrix (AudioConvertCtx * this)
   482 gst_channel_mix_setup_matrix (AudioConvertCtx * this)
   605 {
   483 {
   606   gint i, j;
   484   gint i, j;
       
   485   GString *s;
   607 
   486 
   608   /* don't lose memory */
   487   /* don't lose memory */
   609   gst_channel_mix_unset_matrix (this);
   488   gst_channel_mix_unset_matrix (this);
   610 
   489 
   611   /* temp storage */
   490   /* temp storage */
   624   }
   503   }
   625 
   504 
   626   /* setup the matrix' internal values */
   505   /* setup the matrix' internal values */
   627   gst_channel_mix_fill_matrix (this);
   506   gst_channel_mix_fill_matrix (this);
   628 
   507 
   629 #ifndef GST_DISABLE_GST_DEBUG
       
   630   /* debug */
   508   /* debug */
   631   {
   509   s = g_string_new ("Matrix for");
   632     GString *s;
   510   g_string_append_printf (s, " %d -> %d: ",
   633     s = g_string_new ("Matrix for");
   511       this->in.channels, this->out.channels);
   634     g_string_append_printf (s, " %d -> %d: ",
   512   g_string_append (s, "{");
   635         this->in.channels, this->out.channels);
   513   for (i = 0; i < this->in.channels; i++) {
   636     g_string_append (s, "{");
   514     if (i != 0)
   637     for (i = 0; i < this->in.channels; i++) {
   515       g_string_append (s, ",");
   638       if (i != 0)
   516     g_string_append (s, " {");
       
   517     for (j = 0; j < this->out.channels; j++) {
       
   518       if (j != 0)
   639         g_string_append (s, ",");
   519         g_string_append (s, ",");
   640       g_string_append (s, " {");
   520       g_string_append_printf (s, " %f", this->matrix[i][j]);
   641       for (j = 0; j < this->out.channels; j++) {
       
   642         if (j != 0)
       
   643           g_string_append (s, ",");
       
   644         g_string_append_printf (s, " %f", this->matrix[i][j]);
       
   645       }
       
   646       g_string_append (s, " }");
       
   647     }
   521     }
   648     g_string_append (s, " }");
   522     g_string_append (s, " }");
   649     GST_DEBUG (s->str);
   523   }
   650     g_string_free (s, TRUE);
   524   g_string_append (s, " }");
   651   }
   525   GST_DEBUG (s->str);
   652 #endif
   526   g_string_free (s, TRUE);
   653 }
   527 }
   654 #ifdef __SYMBIAN32__
   528 #ifdef __SYMBIAN32__
   655 EXPORT_C
   529 EXPORT_C
   656 #endif
   530 #endif
   657 
   531