LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 853|回复: 6

linux 下声卡 编程

[复制链接]
发表于 2004-7-20 00:10:50 | 显示全部楼层 |阅读模式
用系统调用write()写linux下的ac97 声卡时,当写数据的速度大于声卡 发声(消耗数据)的速度 时 进程就会被阻塞。 但是 既要使声卡连续发声 又要让进程 同时做其他事 该怎么办啊?
发表于 2004-7-20 01:38:51 | 显示全部楼层
multi-thread

However I recommand you do not write raw data to the card directly, you should rely on some higher level libraries, such as alsa etc.
 楼主| 发表于 2004-7-20 12:03:54 | 显示全部楼层
but i develope it for an embedded system ,and there seems no such libraries available.
发表于 2004-7-21 22:43:35 | 显示全部楼层
用select可以轮询吧
发表于 2004-7-22 08:29:43 | 显示全部楼层
楼上说的多线程和select(或poll)都是合理的解决之道,
还有,可以检查声卡输出缓冲区,如果空间不够就先不写,
参考ioctl用法
发表于 2004-7-22 10:18:22 | 显示全部楼层
SDL库提供了声音的支持,而且不会和其他的声音冲突
我做一个游戏写的一个声音处理部分可以供你参考

sound.h

#ifndef TANK_SOUND_H
#define TANK_SOUND_H
#include <SDL/SDL.h>

#define SND_FAILED    1
#define SND_OK          0
#define SND_NORMAL 0
#define SND_LOOP      1
//#define SND_MAX_TRACK 1;

typedef struct sound_s{
  Uint8 *samples;
  Uint32 length;
}sound_t, *sound_p;

typedef struct playing_s {
  int active;
  sound_p sound;
  Uint32 position;
  int loop;              /*  0 play once,  1 play repeatly */
} playing_t, *playing_p;

SDL_AudioSpec AudioSpec,AudioObtained;

int initSound();
int LoadAndConvertSound(char *filename, SDL_AudioSpec *spec, sound_p sound);
int PlaySound(sound_p sound, int loop);  // 0 play once,  1 play repeatly
void ClearPlayingSounds(void);

#endif

以下是实现文件
sound.c

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "sound.h"

#define MAX_PLAYING_SOUNDS 10
playing_t playing[MAX_PLAYING_SOUNDS];


#define VOLUME_PER_SOUND SDL_MIX_MAXVOLUME / 2

/* initializing sound system */

void AudioCallback(void *user_data, Uint8 *audio, int length)
{
  int i;

  memset(audio,0,length);
  
  for(i=0;i<MAX_PLAYING_SOUNDS;i++){
    if(playing.active){
      Uint8 *sound_buf;
      Uint32 sound_len;

      sound_buf=playing.sound->samples;
      sound_buf+=playing.position;

      if((playing.position+length)>
         playing.sound->length){
        sound_len = playing.sound->length -
          playing.position;
      }else{
        sound_len=length;
      }

      SDL_MixAudio(audio, sound_buf, sound_len,
                   VOLUME_PER_SOUND);
      
      playing.position += length;

      if(playing.position >= playing.sound->length){
        if(playing.loop == SND_LOOP) playing.position = 0;
        else
           playing.active=0;
      }
    }
  }
}

int initSound()
{
AudioSpec.freq = 44100;
AudioSpec.format = AUDIO_S16;
AudioSpec.samples = 4096;
AudioSpec.channels =2;
AudioSpec.callback = AudioCallback;
AudioSpec.userdata = NULL;

atexit(SDL_CloseAudio);

if(SDL_OpenAudio(&AudioSpec, &AudioObtained)<0){
        printf("Unable to open audio device: %s\n", SDL_GetError());
        return SND_FAILED;
}

ClearPlayingSounds();
SDL_PauseAudio(0);

return SND_OK;
}

int LoadAndConvertSound(char *filename, SDL_AudioSpec *spec,
                        sound_p sound)
{
  SDL_AudioCVT cvt;
  SDL_AudioSpec loaded;
  Uint8 *new_buf;

  if(SDL_LoadWAV(filename,
                 &loaded, &sound->samples,
                 &sound->length)==NULL){
    printf("Unable to load sound: %s\n", SDL_GetError());
    return SND_FAILED;
  }
  if(SDL_BuildAudioCVT(&cvt, loaded.format,
                       loaded.channels, loaded.freq,
                       spec->format,spec->channels,
                       spec->freq)<0){
    printf("Unable to convert sound: %s\n",SDL_GetError());
    return SND_FAILED;
  }
  
  cvt.len=sound->length;
  new_buf=(Uint8 *) malloc(cvt.len*cvt.len_mult);
  if(new_buf==NULL){
    printf("Memory allocation failed.\n");
    SDL_FreeWAV(sound->samples);
    return SND_FAILED;
  }

  memcpy(new_buf, sound->samples, sound->length);
  
  cvt.buf=new_buf;
  if(SDL_ConvertAudio(&cvt)<0){
    printf("Audio conversion error: %s\n",SDL_GetError());
    free(new_buf);
    SDL_FreeWAV(sound->samples);
    return SND_FAILED;
  }

  SDL_FreeWAV(sound->samples);
  sound->samples = new_buf;
  sound->length =sound->length*cvt.len_mult;

  printf("'%s' was loaded and converted successfully.\n", filename);

  return SND_OK;
}

void ClearPlayingSounds(void)
{
  int i;
  for(i=0; i<MAX_PLAYING_SOUNDS; i++){
    playing.active =0;
  }
}

int PlaySound(sound_p sound, int loop) // 0 play once,  1 play repeatly
{
  int i;

  for(i=0;i<MAX_PLAYING_SOUNDS; i++){
    if(playing.active == 0)
      break;
  }

  if(i==MAX_PLAYING_SOUNDS)
    return SND_FAILED;

  SDL_LockAudio();
  if(loop) playing.loop=SND_LOOP;
  else
    playing.loop=SND_NORMAL;
  playing.active = 1;
  playing.sound = sound;
  playing.position =0;
  
  SDL_UnlockAudio();
  return SND_OK;
}


目前只能放wav文件,这么用
test.c
#include <SDL/SDL.h>
#include "sound.h"

int main()
{
  sound_t s_background;
if(SDL_Init(SDL_INIT_AUDIO)!=0) {
    printf("无法初始化 SDL: %s\n", SDL_GetError());
    return 1;
  }

  atexit(SDL_Quit);
  initSound();
  if(LoadAndConvertSound("background.wav",&AudioObtained,
                         &s_background)!=0){
    printf("Unable to load sound.\n");
    return 1;
  }
  PlaySound(&s_background,SND_LOOP); // 循环放

SDL_Delay(30000);  //  延时30秒,以便你能听到声音
SDL_PauseAudio(1);   // 暂停声音播放
SDL_LockAudio();       // 暂停向声卡写数据
  
  free(s_background.samples);  // 释放声音文件

  SDL_UnlockAudio();  // 解除锁
}
 楼主| 发表于 2004-7-22 13:17:04 | 显示全部楼层
问题基本解决了 ,如果先检测有没有空闲的fragment 可写 若有在写的 话 进程就不会被阻塞的。 如果没有还写,才会被阻塞。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表