由于芯片硬件AO的音量控制封装,无法灵活调节音量,故添加软件调节音量。
调节建议:在调节音量之前将AO设备音量设置为较大,然后再使用软件调节pcm输出。
代码:
#include <stdbool.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define PCM_SIZE_MAX 4*1024
/*
* 设置16BIT的PCM音量,转换一次的最大size不能超过PCM_SIZE_MAX
*
* src:pcm源数据
*
* size:pcm数据的长度,比如80将音量设置为之前的80%
*
* 设置音量-百分比
*/
static bool pcm_16bit_volume_cover(char * src, int size, int volume)
{
int i = 0;
char dst[PCM_SIZE_MAX] =
{
0
};
if (size > PCM_SIZE_MAX)
{
return false;
}
if (volume == 100)
{
return true;
}
if (volume == 0)
{
memset(src, 0, size);
return true;
}
memset(dst, 0, PCM_SIZE_MAX);
struct timeval tv1, tv2;
gettimeofday(&tv1, NULL);
float bar = volume * 1.0 / 100;
for (i = 0; i < size; i += 2)
{
short src_data = (src[i + 1] << 8) | (src[i] &0xFF);
src_data = src_data * bar;
if (src_data > 32767)
{
src_data = 32767;
}
else if (src_data < -32768)
{
src_data = -32768;
}
dst[i] = src_data & 0xFF;
dst[i + 1] = (src_data >> 8) & 0xFF;
}
memcpy(src, dst, size);
gettimeofday(&tv2, NULL);
printf("cover volume%d time:%d ms \n", volume,
tv2.tv_sec * 1000 + tv2.tv_usec / 1000 - tv1.tv_sec * 1000 - tv1.tv_usec / 1000);
return true;
}
/*测试代码*/
int main(int argc, char * *argv)
{
if (argc != 2)
{
printf("input file name \n");
return 0;
}
/*获取源文件的大小*/
char * src_name = argv[1];
int src_fd = open(src_name, O_RDONLY);
if (src_fd < 0)
{
printf("open %s fail \n", argv[1]);
return 0;
}
int src_size = lseek(src_fd, 0, SEEK_END);
lseek(src_fd, 0, SEEK_SET);
/*读取源文件数据*/
char * src_data = (char *) malloc(src_size);
read(src_fd, src_data, src_size);
close(src_fd);
printf("read %s %dkb \n", src_name, src_size / 1024);
/*复制一个副本*/
char * dst_data = (char *) malloc(src_size);
memcpy(dst_data, src_data, src_size);
/*转换音量为80的数据*/
pcm_16bit_volume_cover(dst_data, src_size, 80);
/*写入音量为80的数据*/
char * p = strrchr(src_name, '.');
if (p)
{
p[0] = '\0';
}
char dst_name[128] =
{
0
};
sprintf(dst_name, "%s-%d%%.pcm", src_name, 50);
int dst_fd = open(dst_name, O_WRONLY | O_CREAT);
write(dst_fd, dst_data, src_size);
close(dst_fd);
free(dst_data);
free(src_data);
return 0;
}