打印
[嵌入式linux]

Linux下编写了一个小程序,播放wav文件成功。

[复制链接]
3836|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
ifree64|  楼主 | 2008-9-9 16:13 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
今天,看了下wav文件格式,在Linux下尝试了读取wav文件数据写往声卡文件/dev/dsp,播放成功。
没想到Linux下声卡编程竟然如此简单,就是把音频数据写到/dev/dsp文件即可。

源代码如下

/* filename: wavplay.c */

#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <linux/soundcard.h>

#define BUFSIZE 512

struct RIFF_Header{
  char RIFF_ID[4];
  uint32_t RIFF_Size;
  char RIFF_Format[4];
};

struct Chunk_Header{
  char Chunk_ID[4];
  uint32_t Chunk_Size;
};

struct Wave_Format{
  uint16_t AudioFormat;
  uint16_t NumChannels;
  uint32_t SampleRate;
  uint32_t AvgBytesPerSec;
  uint16_t BlockAlign;
  uint16_t BitsPerSample;
};

int main(int argc, char *argv[])
{
  struct RIFF_Header riff_header;
  struct Chunk_Header fmt_chunk, data_chunk;
  struct Wave_Format wavfmt;

  char buf[BUFSIZE];
  FILE * fwave;
  int sndfd;        
  int status;
  int arg;
  int readbytes;
  int writebytes;
  int writed;
  
  if( argc < 2 ){
    fprintf(stderr, "Usage: wavplay <filename>\n");
    exit(-1);
  }
  
  fwave = fopen( argv[1], "r");
  if( fwave == NULL ){
    fprintf(stderr, "Can't open file %s\n", argv[1]);
    exit(-1);
  }
        
  fread(&riff_header, 1, sizeof(struct RIFF_Header), fwave);
  if( strncmp(riff_header.RIFF_ID, "RIFF", 4) || strncmp(riff_header.RIFF_Format, "WAVE",4)){
    fprintf(stderr, "Unknown file format.\n");
    exit(-1);
  }

  sndfd = open("/dev/dsp", O_RDWR);
  if (sndfd < 0) {
    perror("open of /dev/dsp failed");
    exit(-1);
  }

  fread(&fmt_chunk, 1, sizeof(struct Chunk_Header), fwave);
  if( !strncmp(fmt_chunk.Chunk_ID, "fmt ", 4) ){
    /* this is a fmt chunk */
    fread(&wavfmt, 1, sizeof(struct Wave_Format), fwave);
    
    arg = wavfmt.BitsPerSample;
    status = ioctl(sndfd, SOUND_PCM_WRITE_BITS, &arg);
    if (status == -1)
      perror("SOUND_PCM_WRITE_BITS ioctl failed");
    if (arg != wavfmt.BitsPerSample)
      perror("unable to set sample size");
    
    arg = wavfmt.NumChannels; 
    status = ioctl(sndfd, SOUND_PCM_WRITE_CHANNELS, &arg);
    if (status == -1)
      perror("SOUND_PCM_WRITE_CHANNELS ioctl failed");
    if (arg != wavfmt.NumChannels)
      perror("unable to set number of channels");

    arg = wavfmt.SampleRate;
    status = ioctl(sndfd, SOUND_PCM_WRITE_RATE, &arg);
    if (status == -1)
      perror("SOUND_PCM_WRITE_WRITE ioctl failed");

    /* skip extra bytes */
    fseek(fwave, fmt_chunk.Chunk_Size - 16 + fmt_chunk.Chunk_Size%2, SEEK_CUR);
  }else{
    fprintf(stderr, "Can't find fmt chunk.\n");
    exit(-1);
  }
  
  while( fread(&data_chunk, 1, sizeof(struct Chunk_Header), fwave) != 0 )
    if( !strncmp(data_chunk.Chunk_ID, "data", 4) ){
      printf("Begin Play\n");
      /* this is a data chunk */
      writed = 0;
      while(writed < data_chunk.Chunk_Size){
        readbytes = fread(buf, 1, BUFSIZE, fwave);
        writebytes = write(sndfd, buf, readbytes);
        if( writebytes != readbytes )
          perror("wrote wrong number of bytes");
        writed += readbytes;
      }
    }else{
      /* skip unknown chunks */
      fseek(fwave, data_chunk.Chunk_Size + fmt_chunk.Chunk_Size%2, SEEK_CUR);
    }
  
  fclose(fwave);
  close(sndfd);
  
  return 0;

相关帖子

沙发
sodwell| | 2008-9-10 08:47 | 只看该作者

大哥,啥时候写个MP3的啊?

使用特权

评论回复
板凳
l0p0c| | 2008-9-10 15:37 | 只看该作者

嗯!恭喜LZ啦!

使用特权

评论回复
地板
765vcf| | 2008-9-10 16:18 | 只看该作者

嘻....嘻...在linux下面裸奔呀

用GStreamer库的小播放器,指定文件路径就行.....
#include <gst/gst.h>
#include <stdbool.h>
static GMainLoop *loop;
static gboolean bus_call (GstBus *bus, GstMessage *msg, gpointer user_data)
{
    switch (GST_MESSAGE_TYPE (msg))
     {
        case GST_MESSAGE_EOS:
              g_message ("End-of-stream");
              g_main_loop_quit (loop);
              break;
        case GST_MESSAGE_ERROR:
            g_message ("Error");
            g_main_loop_quit (loop);
            break;
        default:
            break;
    }
    return true;
}

void play_uri (gchar *uri)
{
    GstElement *pipeline;

    loop = g_main_loop_new (NULL, FALSE);

    pipeline = gst_element_factory_make ("playbin", "player");

    if (uri)
        g_object_set (G_OBJECT (pipeline), "uri", uri, NULL);

    {
        GstBus *bus;

        bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
        gst_bus_add_watch (bus, bus_call, NULL);
        gst_object_unref (bus);
    }

    gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);

    g_main_loop_run (loop);

    gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
    gst_object_unref (GST_OBJECT (pipeline));
}

int main (int argc, char *argv[])
{
    gst_init (&argc, &argv);

    if (argc > 1)
        play_uri (argv[1]);

    return 0;
}

使用特权

评论回复
5
sodwell| | 2008-9-11 08:34 | 只看该作者

re

LS,你上面那个Streamer库是播什么格式的?

使用特权

评论回复
6
ifree64|  楼主 | 2008-9-11 18:20 | 只看该作者

回sodwell

mp3是有损格式,不太想搞。

使用特权

评论回复
7
sinanjj| | 2008-9-11 19:55 | 只看该作者

学习关注,

同时顶一下

使用特权

评论回复
8
talent8791| | 2008-9-22 13:42 | 只看该作者

使用特权

评论回复
9
c5435| | 2008-9-28 20:29 | 只看该作者

ding

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

12

主题

159

帖子

0

粉丝