Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  *  Rate conversion Plug-In
0003  *  Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
0004  *
0005  *
0006  *   This library is free software; you can redistribute it and/or modify
0007  *   it under the terms of the GNU Library General Public License as
0008  *   published by the Free Software Foundation; either version 2 of
0009  *   the License, or (at your option) any later version.
0010  *
0011  *   This program is distributed in the hope that it will be useful,
0012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014  *   GNU Library General Public License for more details.
0015  *
0016  *   You should have received a copy of the GNU Library General Public
0017  *   License along with this library; if not, write to the Free Software
0018  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
0019  *
0020  */
0021   
0022 #include <linux/time.h>
0023 #include <sound/core.h>
0024 #include <sound/pcm.h>
0025 #include "pcm_plugin.h"
0026 
0027 #define SHIFT   11
0028 #define BITS    (1<<SHIFT)
0029 #define R_MASK  (BITS-1)
0030 
0031 /*
0032  *  Basic rate conversion plugin
0033  */
0034 
0035 struct rate_channel {
0036     signed short last_S1;
0037     signed short last_S2;
0038 };
0039  
0040 typedef void (*rate_f)(struct snd_pcm_plugin *plugin,
0041                const struct snd_pcm_plugin_channel *src_channels,
0042                struct snd_pcm_plugin_channel *dst_channels,
0043                int src_frames, int dst_frames);
0044 
0045 struct rate_priv {
0046     unsigned int pitch;
0047     unsigned int pos;
0048     rate_f func;
0049     snd_pcm_sframes_t old_src_frames, old_dst_frames;
0050     struct rate_channel channels[];
0051 };
0052 
0053 static void rate_init(struct snd_pcm_plugin *plugin)
0054 {
0055     unsigned int channel;
0056     struct rate_priv *data = (struct rate_priv *)plugin->extra_data;
0057     data->pos = 0;
0058     for (channel = 0; channel < plugin->src_format.channels; channel++) {
0059         data->channels[channel].last_S1 = 0;
0060         data->channels[channel].last_S2 = 0;
0061     }
0062 }
0063 
0064 static void resample_expand(struct snd_pcm_plugin *plugin,
0065                 const struct snd_pcm_plugin_channel *src_channels,
0066                 struct snd_pcm_plugin_channel *dst_channels,
0067                 int src_frames, int dst_frames)
0068 {
0069     unsigned int pos = 0;
0070     signed int val;
0071     signed short S1, S2;
0072     signed short *src, *dst;
0073     unsigned int channel;
0074     int src_step, dst_step;
0075     int src_frames1, dst_frames1;
0076     struct rate_priv *data = (struct rate_priv *)plugin->extra_data;
0077     struct rate_channel *rchannels = data->channels;
0078     
0079     for (channel = 0; channel < plugin->src_format.channels; channel++) {
0080         pos = data->pos;
0081         S1 = rchannels->last_S1;
0082         S2 = rchannels->last_S2;
0083         if (!src_channels[channel].enabled) {
0084             if (dst_channels[channel].wanted)
0085                 snd_pcm_area_silence(&dst_channels[channel].area, 0, dst_frames, plugin->dst_format.format);
0086             dst_channels[channel].enabled = 0;
0087             continue;
0088         }
0089         dst_channels[channel].enabled = 1;
0090         src = (signed short *)src_channels[channel].area.addr +
0091             src_channels[channel].area.first / 8 / 2;
0092         dst = (signed short *)dst_channels[channel].area.addr +
0093             dst_channels[channel].area.first / 8 / 2;
0094         src_step = src_channels[channel].area.step / 8 / 2;
0095         dst_step = dst_channels[channel].area.step / 8 / 2;
0096         src_frames1 = src_frames;
0097         dst_frames1 = dst_frames;
0098         while (dst_frames1-- > 0) {
0099             if (pos & ~R_MASK) {
0100                 pos &= R_MASK;
0101                 S1 = S2;
0102                 if (src_frames1-- > 0) {
0103                     S2 = *src;
0104                     src += src_step;
0105                 }
0106             }
0107             val = S1 + ((S2 - S1) * (signed int)pos) / BITS;
0108             if (val < -32768)
0109                 val = -32768;
0110             else if (val > 32767)
0111                 val = 32767;
0112             *dst = val;
0113             dst += dst_step;
0114             pos += data->pitch;
0115         }
0116         rchannels->last_S1 = S1;
0117         rchannels->last_S2 = S2;
0118         rchannels++;
0119     }
0120     data->pos = pos;
0121 }
0122 
0123 static void resample_shrink(struct snd_pcm_plugin *plugin,
0124                 const struct snd_pcm_plugin_channel *src_channels,
0125                 struct snd_pcm_plugin_channel *dst_channels,
0126                 int src_frames, int dst_frames)
0127 {
0128     unsigned int pos = 0;
0129     signed int val;
0130     signed short S1, S2;
0131     signed short *src, *dst;
0132     unsigned int channel;
0133     int src_step, dst_step;
0134     int src_frames1, dst_frames1;
0135     struct rate_priv *data = (struct rate_priv *)plugin->extra_data;
0136     struct rate_channel *rchannels = data->channels;
0137 
0138     for (channel = 0; channel < plugin->src_format.channels; ++channel) {
0139         pos = data->pos;
0140         S1 = rchannels->last_S1;
0141         S2 = rchannels->last_S2;
0142         if (!src_channels[channel].enabled) {
0143             if (dst_channels[channel].wanted)
0144                 snd_pcm_area_silence(&dst_channels[channel].area, 0, dst_frames, plugin->dst_format.format);
0145             dst_channels[channel].enabled = 0;
0146             continue;
0147         }
0148         dst_channels[channel].enabled = 1;
0149         src = (signed short *)src_channels[channel].area.addr +
0150             src_channels[channel].area.first / 8 / 2;
0151         dst = (signed short *)dst_channels[channel].area.addr +
0152             dst_channels[channel].area.first / 8 / 2;
0153         src_step = src_channels[channel].area.step / 8 / 2;
0154         dst_step = dst_channels[channel].area.step / 8 / 2;
0155         src_frames1 = src_frames;
0156         dst_frames1 = dst_frames;
0157         while (dst_frames1 > 0) {
0158             S1 = S2;
0159             if (src_frames1-- > 0) {
0160                 S2 = *src;
0161                 src += src_step;
0162             }
0163             if (pos & ~R_MASK) {
0164                 pos &= R_MASK;
0165                 val = S1 + ((S2 - S1) * (signed int)pos) / BITS;
0166                 if (val < -32768)
0167                     val = -32768;
0168                 else if (val > 32767)
0169                     val = 32767;
0170                 *dst = val;
0171                 dst += dst_step;
0172                 dst_frames1--;
0173             }
0174             pos += data->pitch;
0175         }
0176         rchannels->last_S1 = S1;
0177         rchannels->last_S2 = S2;
0178         rchannels++;
0179     }
0180     data->pos = pos;
0181 }
0182 
0183 static snd_pcm_sframes_t rate_src_frames(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t frames)
0184 {
0185     struct rate_priv *data;
0186     snd_pcm_sframes_t res;
0187 
0188     if (snd_BUG_ON(!plugin))
0189         return -ENXIO;
0190     if (frames == 0)
0191         return 0;
0192     data = (struct rate_priv *)plugin->extra_data;
0193     if (plugin->src_format.rate < plugin->dst_format.rate) {
0194         res = (((frames * data->pitch) + (BITS/2)) >> SHIFT);
0195     } else {
0196         res = DIV_ROUND_CLOSEST(frames << SHIFT, data->pitch);
0197     }
0198     if (data->old_src_frames > 0) {
0199         snd_pcm_sframes_t frames1 = frames, res1 = data->old_dst_frames;
0200         while (data->old_src_frames < frames1) {
0201             frames1 >>= 1;
0202             res1 <<= 1;
0203         }
0204         while (data->old_src_frames > frames1) {
0205             frames1 <<= 1;
0206             res1 >>= 1;
0207         }
0208         if (data->old_src_frames == frames1)
0209             return res1;
0210     }
0211     data->old_src_frames = frames;
0212     data->old_dst_frames = res;
0213     return res;
0214 }
0215 
0216 static snd_pcm_sframes_t rate_dst_frames(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t frames)
0217 {
0218     struct rate_priv *data;
0219     snd_pcm_sframes_t res;
0220 
0221     if (snd_BUG_ON(!plugin))
0222         return -ENXIO;
0223     if (frames == 0)
0224         return 0;
0225     data = (struct rate_priv *)plugin->extra_data;
0226     if (plugin->src_format.rate < plugin->dst_format.rate) {
0227         res = DIV_ROUND_CLOSEST(frames << SHIFT, data->pitch);
0228     } else {
0229         res = (((frames * data->pitch) + (BITS/2)) >> SHIFT);
0230     }
0231     if (data->old_dst_frames > 0) {
0232         snd_pcm_sframes_t frames1 = frames, res1 = data->old_src_frames;
0233         while (data->old_dst_frames < frames1) {
0234             frames1 >>= 1;
0235             res1 <<= 1;
0236         }
0237         while (data->old_dst_frames > frames1) {
0238             frames1 <<= 1;
0239             res1 >>= 1;
0240         }
0241         if (data->old_dst_frames == frames1)
0242             return res1;
0243     }
0244     data->old_dst_frames = frames;
0245     data->old_src_frames = res;
0246     return res;
0247 }
0248 
0249 static snd_pcm_sframes_t rate_transfer(struct snd_pcm_plugin *plugin,
0250                  const struct snd_pcm_plugin_channel *src_channels,
0251                  struct snd_pcm_plugin_channel *dst_channels,
0252                  snd_pcm_uframes_t frames)
0253 {
0254     snd_pcm_uframes_t dst_frames;
0255     struct rate_priv *data;
0256 
0257     if (snd_BUG_ON(!plugin || !src_channels || !dst_channels))
0258         return -ENXIO;
0259     if (frames == 0)
0260         return 0;
0261 #ifdef CONFIG_SND_DEBUG
0262     {
0263         unsigned int channel;
0264         for (channel = 0; channel < plugin->src_format.channels; channel++) {
0265             if (snd_BUG_ON(src_channels[channel].area.first % 8 ||
0266                        src_channels[channel].area.step % 8))
0267                 return -ENXIO;
0268             if (snd_BUG_ON(dst_channels[channel].area.first % 8 ||
0269                        dst_channels[channel].area.step % 8))
0270                 return -ENXIO;
0271         }
0272     }
0273 #endif
0274 
0275     dst_frames = rate_dst_frames(plugin, frames);
0276     if (dst_frames > dst_channels[0].frames)
0277         dst_frames = dst_channels[0].frames;
0278     data = (struct rate_priv *)plugin->extra_data;
0279     data->func(plugin, src_channels, dst_channels, frames, dst_frames);
0280     return dst_frames;
0281 }
0282 
0283 static int rate_action(struct snd_pcm_plugin *plugin,
0284                enum snd_pcm_plugin_action action,
0285                unsigned long udata)
0286 {
0287     if (snd_BUG_ON(!plugin))
0288         return -ENXIO;
0289     switch (action) {
0290     case INIT:
0291     case PREPARE:
0292         rate_init(plugin);
0293         break;
0294     default:
0295         break;
0296     }
0297     return 0;   /* silenty ignore other actions */
0298 }
0299 
0300 int snd_pcm_plugin_build_rate(struct snd_pcm_substream *plug,
0301                   struct snd_pcm_plugin_format *src_format,
0302                   struct snd_pcm_plugin_format *dst_format,
0303                   struct snd_pcm_plugin **r_plugin)
0304 {
0305     int err;
0306     struct rate_priv *data;
0307     struct snd_pcm_plugin *plugin;
0308 
0309     if (snd_BUG_ON(!r_plugin))
0310         return -ENXIO;
0311     *r_plugin = NULL;
0312 
0313     if (snd_BUG_ON(src_format->channels != dst_format->channels))
0314         return -ENXIO;
0315     if (snd_BUG_ON(src_format->channels <= 0))
0316         return -ENXIO;
0317     if (snd_BUG_ON(src_format->format != SNDRV_PCM_FORMAT_S16))
0318         return -ENXIO;
0319     if (snd_BUG_ON(dst_format->format != SNDRV_PCM_FORMAT_S16))
0320         return -ENXIO;
0321     if (snd_BUG_ON(src_format->rate == dst_format->rate))
0322         return -ENXIO;
0323 
0324     err = snd_pcm_plugin_build(plug, "rate conversion",
0325                    src_format, dst_format,
0326                    struct_size(data, channels,
0327                            src_format->channels),
0328                    &plugin);
0329     if (err < 0)
0330         return err;
0331     data = (struct rate_priv *)plugin->extra_data;
0332     if (src_format->rate < dst_format->rate) {
0333         data->pitch = ((src_format->rate << SHIFT) + (dst_format->rate >> 1)) / dst_format->rate;
0334         data->func = resample_expand;
0335     } else {
0336         data->pitch = ((dst_format->rate << SHIFT) + (src_format->rate >> 1)) / src_format->rate;
0337         data->func = resample_shrink;
0338     }
0339     data->pos = 0;
0340     rate_init(plugin);
0341     data->old_src_frames = data->old_dst_frames = 0;
0342     plugin->transfer = rate_transfer;
0343     plugin->src_frames = rate_src_frames;
0344     plugin->dst_frames = rate_dst_frames;
0345     plugin->action = rate_action;
0346     *r_plugin = plugin;
0347     return 0;
0348 }