#include
#include
#include
#define FILE_NAME_SIZE_MAX 50
#define SAMPLE_RATE 16000
#define AMPLITUDE 32767
#define PI 3.14159265358979323846
#define AUDIO_TIME_SEC_LEN (0.1)
#define AUDIO_LOUDNESS_DBFS (-12)
typedef struct {
char key;
int freq1;
int freq2;
} dtmf_st;
static const dtmf_st dtmf_table[] = {
{'1', 697, 1209}, {'2', 697, 1336}, {'3', 697, 1477}, {'A', 697, 1633},
{'4', 770, 1209}, {'5', 770, 1336}, {'6', 770, 1477}, {'B', 770, 1633},
{'7', 852, 1209}, {'8', 852, 1336}, {'9', 852, 1477}, {'C', 852, 1633},
{'#', 941, 1209}, {'0', 941, 1336}, {'D', 941, 1477}
};
static const int dtmf_table_size = sizeof(dtmf_table) / sizeof(dtmf_st);
int main(void) {
char key = 0;
short *audio_data = NULL;
int num_samples = 0;
int freq1 = -1, freq2 = -1;
double dtmf_amp = 0;
double time_in_sec = 0;
double sin_wave1 = 0, sin_wave2 = 0;
char filename[FILE_NAME_SIZE_MAX] = {0};
FILE *fp = NULL;
int i = 0;
while(1) {
printf("\nPlease input key:");
if(scanf("%c", &key) != 1) {
while(getchar() != '\n');
printf("Input error! \nPlease input (0-9,A-D,#,*)\n");
continue;
}
for(i=0;i<dtmf_table_size; i++) {
if(key == dtmf_table[i].key) {
break;
}
}
if(i < dtmf_table_size) {
freq1 = dtmf_table[i].freq1;
freq2 = dtmf_table[i].freq2;
// printf("%d %d\n",freq1,freq2);
break;
}
else {
printf("Invalid key!\n");
}
}
num_samples = SAMPLE_RATE * AUDIO_TIME_SEC_LEN;
audio_data = malloc(sizeof(short) * num_samples);
if(audio_data == NULL) {
goto ERROR;
}
dtmf_amp = pow(10, AUDIO_LOUDNESS_DBFS/20.0) * AMPLITUDE;
for (int i = 0; i < num_samples; i++) {
time_in_sec = i / (double) SAMPLE_RATE;
sin_wave1 = sin(2 * PI * freq1 * time_in_sec);
sin_wave2 = sin(2 * PI * freq2 * time_in_sec);
audio_data[i] = dtmf_amp * (sin_wave1 + sin_wave2);
}
sprintf(filename, "key_%c.raw", key);
fp = fopen(filename, "wb");
if (!fp) {
perror("fopen");
goto ERROR;
}
if(fwrite(audio_data, sizeof(short), num_samples, fp) < 0)
{
perror("fwrite");
goto ERROR;
}
ERROR:
if (fp) {
fclose(fp);
fp = NULL;
}
if (audio_data) {
free(audio_data);
audio_data = NULL;
}
return 0;
}
使用C语言编写一段程序,程序可以实现将输入的16进制数据使用fsk调制成音频数据。
1.输入为一个16进制数,输出为一个音频文件。例如输入0x55,对应的二进制为01010101,fsk调制后的频率组合为 低频-高频-低频-高频-低频-高频-低频-高频。
2.音频采样率为16000Hz。
3.fsk调制时使用的两个信号分别为1209Hz和697Hz。
4.fsk使用的调制信号的幅值为-12dB。
5.fsk调制时每个频率的信号长度为10ms。
6.两个不同频率的信号拼接时要注意保持相位上的连续性。
在linux系统中,数据保存为raw格式
#include
#include
#include
#include
#include
#include
#include
#define AMPLITUDE 32767.0
#define SAMPLE_RATE (16000.0)
#define LOW_FREQ 697
#define HIGH_FREQ 1209
#define AUDIO_LOUDNESS_DBFS (-12.0)
#define SIGNAL_LENGTH 0.01
#define BIN_STR_SIZE_MAX 64
#define PI 3.14159265358979323846
#define OUTPUT_FILE "output.raw"
struct wave {
int freq;
double amplitude;
};
static const struct wave waves[2] = {
{LOW_FREQ, pow(10, AUDIO_LOUDNESS_DBFS / 20.0)*AMPLITUDE},
{HIGH_FREQ, pow(10, AUDIO_LOUDNESS_DBFS / 20.0)*AMPLITUDE}
};
static const char *hex_table[] = {"0000", "0001", "0010", "0011", "0100",
"0101", "0110", "0111", "1000", "1001",
"1010", "1011", "1100", "1101", "1110",
"1111"};
void hex_to_bin(char *hex_string, char *bin_string)
{
int i = 0;
char hex_digit = 0;
for (i = 0; hex_string[i] != '\0'; i++) {
hex_digit = hex_string[i];
if (hex_digit >= '0' && hex_digit <= '9') {
strcat(bin_string, hex_table[hex_digit - '0']);
} else if (hex_digit >= 'A' && hex_digit <= 'F') {
strcat(bin_string, hex_table[hex_digit - 'A' + 10]);
} else if (hex_digit >= 'a' && hex_digit <= 'f') {
strcat(bin_string, hex_table[hex_digit - 'a' + 10]);
} else {
printf("error invalid digit '%c'\n", hex_digit);
goto ERROR;
}
}
if (strlen(bin_string) == 0) {
printf("error input is null\n");
goto ERROR;
}
if (strlen(bin_string) % 4 != 0) {
printf("error:invalid len %d\n", (int)strlen(bin_string));
goto ERROR;
}
ERROR:
return ;
}
double generate_fsk_signal(int fi,int freq,int amplitude,int num_samples,short *audio_data)
{
static int pos = 0;
double t = 0;
for (int i = 0; i < num_samples; i++)
{
audio_data[pos++] = (short)(amplitude * sin(2 * PI * freq * t + fi));
t += 1/SAMPLE_RATE;
}
return (2 * PI * freq * (t+1/SAMPLE_RATE) + fi); //相位对齐
}
void generate_sin_wave(int n,char *bin_string,short *audio_data,int num_samples)
{
int len = strlen(bin_string);
int i=0 ,j=0;
double fi = 0;
int index = 0;
for(i=0;i<len;i++)
{
index = bin_string[i] - '0';
if(index == 0) {
fi = generate_fsk_signal(fi,waves[index].freq,waves[index].amplitude,num_samples,audio_data);
}
else if(index == 1) {
fi = generate_fsk_signal(fi,waves[index].freq,waves[index].amplitude,num_samples,audio_data);
}
}
}
char *get_hex_str(char *str)
{
int len = strlen(str);
if(str == NULL) {
goto ERROR;
}
if (len == 0 || len > BIN_STR_SIZE_MAX / 4) {
goto ERROR;
}
if(strstr(str,"0x") || strstr(str,"0X") ) {
str += 2;
}
for(int i=0; i<strlen(str); i++){
if(!isxdigit(str[i])){
printf("error: invalid hex_string\n");
goto ERROR;
}
}
return str;
ERROR:
return NULL;
}
int main(int argc, char **argv)
{
int i = 0, j = 0;
int index = 0;
int num_samples = 0;
FILE *fp = NULL;
int signal_length = 0;
char *hex_str = NULL;
double last_fi = 0;
char bin_string[BIN_STR_SIZE_MAX] = {0};
short *audio_data = NULL;
if (argc < 2) {
printf("Usage: %s hex_string\n", argv[0]);
goto ERROR;
}
hex_str = get_hex_str(argv[1]);
if(hex_str == NULL){
goto ERROR;
}
hex_to_bin(hex_str, bin_string);
num_samples = SIGNAL_LENGTH * SAMPLE_RATE;
signal_length = strlen(bin_string) * num_samples;
audio_data = malloc(sizeof(short) * signal_length);
memset(audio_data,0,sizeof(short) * signal_length);
generate_sin_wave(signal_length,bin_string,audio_data,num_samples);
fp = fopen(OUTPUT_FILE, "wb");
if (fp == NULL) {
perror("fopen");
goto ERROR;
}
if(fwrite(audio_data, sizeof(short), signal_length, fp) < 0) {
perror("fwrite");
goto ERROR;
}
ERROR:
if (fp) {
fclose(fp);
fp = NULL;
}
if (audio_data) {
free(audio_data);
audio_data = NULL;
}
return 0;
}
响度常用的单位是dBSPL、dBFS、dBpa、dBm0。
dB计算:对于功率,dB = 10 * lg(A/B)。对于电压或电流,dB= 20 * lg(A/B)。此处A,B代表参与比较的功率值或者电流、电压值。
以dBfs举例说明:
dBfs = 20 * lg(x/32767)。
其中32767是16bit采样精度时最大的值,x取值0 ~ 32767。所以dBfs的最大值为当x取值为32767时的值,即0dBfs。
采样率是指对模拟音频信号进行取样的每秒次数,通常以赫兹 (Hz) 为单位表示。当我们要将模拟音频信号转换成数字形式时(例如录制音频或将其从 CD 转换成数字格式),需要对其进行采样,即在时间轴上不断地对音频信号进行抽样,获取一系列数字值。采样率越高,每秒中采集到的样本数量就越多,这可以提供更精确的音频表示,但同时也会增加所需的存储空间和处理能力。
振幅是指波形的最大偏移量,通常用单位分贝 (dB) 或电平(以电压为单位)来表示。在音频信号中,振幅描述了声音的响度或强度。例如,在一段声音信号中,振幅越高,则声音会听起来更响亮、更强烈,振幅越低,则声音会听起来更柔和、更安静。与采样率不同,振幅是代表音频信号能量的单一数值,其大小与声音响度直接相关。
y = A * sin(ωt + ϕ)
其中,A代表振幅,即波形的最大偏移量;
ω代表角频率,即单位时间内的变化角度;
t代表时间;
ϕ代表初相位,即初始状态下正弦波图像的左右平移位置
φ = arcsin(y/A) - wt
每秒中采集到的样本数量就越多,这可以提供更精确的音频表示,但同时也会增加所需的存储空间和处理能力。
振幅是指波形的最大偏移量,通常用单位分贝 (dB) 或电平(以电压为单位)来表示。在音频信号中,振幅描述了声音的响度或强度。例如,在一段声音信号中,振幅越高,则声音会听起来更响亮、更强烈,振幅越低,则声音会听起来更柔和、更安静。与采样率不同,振幅是代表音频信号能量的单一数值,其大小与声音响度直接相关。
y = A * sin(ωt + ϕ)
其中,A代表振幅,即波形的最大偏移量;
ω代表角频率,即单位时间内的变化角度;
t代表时间;
ϕ代表初相位,即初始状态下正弦波图像的左右平移位置
φ = arcsin(y/A) - wt