1 /** EMULib Emulation Library *********************************/
2 /**                                                         **/
3 /**                        SndALSA.c                        **/
4 /**                                                         **/
5 /** This file contains ALSA-dependent sound implementation  **/
6 /** for the emulation library.                              **/
7 /**                                                         **/
8 /** Copyright (C) Marat Fayzullin 1996-2009                 **/
9 /**     You are not allowed to distribute this software     **/
10 /**     commercially. Please, notify me, if you make any    **/
11 /**     changes to this file.                               **/
12 /*************************************************************/
13 #include "EMULib.h"
14 #include "Sound.h"
15 
16 #include <ctype.h>
17 #include <stdio.h>
18 #include <sys/types.h>
19 #include <asm/types.h>
20 #include <linux/types.h>
21 #include <sys/ioctl.h>
22 #include <sound/asound.h>
23 
24 static void *ALSA     = 0;  /* Handle to ALSA audio driver   */
25 static int SndSize;         /* ALSA audio buffer size        */
26 
27 /** InitAudio() **********************************************/
28 /** Initialize sound. Returns rate (Hz) on success, else 0. **/
29 /** Rate=0 to skip initialization (will be silent).         **/
30 /*************************************************************/
InitAudio(unsigned int Rate,unsigned int Latency)31 unsigned int InitAudio(unsigned int Rate,unsigned int Latency)
32 {
33   struct snd_pcm_hw_params *HWParams;
34   struct snd_pcm_sw_params *SWParams;
35   struct snd_output *Log;
36   int J,I;
37 
38   /* Uninitialize sound, just in case */
39   TrashSound();
40 
41   /* No sound yet */
42   ALSA = 0;
43 
44   /* If not initializing sound, drop out */
45   if(!Rate) return(0);
46 
47   /* Open ALSA PCM device */
48   if(snd_pcm_open(&ALSA,"default",SNDRV_PCM_STREAM_PLAYBACK,0)<0)
49   { ALSA=0;return(0); }
50 
51   /* Will be logging to STDOUT */
52   snd_output_stdio_attach(&Log,stdout,0);
53 
54   /* Allocate parameters structures */
55   if(snd_pcm_hw_params_malloc(&HWParams)<0) return(0);
56   if(snd_pcm_sw_params_malloc(&SWParams)<0)
57   { snd_pcm_hw_params_free(HWParams);return(0); }
58 
59   /* Set hardware parameters */
60   J = snd_pcm_hw_params_any(ALSA,HWParams);
61   J = J<0? J:snd_pcm_hw_params_set_access(ALSA,HWParams,SNDRV_PCM_ACCESS_RW_INTERLEAVED);
62   J = J<0? J:snd_pcm_hw_params_set_format(ALSA,HWParams,sizeof(sample)>1? SNDRV_PCM_FORMAT_S16_LE:SNDRV_PCM_FORMAT_S8);
63   J = J<0? J:snd_pcm_hw_params_set_channels(ALSA,HWParams,1);
64   J = J<0? J:snd_pcm_hw_params_set_rate_near(ALSA,HWParams,&Rate,0);
65   J = J<0? J:snd_pcm_hw_params_set_buffer_size(ALSA,HWParams,SndSize=((Rate*Latency)/1000+31)&~31);
66   J = J<0? J:snd_pcm_hw_params_set_periods(ALSA,HWParams,4,0);
67   J = J<0? J:snd_pcm_hw_params(ALSA,HWParams);
68 
69   /* Set software parameters */
70   J = snd_pcm_sw_params_current(ALSA,SWParams);
71   J = J<0? J:snd_pcm_sw_params_get_boundary(SWParams,&I);
72   J = J<0? J:snd_pcm_sw_params_set_stop_threshold(ALSA,SWParams,I);
73   J = J<0? J:snd_pcm_sw_params(ALSA,SWParams);
74 
75   /* Done with parameters structures */
76   snd_pcm_hw_params_dump(HWParams,Log);
77   snd_pcm_sw_params_dump(SWParams,Log);
78   snd_pcm_hw_params_free(HWParams);
79   snd_pcm_sw_params_free(SWParams);
80 
81   /* Sound initialized */
82   return(Rate);
83 }
84 
85 /** TrashAudio() *********************************************/
86 /** Free resources allocated by InitAudio().                **/
87 /*************************************************************/
TrashAudio(void)88 void TrashAudio(void)
89 {
90   /* Uninitialize ALSA sound */
91   if(ALSA) snd_pcm_close(ALSA);
92   ALSA = 0;
93 }
94 
95 /** GetFreeAudio() *******************************************/
96 /** Get the amount of free samples in the audio buffer.     **/
97 /*************************************************************/
GetFreeAudio(void)98 unsigned int GetFreeAudio(void)
99 {
100   int J;
101 
102   /* Audio should be initialized */
103   if(!ALSA) return(0);
104 
105   /* Get available frame count */
106   J=snd_pcm_avail_update(ALSA);
107   return(J>0? J:0);
108 }
109 
110 /** WriteAudio() *********************************************/
111 /** Write up to a given number of samples to audio buffer.  **/
112 /** Returns the number of samples written.                  **/
113 /*************************************************************/
WriteAudio(sample * Data,unsigned int Length)114 unsigned int WriteAudio(sample *Data,unsigned int Length)
115 {
116   int J;
117 
118   /* Audio should be initialized */
119   if(!ALSA) return(0);
120 
121   /* Send audio data */
122   J=snd_pcm_writei(ALSA,Data,Length);
123 
124   /* If failed, try recovering */
125   if(J<0) J=snd_pcm_recover(ALSA,J,0);
126 
127   /* Report problems */
128   if(J<0) printf("ALSA: %s (%d)\n",snd_strerror(J),J);
129 
130   /* Done */
131   return(J>0? J:0);
132 }
133