c - 如何在 C 中制作 Siren 噪声 wav 文件?
问题描述
我已经编写了关于警报器的 wav 文件的代码,但我不确定这是否正确......
这是响起从右到左的警笛声。
960Hz(0.65 秒)和 770Hz(0.5 秒)
我想确认“高”和“低”每 0.65 秒变化一次(我想知道这是否比 0.65 秒快或慢)。
如何仅延迟一侧声音(左或右)的时间(-1ms~1ms)?
我想尝试确认如果我只延迟声音的一侧会发生什么,但我所做的代码不是时间的函数,我不知道如何应用于我的代码。
虽然我尝试将 y[1] 中的 'i' 更改为 'i+48',但声音的周期变短了,整个声音的速度(?)变快了……我只想影响声音时间的一侧,不是整个声音。
我认为这是因为
double level_r = 1.0 - level_l;
这是我的代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
//#include <iostream>
#include <string.h>
#include <math.h>
//#pragma once
#define WAVE_FORMAT_UNKNOWN 0X0000;
#define WAVE_FORMAT_PCM 0X0001;
#define WAVE_FORMAT_MS_ADPCM 0X0002;
#define WAVE_FORMAT_IEEE_FLOAT 0X0003;
#define WAVE_FORMAT_ALAW 0X0006;
#define WAVE_FORMAT_MULAW 0X0007;
#define WAVE_FORMAT_IMA_ADPCM 0X0011;
#define WAVE_FORMAT_YAMAHA_ADPCM 0X0016;
#define WAVE_FORMAT_GSM 0X0031;
#define WAVE_FORMAT_ITU_ADPCM 0X0040;
#define WAVE_FORMAT_MPEG 0X0050;
#define WAVE_FORMAT_EXTENSIBLE 0XFFFE;
#define DURATION 8
#define SAMPLE_RATE 48000
#define CHANNEL 2
#define BIT_RATE 16
typedef struct {
unsigned char ChunkID[4]; // Contains the letters "RIFF" in ASCII form
unsigned int ChunkSize; // This is the size of the rest of the chunk following this number
unsigned char Format[4]; // Contains the letters "WAVE" in ASCII form
} RIFF;
typedef struct {
unsigned char ChunkID[4]; // Contains the letters "fmt " in ASCII form
unsigned int ChunkSize; // 16 for PCM. This is the size of the rest of the Subchunk which follows this number.
unsigned short AudioFormat; // PCM = 1
unsigned short NumChannels; // Mono = 1, Stereo = 2, etc.
unsigned int SampleRate; // 8000, 44100, etc.
unsigned int AvgByteRate; // SampleRate * NumChannels * BitsPerSample/8
unsigned short BlockAlign; // NumChannels * BitsPerSample/8
unsigned short BitPerSample; // 8 bits = 8, 16 bits = 16, etc
} FMT;
typedef struct {
char ChunkID[4]; // Contains the letters "data" in ASCII form
unsigned int ChunkSize; // NumSamples * NumChannels * BitsPerSample/8
} DATA;
typedef struct {
RIFF Riff;
FMT Fmt;
DATA Data;
} WAVE_HEADER;
int
main()
{
FILE* f_out;
#if 0
f_out = fopen("D:\\test.wav", "wb");
#else
f_out = fopen("D:\\test.wav", "wb");
#endif
WAVE_HEADER header;
memcpy(header.Riff.ChunkID, "RIFF", 4);
header.Riff.ChunkSize = DURATION * SAMPLE_RATE * CHANNEL * BIT_RATE / 8 + 36;
memcpy(header.Riff.Format, "WAVE", 4);
memcpy(header.Fmt.ChunkID, "fmt ", 4);
header.Fmt.ChunkSize = 0x10;
header.Fmt.AudioFormat = WAVE_FORMAT_PCM;
header.Fmt.NumChannels = CHANNEL;
header.Fmt.SampleRate = SAMPLE_RATE;
header.Fmt.AvgByteRate = SAMPLE_RATE * CHANNEL * BIT_RATE / 8;
header.Fmt.BlockAlign = CHANNEL * BIT_RATE / 8;
header.Fmt.BitPerSample = BIT_RATE;
memcpy(header.Data.ChunkID, "data", 4);
header.Data.ChunkSize = DURATION * SAMPLE_RATE * CHANNEL * BIT_RATE / 8;
fwrite(&header, sizeof(header), 1, f_out);
short y[2];
double high_freq = 960;
double low_freq = 770;
#if 0
for (int i = 0; i < SAMPLE_RATE * DURATION; i++) {
double level_l = (double)i / (SAMPLE_RATE * DURATION);
double level_r = 1.0 - level_l;
y[0] = (short)(30000 * sin(2 * 3.141592 * i * high_freq / SAMPLE_RATE) * level_l);
y[1] = (short)(30000 * sin(2 * 3.141592 * i * low_freq / SAMPLE_RATE) * level_r);
fwrite(&y[0], sizeof(short), 1, f_out);
fwrite(&y[1], sizeof(short), 1, f_out);
}
#endif
#if 1
// number of samples to flip on
#if 0
int flipfreq = (SAMPLE_RATE * 65) / 100;
#else
int flipfreq = (SAMPLE_RATE * 65) / 200;
#endif
// current frequency to use
int curtyp = 0;
for (int i = 0; i < SAMPLE_RATE * DURATION; i++) {
int j = i + 48;
// after 0.65 seconds, change the frequency
if ((i % flipfreq) == 0)
curtyp = !curtyp;
// use the frequency for this period
double cur_freq = curtyp ? high_freq : low_freq;
double level_l = (double)i / (SAMPLE_RATE * DURATION);
#if 1
double level_r = 1.0 - level_l;
#else
double level_r = level_l;
#endif
y[0] = (short)(30000 * sin(2 * 3.141592 * i * cur_freq / SAMPLE_RATE) * level_l);
y[1] = (short)(30000 * sin(2 * 3.141592 * j * cur_freq / SAMPLE_RATE) * level_r);
fwrite(&y[0], sizeof(short), 1, f_out);
fwrite(&y[1], sizeof(short), 1, f_out);
}
#endif
fclose(f_out);
return 0;
}
解决方案
请您尝试以下方法:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <math.h>
#define WAVE_FORMAT_UNKNOWN 0X0000;
#define WAVE_FORMAT_PCM 0X0001;
#define WAVE_FORMAT_MS_ADPCM 0X0002;
#define WAVE_FORMAT_IEEE_FLOAT 0X0003;
#define WAVE_FORMAT_ALAW 0X0006;
#define WAVE_FORMAT_MULAW 0X0007;
#define WAVE_FORMAT_IMA_ADPCM 0X0011;
#define WAVE_FORMAT_YAMAHA_ADPCM 0X0016;
#define WAVE_FORMAT_GSM 0X0031;
#define WAVE_FORMAT_ITU_ADPCM 0X0040;
#define WAVE_FORMAT_MPEG 0X0050;
#define WAVE_FORMAT_EXTENSIBLE 0XFFFE;
#define DURATION 8
#define SAMPLE_RATE 48000
#define CHANNEL 2
#define BIT_RATE 16
#define DELAY 48 // delay left ch in 48 samples (1msec)
typedef struct {
unsigned char ChunkID[4]; // Contains the letters "RIFF" in ASCII form
unsigned int ChunkSize; // This is the size of the rest of the chunk following this number
unsigned char Format[4]; // Contains the letters "WAVE" in ASCII form
} RIFF;
typedef struct {
unsigned char ChunkID[4]; // Contains the letters "fmt " in ASCII form
unsigned int ChunkSize; // 16 for PCM. This is the size of the rest of the Subchunk which follows this number.
unsigned short AudioFormat; // PCM = 1
unsigned short NumChannels; // Mono = 1, Stereo = 2, etc.
unsigned int SampleRate; // 8000, 44100, etc.
unsigned int AvgByteRate; // SampleRate * NumChannels * BitsPerSample/8
unsigned short BlockAlign; // NumChannels * BitsPerSample/8
unsigned short BitPerSample; // 8 bits = 8, 16 bits = 16, etc
} FMT;
typedef struct {
char ChunkID[4]; // Contains the letters "data" in ASCII form
unsigned int ChunkSize; // NumSamples * NumChannels * BitsPerSample/8
} DATA;
typedef struct {
RIFF Riff;
FMT Fmt;
DATA Data;
} WAVE_HEADER;
int
main()
{
FILE* f_out;
f_out = fopen("D:\\test.wav", "wb");
WAVE_HEADER header;
memcpy(header.Riff.ChunkID, "RIFF", 4);
header.Riff.ChunkSize = DURATION * SAMPLE_RATE * CHANNEL * BIT_RATE / 8 + 36;
memcpy(header.Riff.Format, "WAVE", 4);
memcpy(header.Fmt.ChunkID, "fmt ", 4);
header.Fmt.ChunkSize = 0x10;
header.Fmt.AudioFormat = WAVE_FORMAT_PCM;
header.Fmt.NumChannels = CHANNEL;
header.Fmt.SampleRate = SAMPLE_RATE;
header.Fmt.AvgByteRate = SAMPLE_RATE * CHANNEL * BIT_RATE / 8;
header.Fmt.BlockAlign = CHANNEL * BIT_RATE / 8;
header.Fmt.BitPerSample = BIT_RATE;
memcpy(header.Data.ChunkID, "data", 4);
header.Data.ChunkSize = DURATION * SAMPLE_RATE * CHANNEL * BIT_RATE / 8;
fwrite(&header, sizeof(header), 1, f_out);
short y[2];
short l[SAMPLE_RATE * DURATION + DELAY] = { 0 }; // left ch buffer
short r[SAMPLE_RATE * DURATION + DELAY] = { 0 }; // right ch buffer
double high_freq = 960;
double low_freq = 770;
// number of samples to flip on
int flipfreq = (SAMPLE_RATE * 65) / 100;
// current frequency to use
int curtyp = 0;
double phi = 0.;
for (int i = 0; i < SAMPLE_RATE * DURATION + DELAY; i++) {
// after 0.65 seconds, change the frequency
if ((i % flipfreq) == 0)
curtyp = !curtyp;
// use the frequency for this period
double cur_freq = curtyp ? high_freq : low_freq;
double level_l = (double)i / (SAMPLE_RATE * DURATION);
double level_r = 1.0 - level_l;
phi += 2 * M_PI * cur_freq / SAMPLE_RATE;
l[i] = (short)(30000 * sin(phi) * level_l);
r[i] = (short)(30000 * sin(phi) * level_r);
}
for (int i = 0; i < SAMPLE_RATE * DURATION; i++) {
y[0] = l[i];
y[1] = r[i + DELAY];
fwrite(&y[0], sizeof(short), 1, f_out);
fwrite(&y[1], sizeof(short), 1, f_out);
}
fclose(f_out);
return 0;
}
延迟
进行延迟的最简单方法是将样本存储在数组中,并以指定的偏移量顺序输出它们。否则,您需要同时控制频率和幅度的延迟,这可能会导致混乱。请注意,人耳无法识别 1 毫秒延迟。尝试Audacity
或其他可以显示波形以进行验证的声音编辑工具。
毛刺
您的代码会导致glitches
频率转换。毛刺是由不连续波形引起的噪声。为避免这种情况,请尝试
phi += 2 * PI * dt; sin(phi)
代替sin(2 * PI * i * dt)
.
推荐阅读
- android - 如何从协程返回错误响应
- java - ExoPlayer - 在 MergingMediaSource 上抛出 UnrecognizedInputFormatException
- python - 我可以在同一个 Intellij 项目目录中使用并行 python 2.7 和 python 3.7 吗?
- python - 当错误为“No module named 'pytz'”时,我的 vs 代码有什么问题?
- php - 排除匹配中的单词
- c# - C# 将 bool 转换为字节 [4]
- tensorflow - 如何从 python 生成 .tf/.tflite 文件
- nativescript - 背景图像未显示在 NativeScript 页面上
- vbscript - 无法通过 vbs 启动具有固定参数的程序
- linux - Node Exporter 绑定地址已经在运行