如何在 C 中制作 Siren 噪声 wav 文件?

Posted

技术标签:

【中文标题】如何在 C 中制作 Siren 噪声 wav 文件?【英文标题】:How can I make Siren noise wav file in C? 【发布时间】:2021-06-14 00:45:15 【问题描述】:

我已经编写了关于警报器的 wav 文件的代码,但我不确定这是否正确......

这是从右到左的警笛声。

960Hz(0.65 秒)和 770Hz(0.5 秒)

    我想确认 'High' 和 'Low' 每 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;

【问题讨论】:

您可能需要重新考虑问题的标题,因为它没有准确地涵盖您要问的内容。此外,为了获得更多有关问题的背景信息,这是针对计算机科学还是音频编程课程/课程? 【参考方案1】:

请您尝试以下方法:

#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)

【讨论】:

以上是关于如何在 C 中制作 Siren 噪声 wav 文件?的主要内容,如果未能解决你的问题,请参考以下文章

通过 C 中的 FFT 将 1000Hz 噪声添加到 wav 文件

使用 C 编写 wav 文件期间的量化噪声

Android AudioTrack 播放 .wav 文件,只得到白噪声

c#如何播放多个.wav文件,并设置每个文件的音量

使用 C 创建立体声 WAV 文件

wav文件中奇怪的滴答声