Board index » kylix » Problem with Alsa

Problem with Alsa


2004-10-18 05:08:46 AM
kylix2
Further to the above post, I found a really good reasource on using ALSA and
built the following routines. I wonder if anyone here knows what's wrong? I
get output from the soundcard, but it isn't what's expected ;-)
Sounds a bit like a saw-wave........
Audio packets are PCM 8khz signed 16 bit little-endian. They're sitting in a
TQueue derivative that I built which is receiving packets from a TCP/IP
Socket.
I basically have two functions, one to initialise the soundcard and one to
buffer the audio packets to is (160 bytes at a time). "F" is a pointer to my
160 byte PCM buffer.
I also get a few "buffer underruns" and I'm not sure of the reason.
Thanks,
Dean
Code is:-
unit SoundCardOut;
interface
uses pcm_ordinary, asoundlib, Libc, SysUtils;
type
TByteArray = Array[0..0] of Byte;
PByteArray = ^TByteArray;
function OutputPCM(F : Pointer; H : Psnd_pcm_t) : boolean;
function InitSoundCard : Psnd_pcm_t; //--Soundcard handle
implementation
function InitSoundCard : Psnd_pcm_t;
var
{ Handle for the PCM device }
pcm_handle: Psnd_pcm_t;
hwparams: Psnd_pcm_hw_params_t;
pcm_name: Pchar;
rate, periods, periodsize: longint;
data: PByteArray;
l1, l2: longint;
s1, s2: smallint;
num_frames: longint;
const
{ Playback stream }
stream: snd_pcm_stream_t = SND_PCM_STREAM_PLAYBACK;
begin
pcm_name := 'plughw:0,0';
{ Allocate the snd_pcm_hw_params_t structure }
snd_pcm_hw_params_malloc(hwparams);
if (snd_pcm_open(pcm_handle, pcm_name, stream, 0) < 0) then
begin
WriteLn('Error opening PCM device ', pcm_name);
Sleep(2000);
Halt(1);
end;
{ Init hwparams with full configuration space }
if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) then
begin
WriteLn('Can not configure this PCM device.');
Sleep(2000);
Halt(1);
end;
rate := 8000; { Sample rate }
periods := 8; { Number of periods }
periodsize := 160; { Periodsize (bytes) }
if (snd_pcm_hw_params_set_access(pcm_handle, hwparams,
SND_PCM_ACCESS_RW_INTERLEAVED) < 0) then
begin
WriteLn('Error setting access.');
Sleep(2000);
Halt(1);
end;
{ Set sample format }
if (snd_pcm_hw_params_set_format(pcm_handle, hwparams,
SND_PCM_FORMAT_S16_LE) < 0) then
begin
WriteLn('Error setting format.');
Sleep(2000);
Halt(1);
end;
{$ifdef ALSA_PCM_NEW_HW_PARAMS_API}
if (snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, @rate, nil) < 0)
then
{$else}
if (snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, rate, nil) < 0)
then
{$endif}
begin
WriteLn('Error setting rate.');
Sleep(2000);
Halt(1);
end;
{ Set number of channels }
if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, 2) < 0) then
begin
WriteLn('Error setting channels.');
Sleep(2000);
Halt(1);
end;
{ Set number of periods. Periods used to be called fragments. }
if (snd_pcm_hw_params_set_periods(pcm_handle, hwparams, periods, 0) < 0)
then
begin
WriteLn('Error setting periods.');
Sleep(2000);
Halt(1);
end;
{ Set buffer size (in frames). The resulting latency is given by
latency = periodsize * periods / (rate * bytes_per_frame) }
if (snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, (periodsize *
periods) shr 2) < 0) then
begin
WriteLn('Error setting buffersize.');
Sleep(2000);
Halt(1);
end;
if (snd_pcm_hw_params(pcm_handle, hwparams) < 0) then
begin
WriteLn('Error setting HW params.');
Sleep(2000);
Halt(1);
end;
snd_pcm_prepare(pcm_handle);
Result := pcm_handle;
end;
function OutputPCM(F : Pointer; H : Psnd_pcm_t) : boolean;
var num_frames: longint;
begin
num_frames := 160;
while (snd_pcm_writei(H, F, num_frames) < 0) do
begin
snd_pcm_prepare(H);
WriteLn('<<<<<<<<<<<<<<< Buffer Underrun>>>>>>>>>>>>>>>');
end;
end;
end.
 
 

Re:Problem with Alsa

Scrub that - worked it out. Needed to set it to mono for a mono file......
ALSA is great once you've got to learn how to use it :-)