📄 pcmtran.cpp
字号:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pcmtran.h"
#define MAKETAG(a, b, c, d) (((((long)a)%256)<<24) | ((((long)b)%256)<<16) | ((((long)c)%256)<<8) | ((((long)d)%256)<<0))
typedef struct tagPcmTranCtrl
{
unsigned long tag ;
int s_c ; /* source channels */
int s_sw ; /* source sample width */
int s_sr ; /* source sample rate (hz) */
int d_c ; /* dest channels */
int d_sw ; /* dest sample width */
int d_sr ; /* dest sample rate (hz) */
int s_max_len ; /* source max input length */
unsigned char *w_b0 ; /* work buffer 0 */
unsigned char *w_b1 ; /* work buffer 1 */
} PcmTranCtrl_t, *pPcmTranCtrl_t ;
static unsigned long _tag = (unsigned long) MAKETAG('P', 'T', 'R', 'A') ;
/* sample rate convert */
static int sr_conv(unsigned char *inbuf0, unsigned char *inbuf1, int width, int channel, unsigned char *outbuf, int level) ;
/* sample width convert */
static int sw_conv(unsigned char *inbuf, int source_width, int channel, int dest_width, unsigned char *outbuf) ;
unsigned long pcm_transform_open(int source_channels, int source_sample_width, int source_samples_rate, int dest_channels, int dest_sample_width, int dest_samples_rate, int max_input_len)
{
unsigned long result = 0 ;
PcmTranCtrl_t *p ;
int err = 1 ;
if (
(source_channels == 1 || source_channels == 2)
&& (source_sample_width == 8 || source_sample_width == 16 || source_sample_width == 24 || source_sample_width == 32)
&& (source_samples_rate == 11025 || source_samples_rate == 22050 || source_samples_rate == 44100)
&& (dest_channels == 1 || dest_channels == 2)
&& (dest_sample_width == 8 || dest_sample_width == 16 || dest_sample_width == 24 || dest_sample_width == 32)
&& (dest_samples_rate == 11025 || dest_samples_rate == 22050 || dest_samples_rate == 44100)
&& (!(source_channels == dest_channels && source_sample_width == dest_sample_width && source_samples_rate == dest_samples_rate))
&& max_input_len > 0
)
{
p = (PcmTranCtrl_t *)malloc(sizeof(PcmTranCtrl_t)) ;
if (p)
{
size_t size ;
memset(p, 0x00, sizeof(PcmTranCtrl_t)) ;
p->tag = _tag ;
p->s_c = source_channels ;
p->s_sw = source_sample_width ;
p->s_sr = source_samples_rate ;
p->d_c = dest_channels ;
p->d_sw = dest_sample_width ;
p->d_sr = dest_samples_rate ;
p->s_max_len = max_input_len ;
size = (size_t)((p->s_c>p->d_c)?p->s_c:p->d_c) ;
size *= (size_t)(((p->s_sw>p->d_sw)?p->s_sw:p->d_sw)/8) ;
size *= (size_t)(max_input_len/(p->s_c*(p->s_sw/8))+1) ;
if (size > 0
&& (p->w_b0 = (unsigned char *)malloc(size))
&& (p->w_b1 = (unsigned char *)malloc(size))
)
{
err = 0 ;
}
}
}
if (err)
{
if (p
&& p->w_b0
)
free(p->w_b0) ;
if (p
&& p->w_b1
)
free(p->w_b1) ;
if (p)
free(p) ;
}
else
{
result = (unsigned long)p ;
}
return (result) ;
}
int pcm_transform_close(unsigned long handle)
{
int result = -1 ;
PcmTranCtrl_t *p ;
p = (PcmTranCtrl_t *)handle ;
if (p
&& p->tag == _tag
)
{
if (p->w_b0)
free(p->w_b0) ;
if (p->w_b1)
free(p->w_b1) ;
free(p) ;
result = 0 ;
}
return (result) ;
}
int pcm_transform(unsigned long handle, char *inbuf, int inbuf_len, char **outbuf, int *output_len)
{
int result = PCMTRAN_ERR_GENERAL ;
PcmTranCtrl_t *p ;
p = (PcmTranCtrl_t *)handle ;
if (p && p->tag == _tag
&& inbuf
&& *outbuf)
{
int i, j ;
int _c = p->s_c ; /* current channels */
int _sw = p->s_sw ; /* current sample width */
int _sr = p->s_sr ; /* current sample rate */
int _sn = inbuf_len/(_c*(_sw/8)) ; /* current samples number */
unsigned char *s_b ; /* source buffer */
unsigned char *d_b ; /* dest buffer */
int len = 0 ;
int _s_sn = _sn ; /* source samples number used to convert */
if (!(pcm_transform_getdestsize(handle, inbuf_len, &len) == 0
&& len <= *output_len
&& inbuf_len <= p->s_max_len
)
)
goto done ;
/* channel convert */
s_b = (unsigned char *)inbuf ;
d_b = (unsigned char *)p->w_b0 ;
if (p->s_c == 1
&& p->d_c == 2
)
{
int w = _sw/8 ;
for (i=0, j=0; i<_sn; i++)
{
memcpy(d_b+j, s_b+i*w, w) ;
j += w ;
memcpy(d_b+j, s_b+i*w, w) ;
j += w ;
}
_c = p->d_c ;
}
else
if (p->s_c == 2
&& p->d_c == 1
)
{
int w = _sw/8 ;
int off = 0 ; /* int off = 0, left channel; int off = w, right channel */
for (i=0, j=0; i<_sn; i++)
{
memcpy(d_b+j, s_b+i*2*w+off, w) ;
j += w ;
}
_c = p->d_c ;
}
else
{
result = PCMTRAN_ERR_SAMCHAN ;
goto done ;
}
/* sampleRate convert */
s_b = (unsigned char *)p->w_b0 ;
d_b = (unsigned char *)p->w_b1 ;
if (p->s_sr == 11025)
{
int w = _sw/8 ;
unsigned char buf[2*4*4] ;
if (p->d_sr == 22050)
{
for (i=0, j=0; i<_sn; i++)
{
int r ;
unsigned char *p0, *p1 ;
p0 = s_b+i*w*_c ;
p1 = s_b+(i+1)*w*_c ;
if (i+1 >= _sn)
p1 = p0 ;
/* get the prev sample (one or two) */
memcpy(d_b+j, p0, w*_c) ;
j += (w*_c) ;
r = sr_conv(p0, p1, w, _c, buf, 1) ;
if (r > 0)
{
memcpy(d_b+j, buf, r) ;
j += r ;
}
else
{
memcpy(d_b+j, p0, w*_c) ;
j += (w*_c) ;
}
}
_sr = p->d_sr ;
_sn = j/(w*_c) ;
_s_sn = _sn/2 ;
}
else
if (p->d_sr == 44100)
{
for (i=0, j=0; i<_sn; i++)
{
int r ;
unsigned char *p0, *p1 ;
p0 = s_b+i*w*_c ;
p1 = s_b+(i+1)*w*_c ;
if (i+1 >= _sn)
p1 = p0 ;
/* get the prev sample (one or two) */
memcpy(d_b+j, p0, w*_c) ;
j += (w*_c) ;
r = sr_conv(p0, p1, w, _c, buf, 3) ;
if (r > 0)
{
memcpy(d_b+j, buf, r) ;
j += r ;
}
else
{
memcpy(d_b+j, p0, w*_c) ;
j += (w*_c) ;
memcpy(d_b+j, p0, w*_c) ;
j += (w*_c) ;
memcpy(d_b+j, p0, w*_c) ;
j += (w*_c) ;
}
}
_sr = p->d_sr ;
_sn = j/(w*_c) ;
_s_sn = _sn/4 ;
}
}
else
if (p->s_sr == 22050)
{
int w = _sw/8 ;
unsigned char buf[2*4*4] ;
if (p->d_sr == 11025)
{
for (i=0, j=0; i<_sn; i++)
{
if ((i%2) == 0)
{
memcpy(d_b+j, s_b+i*w*_c, w*_c) ;
j += (w*_c) ;
}
}
_sr = p->d_sr ;
_sn = j/(w*_c) ;
_s_sn = _sn*2 ;
}
else
if (p->d_sr == 44100)
{
for (i=0, j=0; i<_sn; i++)
{
int r ;
unsigned char *p0, *p1 ;
p0 = s_b+i*w*_c ;
p1 = s_b+(i+1)*w*_c ;
if (i+1 >= _sn)
p1 = p0 ;
/* get the prev sample (one or two) */
memcpy(d_b+j, p0, w*_c) ;
j += (w*_c) ;
r = sr_conv(p0, p1, w, _c, buf, 1) ;
if (r > 0)
{
memcpy(d_b+j, buf, r) ;
j += r ;
}
else
{
memcpy(d_b+j, p0, w*_c) ;
j += (w*_c) ;
}
}
_sr = p->d_sr ;
_sn = j/(w*_c) ;
_s_sn = _sn/2 ;
}
}
else
if (p->s_sr == 44100)
{
int w = _sw/8 ;
unsigned char buf[2*4*4] ;
if (p->d_sr == 11025)
{
for (i=0, j=0; i<_sn; i++)
{
if ((i%4) == 0)
{
memcpy(d_b+j, s_b+i*w*_c, w*_c) ;
j += (w*_c) ;
}
}
_sr = p->d_sr ;
_sn = j/(w*_c) ;
_s_sn = _sn*4 ;
}
else
if (p->d_sr == 22050)
{
for (i=0, j=0; i<_sn; i++)
{
if ((i%2) == 0)
{
memcpy(d_b+j, s_b+i*w*_c, w*_c) ;
j += (w*_c) ;
}
}
_sr = p->d_sr ;
_sn = j/(w*_c) ;
_s_sn = _sn*2 ;
}
}
else
{
result = PCMTRAN_ERR_SAMRATE ;
goto done ;
}
/* sample bitWidth convert */
s_b = (unsigned char *)p->w_b1 ;
d_b = (unsigned char *)p->w_b0 ;
if (p->s_sw != p->d_sw)
{
int r ;
int w = _sw/8 ;
unsigned char buf[2*4*4] ;
for (i=0, j=0; i<_sn; i++)
{
r = sw_conv(s_b+i*w*_c, _sw, _c, p->d_sw, buf) ;
if (r > 0)
{
memcpy(d_b+j, buf, r) ;
j += r ;
}
else
{
result = PCMTRAN_ERR_SAMWIDTH ;
goto done ;
}
}
}
if (output_len)
*output_len = _sn * p->d_c * (p->d_sw/8) ;
memcpy(*outbuf, d_b, _sn * p->d_c * (p->d_sw/8)) ;
result = PCMTRAN_OK ;
}
done:
return (result) ;
}
int pcm_transform_getdestsize(unsigned long handle, int source_size, int *dest_size)
{
int result = -1 ;
PcmTranCtrl_t *p ;
p = (PcmTranCtrl_t *)handle ;
if (p
&& p->tag == _tag
&& source_size > 0
&& dest_size
)
{
int s = source_size / (p->s_c * p->s_sw / 8) ;
if (s > 0)
{
int ds = (s * (p->d_c * p->d_sw * p->d_sr)) / (p->s_c * p->s_sw * p->s_sr) ;
if ((s * (p->d_c * p->d_sw * p->d_sr)) % (p->s_c * p->s_sw * p->s_sr))
ds ++ ;
if (ds > 0)
{
*dest_size = ds * (p->d_c * p->d_sw / 8) ;
result = 0 ;
}
}
}
return (result) ;
}
/*
Function:
Sample rate convert
Description:
Convert bitween 11025Hz,22050Hz,44100Hz PCM Data (8Bit,16Bit,24Bit,32Bit)
*/
static int sr_conv(unsigned char *inbuf0, unsigned char *inbuf1, int width, int channel, unsigned char *outbuf, int level)
{
int result = 0 ;
int i, j ;
int w = width ;
int c = channel ;
int l = level ;
unsigned char *i0 = inbuf0 ;
unsigned char *i1 = inbuf1 ;
unsigned char *o = outbuf ;
long s00, s01 ;
long s10, s11 ;
long s0_0, s0_1, s0_2 ;
long s1_0, s1_1, s1_2 ;
long buf[2*3] ;
int buf_nums = 0 ;
if (i0
&& i1
&& o
&& width > 0
&& width <= 4
)
{
if (w == 1)
{
s00 = ((long)i0[0]) ;
s01 = ((long)i1[0]) ;
if (c == 2)
{
s10 = ((long)i0[w+0]) ;
s11 = ((long)i1[w+0]) ;
}
}
else
if (w == 2)
{
s00 = (((long)i0[1])<<8) | ((long)i0[0]) ;
s01 = (((long)i1[1])<<8) | ((long)i1[0]) ;
if (c == 2)
{
s10 = (((long)i0[w+1])<<8) | ((long)i0[w+0]) ;
s11 = (((long)i1[w+1])<<8) | ((long)i1[w+0]) ;
}
}
else
if (w == 3)
{
s00 = (((long)i0[2])<<16) | (((long)i0[1])<<8) | ((long)i0[0]) ;
s01 = (((long)i1[2])<<16) | (((long)i1[1])<<8) | ((long)i1[0]) ;
if (c == 2)
{
s10 = (((long)i0[w+2])<<16) | (((long)i0[w+1])<<8) | ((long)i0[w+0]) ;
s11 = (((long)i1[w+2])<<16) | (((long)i1[w+1])<<8) | ((long)i1[w+0]) ;
}
}
else
if (w == 4)
{
s00 = (((long)i0[3])<<24) | (((long)i0[2])<<16) | (((long)i0[1])<<8) | ((long)i0[0]) ;
s01 = (((long)i1[3])<<24) | (((long)i1[2])<<16) | (((long)i1[1])<<8) | ((long)i1[0]) ;
if (c == 2)
{
s10 = (((long)i0[w+3])<<24) | (((long)i0[w+2])<<16) | (((long)i0[w+1])<<8) | ((long)i0[w+0]) ;
s11 = (((long)i1[w+3])<<24) | (((long)i1[w+2])<<16) | (((long)i1[w+1])<<8) | ((long)i1[w+0]) ;
}
}
else
{
goto done ;
}
if (l == 1)
{
s0_0 = s00 + (s01-s00)/2 ;
buf[0] = s0_0 ;
buf_nums = 1 ;
if (c == 2)
{
s1_0 = s10 + (s11-s10)/2 ;
buf[1] = s1_0 ;
buf_nums += 1 ;
}
}
else
if (l == 2)
{
s0_0 = s00 + (s01-s00)/3 ;
s0_1 = s00 + (s01-s00)*2/3 ;
buf[0] = s0_0 ;
buf[2] = s0_1 ;
buf_nums = 2 ;
if (c == 2)
{
s1_0 = s10 + (s11-s10)/3 ;
s1_1 = s10 + (s11-s10)*2/3 ;
buf[1] = s1_0 ;
buf[3] = s1_1 ;
buf_nums += 2 ;
}
}
else
if (l == 3)
{
s0_0 = s00 + (s01-s00)/4 ;
s0_1 = s00 + (s01-s00)*2/4 ;
s0_2 = s00 + (s01-s00)*3/4 ;
buf[0] = s0_0 ;
buf[2] = s0_1 ;
buf[4] = s0_2 ;
buf_nums = 3 ;
if (c == 2)
{
s1_0 = s10 + (s11-s10)/4 ;
s1_1 = s10 + (s11-s10)*2/4 ;
s1_2 = s10 + (s11-s10)*3/4 ;
buf[1] = s1_0 ;
buf[3] = s1_1 ;
buf[5] = s1_2 ;
buf_nums += 3 ;
}
}
else
{
goto done ;
}
for (i=0; i<buf_nums; i++)
{
for (j=0; j<w; j++)
{
o[i*w+j] = (unsigned char)((buf[i]>>(j*8))&0xff) ;
result++ ;
}
}
}
done:
return (result) ;
}
/*
Function:
Sample width convert
Description:
Convert bitween 8Bit,16Bit,24Bit,32Bit data
*/
static int sw_conv(unsigned char *inbuf, int source_width, int channel, int dest_width, unsigned char *outbuf)
{
int result = 0 ;
if (inbuf
&& outbuf
)
{
int n ;
int sw = source_width/8 ;
int dw = dest_width/8 ;
if (source_width > dest_width)
{
n = (source_width - dest_width)/8 ;
/* discard lower-bit data */
memcpy(outbuf, inbuf+n, dw) ;
result = dw ;
if (channel == 2)
{
/* discard lower-bit data */
memcpy(outbuf+dw, inbuf+sw+n, dw) ;
result += dw ;
}
}
else
if (source_width < dest_width)
{
n = (dest_width - source_width)/8 ;
/* fill lower-bit data with 0x00 */
memset(outbuf, 0x00, n) ;
memcpy(outbuf+n, inbuf, sw) ;
result = dw ;
if (channel == 2)
{
/* fill lower-bit data with 0x00 */
memset(outbuf+dw, 0x00, n) ;
memcpy(outbuf+dw+n, inbuf+sw, sw) ;
result += dw ;
}
}
}
done:
return (result) ;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -