逐渐将音频文件从正常速度减慢到半速?

Posted

技术标签:

【中文标题】逐渐将音频文件从正常速度减慢到半速?【英文标题】:Gradually slow down audio file from normal speed to half speed? 【发布时间】:2015-07-14 02:10:36 【问题描述】:

我正在尝试从一个音频文件中获取内容并将它们写入另一个音频文件——除了输出应该以正常速度开始,然后随着时间的推移减慢并以原始速度的一半结束。我正在尝试拉格朗日插值方法,但似乎无法完全正确。我暂时搁置 struct 只是为了看看我在做什么。这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() 
    FILE *original, *slowdown;
    unsigned int ChunkSize, Subchunk1Size, Subchunk2Size, RIFFSize, fmtSize, dataSize, SampleRate, ByteRate;
    unsigned short int AudioFormat, NumChannels, BlockAlign, BitsPerSample;
    char ChunkID[5], Format[5], Subchunk1ID[5], Subchunk2ID[5];
    ChunkID[4] = '\0';
    Format[4] = '\0';
    Subchunk1ID[4] = '\0';
    Subchunk2ID[4] = '\0';
    char path[FILENAME_MAX], dslowdown[FILENAME_MAX];
    printf("Enter path to Alejandro_project.wav file:\n");
    scanf("%s", path);
    strcpy(dslowdown, path);
    dslowdown[strlen(path) - 21] = '\0';
    strcat(dslowdown, "Alejandro_fast.wav");
    original = fopen(path, "rb");
    if (!original) 
        printf("Error: file does not exist.\n");
        return EXIT_FAILURE;
    
    fread(ChunkID, 4, 1, original);
    fread(&ChunkSize, 4, 1, original);
    fread(Format, 4, 1, original);
    fread(Subchunk1ID, 4, 1, original);
    fread(&Subchunk1Size, 4, 1, original);
    fread(&AudioFormat, 2, 1, original);
    fread(&NumChannels, 2, 1, original);
    fread(&SampleRate, 4, 1, original);
    fread(&ByteRate, 4, 1, original);
    fread(&BlockAlign, 2, 1, original);
    fread(&BitsPerSample, 2, 1, original);
    fread(Subchunk2ID, 4, 1, original);
    fread(&Subchunk2Size, 4, 1, original);
    fseek(original, 0, SEEK_SET);
    slowdown = fopen(dslowdown, "wb");
    fwrite(ChunkID, 4, 1, slowdown);
    fwrite(&ChunkSize, 4, 1, slowdown);
    fwrite(Format, 4, 1, slowdown);
    fwrite(Subchunk1ID, 4, 1, slowdown);
    fwrite(&Subchunk1Size, 4, 1, slowdown);
    fwrite(&AudioFormat, 2, 1, slowdown);
    fwrite(&NumChannels, 2, 1, slowdown);
    fwrite(&SampleRate, 4, 1, slowdown);
    fwrite(&ByteRate, 4, 1, slowdown);
    fwrite(&BlockAlign, 2, 1, slowdown);
    fwrite(&BitsPerSample, 2, 1, slowdown);
    fwrite(Subchunk2ID, 4, 1, slowdown);
    fwrite(&Subchunk2Size, 4, 1, slowdown);
    short int t[4], audio[Subchunk2Size / 2], f[4];
    for (i = 0; i < Subchunk2Size / 2; i++) 
        fread(&data, 2, 1, original);
        audio[i] = data;
    
    for (i = 0; i < sizeof(t) / 2; i++)
        t[i + 1] = t[i] + (11.41 - t[i]) / 11.41 * (1.0 / 22050.0) + t[i] / 11.41 * (0.4 / 22050.0);
    for (i = 0; i < sizeof(f) / 2; i++) 
        f[i + 1] = ((t[i] - t[i - 1]) * (t[i] - t[i + 1]) * (t[i] - t[i + 2])) / ((t[i - 2] - t[i - 1]) * (t[i - 2] - t[i + 1]) * (t[i - 2] - t[i + 2])) * f[i - 2] + ((t[i] - t[i - 2]) * (t[i] - t[i + 1]) * (t[i] - t[i + 2])) / ((t[i - 1] - t[i - 2]) * (t[i - 1] - t[i + 1]) * (t[i - 1] - t[i + 2])) * f[i - 1] + ((t[i] - t[i - 2]) * (t[i] - t[i - 1]) * (t[i] - t[i + 2])) / ((t[i + 1] - t[i - 2]) * (t[i + 1] - t[i - 1]) * (t[i + 1] - t[i + 2])) * f[i + 1] + ((t[i] - t[i - 2]) * (t[i] - t[i - 1]) * (t[i] - t[i + 2])) / ((t[i + 1] - t[i - 2]) * (t[i + 1] - t[i - 1]) * (t[i + 1] - t[i + 2])) * f[i + 2];
    
    for (i = 0; i < Subchunk2Size; i++) 
        audio[i] = audio[f[i]];
    
    fwrite(audio, sizeof(audio), 1, slowdown);
    fseek(slowdown, 40, SEEK_SET);
    fwrite(&Subchunk2Size, 4, 1, slowdown);
    fseek(slowdown, 40, SEEK_SET);
    fwrite(audio, sizeof(audio), 1, slowdown);
    fseek(slowdown, 4, SEEK_SET);
    fwrite(&ChunkSize, 4, 1, slowdown);
    fclose(slowdown);
    fclose(original);
    return EXIT_SUCCESS;

【问题讨论】:

此程序无法编译。 i 和数据未声明。编译并修复所有警告时使用 -Wall。编译干净后,就可以开始调试了。 【参考方案1】:

我想通了。我回到 struct 并重新计算了数学。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() 
    FILE *original, *fast, *slow, *slowdown;
    unsigned int RIFFSize, fmtSize, dataSize;
    struct WAVE 
        char ChunkID[4];
        unsigned int ChunkSize;
        char Format[4];
        char Subchunk1ID[4];
        unsigned int Subchunk1Size;
        unsigned short int AudioFormat;
        unsigned short int NumChannels;
        int SampleRate;
        int ByteRate;
        unsigned short int BlockAlign;
        unsigned short int BitsPerSample;
        char Subchunk2ID[4];
        unsigned int Subchunk2Size;
     o, f, s, sd;
    char path[FILENAME_MAX], dfast[FILENAME_MAX], dslow[FILENAME_MAX], dslowdown[FILENAME_MAX];
    printf("Enter the path to an input WAVE (.wav) file:\n");
    gets(path);
    strcpy(dfast, path);
    dfast[strlen(path) - 4] = '\0';
    strcpy(dslow, dfast);
    strcpy(dslowdown, dslow);
    strcat(dfast, "_fast.wav");
    strcat(dslow, "_slow.wav");
    strcat(dslowdown, "_slowdown.wav");
    original = fopen(path, "rb");
    if (!original) 
        printf("Error: file does not exist.\n");
        return EXIT_FAILURE;
    
    fread(&o, 44, 1, original);
    fseek(original, 0, SEEK_SET);
    fread(&f, 44, 1, original);
    fseek(original, 0, SEEK_SET);
    fread(&s, 44, 1, original);
    fseek(original, 0, SEEK_SET);
    fread(&sd, 44, 1, original);
    fmtSize = o.Subchunk1Size + 8;
    dataSize = o.Subchunk2Size + 8;
    RIFFSize = o.ChunkSize + 8 - (fmtSize + dataSize);
    printf("Characteristics of %s:\n", path);
    printf("RIFF Size:     %d\n", RIFFSize);
    printf("fmt Size:      %d\n", fmtSize);
    printf("data Size:     %d\n\n", dataSize);
    printf("ChunkID:       %.4s\n", o.ChunkID);
    printf("ChunkSize:     %d\n", o.ChunkSize);
    printf("Format:        %.4s\n\n", o.Format);
    printf("Subchunk1ID:   %.4s\n", o.Subchunk1ID);
    printf("Subchunk1Size: %d\n", o.Subchunk1Size);
    printf("AudioFormat:   %d\n", o.AudioFormat);
    printf("NumChannels:   %d\n", o.NumChannels);
    printf("SampleRate:    %d\n", o.SampleRate);
    printf("ByteRate:      %d\n", o.ByteRate);
    printf("BlockAlign:    %d\n", o.BlockAlign);
    printf("BitsPerSample: %d\n\n", o.BitsPerSample);
    printf("Subchunk2ID:   %.4s\n", o.Subchunk2ID);
    printf("Subchunk2Size: %d\n\n", o.Subchunk2Size);
    fseek(original, 0, SEEK_SET);
    fast = fopen(dfast, "wb");
    f.SampleRate = o.SampleRate * 2;
    f.ByteRate = 2 * f.SampleRate;
    fseek(fast, 0, SEEK_SET);
    fwrite(&f, 44, 1, fast);
    fmtSize = f.Subchunk1Size + 8;
    dataSize = f.Subchunk2Size + 8;
    RIFFSize = f.ChunkSize + 8 - (fmtSize + dataSize);
    printf("\nCharacteristics of %s:\n", dfast);
    printf("RIFF Size:     %d\n", RIFFSize);
    printf("fmt Size:      %d\n", fmtSize);
    printf("data Size:     %d\n\n", dataSize);
    printf("ChunkID:       %.4s\n", f.ChunkID);
    printf("ChunkSize:     %d\n", f.ChunkSize);
    printf("Format:        %.4s\n\n", f.Format);
    printf("Subchunk1ID:   %.4s\n", f.Subchunk1ID);
    printf("Subchunk1Size: %d\n", f.Subchunk1Size);
    printf("AudioFormat:   %d\n", f.AudioFormat);
    printf("NumChannels:   %d\n", f.NumChannels);
    printf("SampleRate:    %d\n", f.SampleRate);
    printf("ByteRate:      %d\n", f.ByteRate);
    printf("BlockAlign:    %d\n", f.BlockAlign);
    printf("BitsPerSample: %d\n\n", f.BitsPerSample);
    printf("Subchunk2ID:   %.4s\n", f.Subchunk2ID);
    printf("Subchunk2Size: %d\n\n", f.Subchunk2Size);
    short int data;
    unsigned int i;
    for (i = 0; i < f.Subchunk2Size / 2; i++) 
        fread(&data, 2, 1, original);
        fwrite(&data, 2, 1, fast);
    
    fclose(fast);
    fseek(original, 0, SEEK_SET);
    slow = fopen(dslow, "wb");
    s.SampleRate = o.SampleRate / 2;
    s.ByteRate = 2 * s.SampleRate;
    fseek(slow, 0, SEEK_SET);
    fwrite(&s, 44, 1, slow);
    printf("\nCharacteristics of %s:\n", dslow);
    printf("RIFF Size:     %d\n", RIFFSize);
    printf("fmt Size:      %d\n", fmtSize);
    printf("data Size:     %d\n\n", dataSize);
    printf("ChunkID:       %.4s\n", s.ChunkID);
    printf("ChunkSize:     %d\n", s.ChunkSize);
    printf("Format:        %.4s\n\n", s.Format);
    printf("Subchunk1ID:   %.4s\n", s.Subchunk1ID);
    printf("Subchunk1Size: %d\n", s.Subchunk1Size);
    printf("AudioFormat:   %d\n", s.AudioFormat);
    printf("NumChannels:   %d\n", s.NumChannels);
    printf("SampleRate:    %d\n", s.SampleRate);
    printf("ByteRate:      %d\n", s.ByteRate);
    printf("BlockAlign:    %d\n", s.BlockAlign);
    printf("BitsPerSample: %d\n\n", s.BitsPerSample);
    printf("Subchunk2ID:   %.4s\n", s.Subchunk2ID);
    printf("Subchunk2Size: %d\n\n", s.Subchunk2Size);
    for (i = 0; i < s.Subchunk2Size / 2; i++) 
        fread(&data, 2, 1, original);
        fwrite(&data, 2, 1, slow);
    
    fclose(slow);
    fseek(original, 0, SEEK_SET);
    slowdown = fopen(dslowdown, "wb");
    unsigned int samples;
    fseek(original, 44, SEEK_SET);
    fseek(slowdown, 44, SEEK_SET);
    samples = o.Subchunk2Size / 2;
    double dt = 1/22050.0, out, space, t;
    double point[4], ta, tb, tc, td;
    unsigned int stamp;
    unsigned int count = 0;
    short int fd[4], audio;
    t = dt;
    space = dt;
    point[0] = (-1.0) * (-2.0) * (-3.0) * dt;
    point[1] = (1.0) * (-1.0) * (-2.0) * dt;
    point[2] = (2.0) * (1.0) * (-1.0) * dt;
    point[3] = (3.0) * (2.0) * (1.0) * dt;

    while (t < (samples - 2) * dt) 
        stamp = (int)(t / dt - 1);
        fseek(original, 44 + stamp * 2, SEEK_SET);
        for(i = 0; i < 4; i++) 
            fread(&fd[i], 2, 1, original);
    
        ta = stamp * dt;
        tb = (stamp + 1) * dt;
        tc = (stamp + 2) * dt;
        td = (stamp + 3);
        out = (((t - tb) * (t - tc) * (t - td)) / (point[0])) * fd[0] + (((t - ta) * (t - tc) * (t - td)) / (point[1])) * fd[1] + (((t - ta) * (t - tb) * (t - td)) / (point[2])) * fd[2] + (((t - ta) * (t - tb) * (t - tc)) / (point[3])) * fd[3];
        audio = (short int)(out);
        fwrite(&audio, 2, 1, slowdown);
        space = (((samples - 1) * dt - t) / ((samples - 1) * dt)) * dt + (t / ((samples - 1) * dt)) * .4 * dt;
        t += space;
        count++;
    
    sd.Subchunk2Size = count * 2;
    sd.ChunkSize = 36 + sd.Subchunk2Size;
    fseek(slowdown, 0, SEEK_SET);
    fwrite(&sd, 44, 1, slowdown);
    fmtSize = sd.Subchunk1Size + 8;
    dataSize = sd.Subchunk2Size + 8;
    RIFFSize = sd.ChunkSize + 8 - (fmtSize + dataSize);
    printf("\nCharacteristics of %s:\n", dslowdown);
    printf("RIFF Size:     %d\n", RIFFSize);
    printf("fmt Size:      %d\n", fmtSize);
    printf("data Size:     %d\n\n", dataSize);
    printf("ChunkID:       %.4s\n", sd.ChunkID);
    printf("ChunkSize:     %d\n", sd.ChunkSize);
    printf("Format:        %.4s\n\n", sd.Format);
    printf("Subchunk1ID:   %.4s\n", sd.Subchunk1ID);
    printf("Subchunk1Size: %d\n", sd.Subchunk1Size);
    printf("AudioFormat:   %d\n", sd.AudioFormat);
    printf("NumChannels:   %d\n", sd.NumChannels);
    printf("SampleRate:    %d\n", sd.SampleRate);
    printf("ByteRate:      %d\n", sd.ByteRate);
    printf("BlockAlign:    %d\n", sd.BlockAlign);
    printf("BitsPerSample: %d\n\n", sd.BitsPerSample);
    printf("Subchunk2ID:   %.4s\n", sd.Subchunk2ID);
    printf("Subchunk2Size: %d\n\n", sd.Subchunk2Size);
    printf("\nAs you can see, the only differences between the fast/slow output files and the original input file are the sample rate and byte rate. However, the slowdown output file differs from the original input file not only in its sample rate and byte rate, but also in its data size, Chunk size, and Subchunk2 size.\n");
    fclose(slowdown);
    fclose(original);
    return EXIT_SUCCESS;

【讨论】:

以上是关于逐渐将音频文件从正常速度减慢到半速?的主要内容,如果未能解决你的问题,请参考以下文章

如何以不同的速度播放音频?

更改“发声器”的音频音高

下采样 wav 音频文件

如何实时流式传输音频文件

将 MP3 流式传输到 Discord.net 2.0 - 音频速度超快(花栗鼠)。想法?

如何延迟/减慢 UIScrollView 平移速度