【问题标题】:Playing audio files with libao使用 libao 播放音频文件
【发布时间】:2013-12-02 06:54:03
【问题描述】:

我正在尝试让一个简单的 C 程序播放 AIFF 或 WAV 文件。根据我在http://www.xiph.org/ao/doc/ 看到的内容,这应该可以工作,但无论我提供什么文件,它都会发出嗡嗡声。这有什么问题?

/* compile with "gcc -o playme playme.c -lao -ldl -lm" */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ao/ao.h>
#include <math.h>

ao_device *device;
ao_sample_format format;

int main(int argc, char *argv[])
{
    int default_driver;
    char *buffer;
    unsigned long count;

    FILE *fp;

    if (argc != 2) {
    printf("usage: %s <filename>\n", argv[0]);
    exit(1);
    }

    ao_initialize();
    default_driver = ao_default_driver_id();
    memset(&format, 0, sizeof(format));

    format.bits = 16;
    format.channels = 2;
    format.rate = 44100;
    format.byte_format = AO_FMT_LITTLE;

    device = ao_open_live(default_driver, &format, NULL /* no options */);
    if (device == NULL) {
        printf("Error opening sound device.\n");
        exit(1);
    }

    fp = fopen(argv[1], "rb");
    if (fp == NULL) {
    printf("Cannot open %s.\n", argv[1]);
    exit(2);
    }

    fseek(fp, 0, SEEK_END);
    count = ftell(fp);
    fseek(fp, 0, SEEK_SET);

    fread(buffer, sizeof(char), count, fp);
    ao_play(device, buffer, count);
    ao_close(device);
    ao_shutdown();

    return 0;
}

【问题讨论】:

    标签: c linux audio wav aiff


    【解决方案1】:

    我没有意识到的一个关键问题是 libao 完全不解码。因此,程序员需要在打开音频设备之前提取样本大小、速率、通道等并将其提供给 libao。 libsndfile 可用于执行此操作,但如果您只是想要快速而肮脏的东西,这里是播放 AIFF 文件的代码:

    /* compile with "gcc -o playaiff playaiff.c -lao -ldl -lm" */
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ao/ao.h>
    #include <math.h>
    
    #define MAXCHAN 8
    
    ao_device *device;
    ao_sample_format format;
    
    #define gshort( b) (((int)((b)[0]) << 8) + (int)((b)[1]))
    #define glong( b) (((int)((b)[0]) << 24) + ((int)((b)[1]) << 16) +\
            ((int)((b)[2]) << 8) + (int)((b)[3]))
    
    typedef struct {
        short     channels;
        short     samplesize;
        int   samplerate;
        unsigned long samplecount;
        int       valid;
    } aiffinfo;
    
    aiffinfo getaiffinfo(FILE *);
    static int IeeeExtendedToLong(unsigned char *);
    
    int main(int argc, char *argv[])
    {
        int default_driver;
        char *buffer;
    
        aiffinfo info;
    
        FILE *fp;
    
        if (argc != 2) {
        printf("usage: %s <filename>\n", argv[0]);
        exit(1);
        }
    
        ao_initialize();
        default_driver = ao_default_driver_id();
        memset(&format, 0, sizeof(format));
    
        fp = fopen(argv[1], "rb");
        if (fp == NULL) {
        printf("Cannot open %s.\n", argv[1]);
        exit(2);
        }
    
        info = getaiffinfo(fp);
    
        if (!info.valid) {
        printf("Invalid AIFF file.\n");
        exit(1);
        }
    
        format.bits = info.samplesize;
        format.channels = info.channels;
        format.rate = info.samplerate;
        format.byte_format = AO_FMT_LITTLE;
    
        device = ao_open_live(default_driver, &format, NULL /* no options */);
        if (device == NULL) {
            printf("Error opening sound device.\n");
            exit(1);
        }
    
        buffer = malloc(sizeof(char) * info.samplecount);
    
        fread(buffer, sizeof(char), info.samplecount, fp);
        ao_play(device, buffer, info.samplecount);
        ao_close(device);
        ao_shutdown();
    
        return 0;
    }
    
    
    aiffinfo getaiffinfo(FILE *fp)
    {
        int size;
        int len;
        int offset;
        int blocksize;
        int found = 0;
        unsigned char chunk[18];
        unsigned char fid[4];
        aiffinfo info;
    
        info.samplesize = 0;
        info.valid = 0;
    
        if (fread(chunk, 1, 4, fp) < 4) return info;
        if (memcmp(chunk,"FORM",4)) return info;
        if (fread(chunk, 1, 4, fp) < 4)  return info;
        size = glong(chunk);
        if (size & 1) size++;
        if (size < 20) return info;
        if (fread(chunk, 1, 4, fp) < 4) return info;
        if (memcmp(chunk, "AIFF", 4)) return info;
    
        size -= 4;
        while (size > 8) {
        if (fread(fid, 1, 4, fp) < 4) return info;    // chunck id
        if (fread(chunk, 1, 4, fp) < 4) return info;    // and len
        size -= 8;
        len = glong(chunk);
        if (len < 0) return info;
        if (len & 1) len++;
        size -= len;
        if (size < 0) return info;
        if (memcmp(fid, "COMM", 4) == 0) {
            if (len != 18) return info;
            if (fread(chunk, 1, 18, fp) < 18) return info;
            info.channels = gshort(chunk);
            if (info.channels < 1) return info;
            if (info.channels > MAXCHAN) return info;
            info.samplecount = glong(chunk+2);
            if (info.samplecount < 1) return info;
            info.samplerate = IeeeExtendedToLong(chunk + 8);
            if (info.samplerate <= 0) return info;
            info.samplesize = gshort(chunk + 6);
            if (info.samplesize < 1 || info.samplesize > 16) return info;
        } else if (memcmp(fid,"SSND",4)==0){
            if (!info.channels) return info;
            if (fread(chunk, 1, 4, fp) < 4) return info;
            offset = glong(chunk);
            if (fread(chunk, 1, 4, fp) < 4) return info;
            blocksize = glong(chunk);
            if (blocksize) return info;
            if (offset) fseek(fp, offset,SEEK_CUR);
            found = 1;
            break;
        } else fseek (fp, len, SEEK_CUR);
        }
    
        if (!found) return info;
        if (!info.channels) return info;
    
    //    printf("Looks good so far.\n");
        info.valid = 1;
        return info;
    }
    
    
    /****************************************************************
     * Extended precision IEEE floating-point conversion routine.
     ****************************************************************/
    
    #ifndef Uint32
    #define Uint32 unsigned int
    #endif
    #ifndef HUGE_INT32
    #define HUGE_INT32 0x7fffffff
    #endif                                          /* HUGE_VAL */
    
    static int IeeeExtendedToLong( unsigned char *bytes)
    {
        int f = 0;
        int expon;
        Uint32 hiMant;
        Uint32 loMant;
    
        expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF);
        hiMant = ((Uint32) (bytes[2] & 0xFF) << 24)
        | ((Uint32) (bytes[3] & 0xFF) << 16)
        | ((Uint32) (bytes[4] & 0xFF) << 8)
        | ((Uint32) (bytes[5] & 0xFF));
        loMant = ((Uint32) (bytes[6] & 0xFF) << 24)
        | ((Uint32) (bytes[7] & 0xFF) << 16)
        | ((Uint32) (bytes[8] & 0xFF) << 8)
        | ((Uint32) (bytes[9] & 0xFF));
    
        if (expon == 0 && hiMant == 0 && loMant == 0) f = 0;
        else if (expon == 0x7FFF) f = HUGE_INT32;
        else {
        expon -= 16382;
        expon = 32-expon;
        if (expon < 0) f = HUGE_INT32;
        else f = hiMant >> expon;
        }
    
        if (bytes[0] & 0x80)
        return -f;
        else
        return f;
    }
    

    【讨论】:

      猜你喜欢
      • 2012-04-05
      • 2015-05-25
      • 2019-01-20
      • 2012-07-31
      • 2021-06-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多