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