生成用于验证 TDM slot 配置的波形

Qidi Huang 2025.11.17


使用逻辑分析仪测量 TDM 的 BCLKFSYNCSDO引脚上的信号,可以验证 TDM slot 配置及输出是否正确。不过,我们不能使用常规正弦波进行测量,而是要使用一种特殊波形。在这种波形上:有信号的 slot 输出 0xAA;无信号的 slot 输出 0x00。两种 slot 交替,即可在逻辑分析仪上分辨出 slot 个数和宽度。

这种波形正常人也用不上,所以一般需要工程师自己生成。
以下代码可以生成一段 30秒、单声道、16位、48000赫兹 的测试波形:

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

#pragma pack(push, 1)   // Ensure no padding in WAV header structs

typedef struct {
    char     chunkID[4];      // "RIFF"
    uint32_t chunkSize;
    char     format[4];       // "WAVE"
} RIFFHeader;

typedef struct {
    char     subChunk1ID[4];  // "fmt "
    uint32_t subChunk1Size;   // 16 for PCM
    uint16_t audioFormat;     // 1 = PCM
    uint16_t numChannels;
    uint32_t sampleRate;
    uint32_t byteRate;
    uint16_t blockAlign;
    uint16_t bitsPerSample;
} FmtSubchunk;

typedef struct {
    char     subChunk2ID[4];  // "data"
    uint32_t subChunk2Size;
} DataSubchunk;

#pragma pack(pop)

int main() {
    const char *filename = "tdmCalibration_1c_16b_48k_30s.wav";
    FILE *fp = fopen(filename, "wb");
    if (!fp) {
        perror("Failed to open output file");
        return 1;
    }

    // WAV parameters
    uint16_t numChannels = 1;
    uint32_t sampleRate = 48000;
    uint16_t bitsPerSample = 16;
    uint32_t durationSec = 30;
    uint32_t numSamples = sampleRate * durationSec;
    uint32_t dataSize = numSamples * numChannels * (bitsPerSample / 8);

    // Prepare WAV header
    RIFFHeader riff = {
        {'R','I','F','F'},
        36 + dataSize,          // chunkSize = 4 + (8 + SubChunk1Size) + (8 + SubChunk2Size)
        {'W','A','V','E'}
    };

    FmtSubchunk fmt = {
        {'f','m','t',' '},
        16,                      // PCM
        1,                       // audioFormat = 1 (PCM)
        numChannels,
        sampleRate,
        sampleRate * numChannels * (bitsPerSample / 8),
        (uint16_t)(numChannels * (bitsPerSample / 8)),
        bitsPerSample
    };

    DataSubchunk data = {
        {'d','a','t','a'},
        dataSize
    };

    // Write headers
    fwrite(&riff, sizeof(riff), 1, fp);
    fwrite(&fmt, sizeof(fmt), 1, fp);
    fwrite(&data, sizeof(data), 1, fp);

    // Create 0xAA-filled audio buffer
    uint8_t sampleBytes[2] = {0xAA, 0xAA};  // 16bit = 2bytes
    for (uint32_t i = 0; i < numSamples; i++) {
        fwrite(sampleBytes, sizeof(sampleBytes), 1, fp);
    }

    fclose(fp);
    printf("WAV file generated: %s\n", filename);
    return 0;
}

如果想生成多声道的测试波形,可以使用如下代码(按需修改 numChannels 变量值):

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

#pragma pack(push, 1)
typedef struct {
    char     chunkID[4];      // "RIFF"
    uint32_t chunkSize;
    char     format[4];       // "WAVE"
} RIFFHeader;

typedef struct {
    char     subChunk1ID[4];  // "fmt "
    uint32_t subChunk1Size;   // 16 for PCM
    uint16_t audioFormat;     // 1 = PCM
    uint16_t numChannels;
    uint32_t sampleRate;
    uint32_t byteRate;
    uint16_t blockAlign;
    uint16_t bitsPerSample;
} FmtSubchunk;

typedef struct {
    char     subChunk2ID[4];  // "data"
    uint32_t subChunk2Size;
} DataSubchunk;
#pragma pack(pop)

int main() {
    const char *filename = "12ch_output.wav";
    FILE *fp = fopen(filename, "wb");
    if (!fp) {
        perror("Failed to open output file");
        return 1;
    }

    // WAV parameters
    const uint16_t numChannels = 12;
    const uint32_t sampleRate = 48000;
    const uint16_t bitsPerSample = 16;
    const uint32_t durationSec = 30;

    const uint32_t numSamples = sampleRate * durationSec;
    const uint32_t bytesPerSample = bitsPerSample / 8;
    const uint32_t frameSize = numChannels * bytesPerSample;   // 12 * 2 = 24 bytes
    const uint32_t dataSize = numSamples * frameSize;

    // Prepare headers
    RIFFHeader riff = {
        {'R','I','F','F'},
        36 + dataSize,
        {'W','A','V','E'}
    };

    FmtSubchunk fmt = {
        {'f','m','t',' '},
        16,
        1,                          // PCM
        numChannels,
        sampleRate,
        sampleRate * frameSize,     // byteRate
        frameSize,                  // blockAlign
        bitsPerSample
    };

    DataSubchunk data = {
        {'d','a','t','a'},
        dataSize
    };

    // Write headers
    fwrite(&riff, sizeof(riff), 1, fp);
    fwrite(&fmt, sizeof(fmt), 1, fp);
    fwrite(&data, sizeof(data), 1, fp);

    // Build one 12-channel interleaved frame
    uint8_t frame[24];  // 12 channels × 2 bytes

    for (int ch = 0; ch < numChannels; ch++) {
        if (ch % 2 == 0) {
            // Even channel: 0xAAAA
            frame[ch * 2 + 0] = 0xAA;
            frame[ch * 2 + 1] = 0xAA;
        } else {
            // Odd channel: 0x0000
            frame[ch * 2 + 0] = 0x00;
            frame[ch * 2 + 1] = 0x00;
        }
    }

    // Write frames
    for (uint32_t i = 0; i < numSamples; i++) {
        fwrite(frame, sizeof(frame), 1, fp);
    }

    fclose(fp);

    printf("Generated 12-channel WAV: %s\n", filename);
    return 0;
}
posted @ 2025-11-17 15:14  Qidi_Huang  阅读(3)  评论(0)    收藏  举报