int dst_voices;
int src_rate;
int dst_rate;
+ int sample_size;
unsigned int pitch;
unsigned int pos;
signed short last_S1[MAX_VOICES];
};
-static void mix(struct rate_private_data *data, int voices,
- signed short *src_ptr, int src_size,
- signed short *dst_ptr, int dst_size)
+static void mix16(struct rate_private_data *data, int voices,
+ signed short *src_ptr, int src_size,
+ signed short *dst_ptr, int dst_size)
{
unsigned int pos;
signed int val;
src += (pos >> SHIFT) * voices;
pos &= MASK;
S1 = S2;
- S2 = *src;
+ if ((src - src_ptr) < src_size * voices)
+ S2 = *src;
}
val = S1 + ((S2 - S1) * (signed int)pos) / BITS;
if (val < -32768)
}
data->last_S1[voice] = S1;
data->last_S2[voice] = S2;
+ data->pos = pos;
+ }
+}
+
+static void mix8(struct rate_private_data *data, int voices,
+ unsigned char *src_ptr, int src_size,
+ unsigned char *dst_ptr, int dst_size)
+{
+ unsigned int pos;
+ signed int val;
+ signed short S1, S2;
+ int voice;
+ unsigned char *src, *dst;
+ int size;
+
+ for (voice = 0; voice < voices; ++voice) {
+ pos = data->pos;
+ S1 = data->last_S1[voice];
+ S2 = data->last_S2[voice];
+ src = src_ptr + voice;
+ dst = dst_ptr + voice;
+ size = dst_size;
+ if (pos >> SHIFT) {
+ src += ((pos >> SHIFT) - 1) * voices;
+ pos &= MASK;
+ S1 = S2;
+ S2 = (*src << 8) ^ 0x8000;
+ }
+ while (size-- > 0) {
+ if (pos >> SHIFT) {
+ src += (pos >> SHIFT) * voices;
+ pos &= MASK;
+ S1 = S2;
+ if ((src - src_ptr) < src_size * voices)
+ S2 = (*src << 8) ^ 0x8000;
+ }
+ val = S1 + ((S2 - S1) * (signed int)pos) / BITS;
+ if (val < -32768)
+ val = -32768;
+ else if (val > 32767)
+ val = 32767;
+ *dst = (val >> 8) ^ 0x0080;
+ dst += voices;
+ pos += data->pitch;
+ }
+ data->last_S1[voice] = S1;
+ data->last_S2[voice] = S2;
+ data->pos = pos;
}
- data->pos = pos;
}
static ssize_t rate_transfer(snd_pcm_plugin_t *plugin,
data = (struct rate_private_data *)snd_pcm_plugin_extra_data(plugin);
if (data == NULL)
return -EINVAL;
- mix(data, data->src_voices,
- (signed short *)src_ptr, src_size / (data->src_voices * 2),
- (signed short *)dst_ptr, dst_size / (data->dst_voices * 2));
- return dst_size / (2 * data->src_voices) * (2 * data->src_voices);
+ if (data->sample_size == 2) {
+ mix16(data, data->src_voices,
+ (signed short *)src_ptr, src_size / (data->src_voices * 2),
+ (signed short *)dst_ptr, dst_size / (data->dst_voices * 2));
+ } else {
+ mix8(data, data->src_voices,
+ src_ptr, src_size / data->src_voices,
+ dst_ptr, dst_size / data->dst_voices);
+ }
+ return dst_size / (data->sample_size * data->src_voices) * (data->sample_size * data->src_voices);
}
static int rate_action(snd_pcm_plugin_t *plugin, snd_pcm_plugin_action_t action)
return -EINVAL;
data = (struct rate_private_data *)snd_pcm_plugin_extra_data(plugin);
res = (((size * data->pitch) + (BITS/2)) >> SHIFT);
- res = res / (data->src_voices*2) * (data->src_voices*2);
- /* Why this? */
- if (size < 128*1024) {
- if (data->old_src_size == size)
- return data->old_dst_size;
- data->old_src_size = size;
- data->old_dst_size = res;
+ res = res / (data->src_voices*data->sample_size) * (data->src_voices*data->sample_size);
+ if (data->old_src_size > 0) {
+ if ((data->old_src_size % size) == 0) {
+ return (data->old_dst_size * data->old_src_size) / size;
+ } else if ((size % data->old_src_size) == 0) {
+ return (data->old_dst_size * size) / data->old_src_size;
+ }
}
+ data->old_src_size = size;
+ data->old_dst_size = res;
return res;
}
return -EINVAL;
data = (struct rate_private_data *)snd_pcm_plugin_extra_data(plugin);
res = (((size << SHIFT) + (data->pitch / 2)) / data->pitch);
- res = res / (data->dst_voices*2) * (data->dst_voices*2);
- /* Why this? */
- if (size < 128*1024) {
- if (data->old_dst_size == size)
- return data->old_src_size;
- data->old_dst_size = size;
- data->old_src_size = res;
+ res = res / (data->dst_voices*data->sample_size) * (data->dst_voices*data->sample_size);
+ if (data->old_dst_size > 0) {
+ if ((data->old_dst_size % size) == 0) {
+ return (data->old_src_size * data->old_dst_size) / size;
+ } else if ((size % data->old_dst_size) == 0) {
+ return (data->old_src_size * size) / data->old_dst_size;
+ }
}
+ data->old_dst_size = size;
+ data->old_src_size = res;
return res;
}
if (dst_format->voices < 1 || dst_format->voices > MAX_VOICES)
return -EINVAL;
- if (src_format->format != SND_PCM_SFMT_S16_LE ||
- dst_format->format != SND_PCM_SFMT_S16_LE)
+ if (src_format->format != SND_PCM_SFMT_S16_LE &&
+ src_format->format != SND_PCM_SFMT_U8)
return -EINVAL;
if (src_format->rate == dst_format->rate)
return -EINVAL;
if (plugin == NULL)
return -ENOMEM;
data = (struct rate_private_data *)snd_pcm_plugin_extra_data(plugin);
+ data->sample_size = src_format->format == SND_PCM_SFMT_S16_LE ? 2 : 1;
data->src_voices = src_format->voices;
data->dst_voices = dst_format->voices;
data->src_rate = src_format->rate;
int src_voices;
int dst_voices;
int width; /* in bites */
- int flg_merge: 1,
- flg_signed: 1;
+ int flg_signed: 1;
};
static void divide_8bit(char *src_ptr, char *dst_ptr, int size)
unsigned char *dst_ptr,
int size)
{
+ printf("unsigned!!\n");
while (size-- > 0) {
- *dst_ptr++ = (*src_ptr + *(src_ptr + 1)) / 2;
+ *dst_ptr++ = ((int)*src_ptr + (int)*(src_ptr + 1)) / 2;
src_ptr += 2;
}
}
int size)
{
while (size-- > 0) {
- *dst_ptr++ = (*src_ptr + *(src_ptr + 1)) / 2;
+ *dst_ptr++ = ((int)*src_ptr + (int)*(src_ptr + 1)) / 2;
src_ptr += 2;
}
}
int size)
{
while (size-- > 0) {
- *dst_ptr++ = (*src_ptr + *(src_ptr + 1)) / 2;
+ *dst_ptr++ = ((int)*src_ptr + (int)*(src_ptr + 1)) / 2;
src_ptr += 2;
}
}
int size)
{
while (size-- > 0) {
- *dst_ptr++ = (*src_ptr + *(src_ptr + 1)) / 2;
+ *dst_ptr++ = ((int)*src_ptr + (int)*(src_ptr + 1)) / 2;
src_ptr += 2;
}
}
} else {
merge_8bit_unsigned(src_ptr, dst_ptr, src_size / 2);
}
- return (src_size * data->src_voices) / data->dst_voices;
} else {
divide_8bit(src_ptr, dst_ptr, src_size);
- return (src_size * data->dst_voices) / data->src_voices;
}
break;
case 16:
} else {
merge_16bit_unsigned((short *)src_ptr, (short *)dst_ptr, src_size / 4);
}
- return (src_size * data->src_voices) / data->dst_voices;
} else {
divide_16bit((short *)src_ptr, (short *)dst_ptr, src_size / 2);
- return (src_size * data->dst_voices) / data->src_voices;
}
break;
default:
return -EINVAL;
}
+ return (src_size * data->dst_voices) / data->src_voices;
}
static ssize_t voices_src_size(snd_pcm_plugin_t *plugin, size_t size)
if (!plugin || size <= 0)
return -EINVAL;
data = (struct voices_private_data *)snd_pcm_plugin_extra_data(plugin);
- if (data->src_voices < data->dst_voices)
- return (size * data->src_voices) / data->dst_voices;
- else
- return (size * data->dst_voices) / data->src_voices;
+ return (size * data->src_voices) / data->dst_voices;
}
static ssize_t voices_dst_size(snd_pcm_plugin_t *plugin, size_t size)
if (!plugin || size <= 0)
return -EINVAL;
data = (struct voices_private_data *)snd_pcm_plugin_extra_data(plugin);
- if (data->src_voices > data->dst_voices)
- return (size * data->src_voices) / data->dst_voices;
- else
- return (size * data->dst_voices) / data->src_voices;
+ return (size * data->dst_voices) / data->src_voices;
}
int snd_pcm_plugin_build_voices(snd_pcm_format_t *src_format,
data->src_voices = src_format->voices;
data->dst_voices = dst_format->voices;
data->width = snd_pcm_format_width(src_format->format);
- data->flg_merge = src_format->voices > dst_format->voices;
data->flg_signed = snd_pcm_format_signed(src_format->format);
plugin->transfer = voices_transfer;
plugin->src_size = voices_src_size;