Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1676 | tullio | 1 | %---------------------------------------------------------------------------- |
2 | \chapter{The Sound Library} |
||
3 | %---------------------------------------------------------------------------- |
||
4 | |||
5 | If a SoundBlaster16 sound card is available, S.Ha.R.K. allows to sample and play |
||
6 | sounds by using the functions provided by the sound library \footnote{Currently |
||
7 | only the sound blaster 16 is supported; the code of the library is directly |
||
8 | inherited from the Hartik 3.3.0 Kernel...}. The library currently supports |
||
9 | either program or DMA controlled sampling an playing, according to 4 possible |
||
10 | operating modes: |
||
11 | |||
12 | \begin{itemize} |
||
13 | \item PIO mode; |
||
14 | \item DMA-Raw mode; |
||
15 | \item DMA-Double-buffering mode; |
||
16 | \item DMA-Self-buffering mode. |
||
17 | \end{itemize} |
||
18 | |||
19 | Working under PIO mode, sounds can be sampled and played only with 8 bit PCM. |
||
20 | The frequence depends on the hardware speeds but cannot in any case overcome 10 |
||
21 | Khz. This mode is reserved for the pure classical hard real-time approach which |
||
22 | refuses the usage of DMA controlled I/O. |
||
23 | |||
24 | The DMA-Raw mode uses DMA controller to sample and play directly on a memory |
||
25 | buffer. Owing to technical problems related to the structure of the PC DMA |
||
26 | controller, the buffer's size can be no bigger than 64K. This mode is the one |
||
27 | that minimizes the DMA operations' impact on CPU. |
||
28 | |||
29 | The DMA Double-Buffering mode uses an internal buffer in order to overcome the |
||
30 | 64k limitation. The internal buffer is split into two parts: while the DMA |
||
31 | tranfers data to one half, an ad-hoc task moves data between the second half and |
||
32 | a user-provided external memory region. In this way, it is possible for a user |
||
33 | to work on samples much bigger than 64K, paying the fee of a higher CPU load |
||
34 | \footnote{This is possible only if the protected mode is used.}. |
||
35 | |||
36 | The DMA-Self-Buffering mode allows the user to directly handle the internal |
||
37 | buffer. The user specifies a function to be activated every time the DMA |
||
38 | controller has finished transferring data on one half of the internal buyffer. |
||
39 | In this mode, the user can obtain the data while they are being sampled; the |
||
40 | time lag between sampling and data delivery is thus reduced. Such a feature |
||
41 | makes this working mode interesting for real-time applications. Independently of |
||
42 | the chosen working mode, an operation can be either synchronous or asynchronous. |
||
43 | A synchronous operation provides the task invoking the operation with a |
||
44 | synchronizing point located at its ending. In order to use the sound library |
||
45 | functions, the files \texttt{drivers/sound.h} and \texttt{drivers/dma.h} must be |
||
46 | included. The former contains the prototypes of the declared functions, the |
||
47 | latter is necessary because the sound library uses DMA. |
||
48 | |||
49 | The first step to be performed is initializing the audio drivers by the |
||
50 | \texttt{sound\_init} function. Then, if one wishes to work in DMA-Raw mode, it |
||
51 | is necessary to allocate a memory buffer and align it by calling |
||
52 | \texttt{dma\_getpage()} (in the remaining modes no particular alignment is |
||
53 | required for the buffer). If the DMA-Self-buffering mode is chosen, the |
||
54 | programmer has to properly set the functions to be called every time the DMA |
||
55 | finishes working on one half of the internal buffer; this can be done by calling |
||
56 | the \texttt{sound\_setfun()} primitive. As soon as these operations have been |
||
57 | performed, sampling or playing can be made through \texttt{sound\_sample()} and |
||
58 | \texttt{sound\_play()}, respectively. |
||
59 | |||
60 | \vspace{7mm} |
||
61 | |||
62 | \begin{intest} |
||
63 | SOUND\_INIT\index{sound\_init()} |
||
64 | \end{intest} |
||
65 | |||
66 | \begin{description} |
||
67 | \item [\textbf{void sound\_init(WORD rawbufsize, WORD tick);}] |
||
68 | \item [\textbf{Description:}] It initializes the audio driver by allocating the |
||
69 | internal |
||
70 | buffer for the DMA-Double-buffering and DMA-Self-Buffering modes. The |
||
71 | \texttt{rawbufsize} parameter contains the dimension of this buffer. Higher |
||
72 | values reduce the CPU load and are thus advised when using the |
||
73 | DMA-Double-buffering mode. Lower values, on the contrary, can be used to shorten |
||
74 | the latency between sampling and data delivering (particularly when using |
||
75 | DMA-Self-buffering). The \texttt{tick} parameter contains the value of the |
||
76 | system tick; its correctness is fundamental for the PIO mode. |
||
77 | \end{description} |
||
78 | |||
79 | \begin{intest} |
||
80 | SOUND\_INFO\index{sound\_info()} |
||
81 | \end{intest} |
||
82 | |||
83 | \begin{description} |
||
84 | \item [\textbf{void sound\_info(void);}] |
||
85 | \item [\textbf{Description:}] It outputs on the screen some information concerning |
||
86 | the soundcard and the drivers. |
||
87 | \end{description} |
||
88 | |||
89 | \begin{intest} |
||
90 | SOUND\_SETFUN\index{sound\_setfun()} |
||
91 | \end{intest} |
||
92 | |||
93 | \begin{description} |
||
94 | \item [\textbf{void sound\_setfun(int ({*}infun)(BYTE {*}rawbuff),}\\ |
||
95 | \texttt{int ({*}outfun)(BYTE {*}rawbuff));}] |
||
96 | \item [\textbf{Description:}] It specifies the functions to be called when the DMA |
||
97 | finishes working on one of the two internal buffer's halves when using |
||
98 | DMA-Self-Buffering mode. The function pointed by \texttt{infun} is used when |
||
99 | performing sampling operations, whereas \texttt{outfun} is used for playing |
||
100 | operations. Both functions receive a pointer to the half-buffer not currently |
||
101 | acted upon by the DMA (the half-buffer sizes are equal to one half of the |
||
102 | \texttt{sound\_init()} parameter) and have to return 0 if the operation has not |
||
103 | yet been finished, 1 if it is going to finish in the next DMA cycle, and 2 if it |
||
104 | finishes immediately. Attention should be paid to the fact that these functions |
||
105 | are periodically called with a frequency equal to the operation's frequency |
||
106 | divided by the half-buffer's size; thus, they should be very short in order not |
||
107 | to overload the system. |
||
108 | \end{description} |
||
109 | |||
110 | \begin{description} |
||
111 | \item [Example:] |
||
112 | \end{description} |
||
113 | |||
114 | \begin{tt} |
||
115 | \begin{verbatim} |
||
116 | int osc_fun(BYTE *b) { |
||
117 | int i; |
||
118 | int sum = 0; |
||
119 | BYTE *p; |
||
120 | |||
121 | /* Averages the values read from the buffer */ |
||
122 | /* and writes the result on a CAB shared */ |
||
123 | /* with a task */ |
||
124 | for (i = 0; i < (BUFFDIM >> 1); i++) |
||
125 | sum += b[i]; |
||
126 | sum = (BUFFDIM >> 1); |
||
127 | p = cab_reserve(cc); |
||
128 | *p = (BYTE) sum; |
||
129 | cab_putmes(cc, p); |
||
130 | return 0; |
||
131 | } |
||
132 | ... |
||
133 | |||
134 | void *io_task(void *arg) { |
||
135 | int x, y; |
||
136 | BYTE *p; |
||
137 | BYTE page = 0; |
||
138 | char str[50]; |
||
139 | short int talk, silencecount; |
||
140 | |||
141 | /* This task reads the value put on the CAB by */ |
||
142 | /* the self-buffering function */ |
||
143 | /* sets the self-buffering function */ |
||
144 | sound_setfun(osc_infun, -1); |
||
145 | |||
146 | /* starts the sampling operation */ |
||
147 | sound_sample(NULL, 20000, 0, DMA_OP | PCM8 | MYFUN); |
||
148 | cc = cab_create("osc_cab", sizeof(BYTE), 3); |
||
149 | for (;;) { |
||
150 | /* reads and proccesses */ |
||
151 | /* the CAB's value */ |
||
152 | ... |
||
153 | task_endcycle(); |
||
154 | } |
||
155 | return 0; |
||
156 | } |
||
157 | \end{verbatim} |
||
158 | \end{tt} |
||
159 | |||
160 | \begin{intest} |
||
161 | SOUND\_SAMPLE\index{sound\_sample()} |
||
162 | \end{intest} |
||
163 | |||
164 | \begin{description} |
||
165 | \item [\textbf{void sound\_sample(BYTE {*}buf, DWORD sps, DWORD len, BYTE t);}] |
||
166 | \item [\textbf{Description:}] It samples \texttt{len} bytes in the \texttt{buf} |
||
167 | buffer at the frequency of \texttt{sps} samples per second with the mode |
||
168 | expressed by \texttt{t}. The latter can be assigned one of the following |
||
169 | constants: |
||
170 | |||
171 | \begin{itemize} |
||
172 | \item \texttt{PIO\_OP} operates using PIO mode: as said earlier, in this mode |
||
173 | values for \texttt{sps} higher than 10000 make no sense. Moreover, for the |
||
174 | sampling and playing to happen with the correct timing, it is necessary that the |
||
175 | audio driver be initialized with the \texttt{tick} parameter set to the system |
||
176 | tick expressed in microseconds (see \texttt{sound\_init()} for more details). |
||
177 | \item \texttt{DMA\_OP} operates using one of the DMA modes (the default is |
||
178 | DMA-Double-Buffering). The internal buffer size is specified in |
||
179 | \texttt{sound\_init}. |
||
180 | \item \texttt{PCM8} operates using 8 bit PCM format (it is the default). It is |
||
181 | the only possible format in PIO mode. |
||
182 | \item \texttt{PCM16} operates using 16 bit PCM format. This choice is |
||
183 | meaningless in PIO mode. |
||
184 | \item \texttt{SYNCH} synchronous operation: it is necessary to call |
||
185 | \texttt{sound\_wait()} after \texttt{sound\_sample()}. |
||
186 | \item \texttt{ASYNCH} asynchronous operation. |
||
187 | \item \texttt{MYFUN} operates with DMA-Self-buffering mode; it makes sense only |
||
188 | if \texttt{DMA\_OP} has been set. |
||
189 | \item \texttt{NOBUFF} operates in DMA-Raw-Mode; it makes sense only if |
||
190 | \texttt{DMA\_OP} has been set. |
||
191 | \end{itemize} |
||
192 | \end{description} |
||
193 | |||
194 | \begin{description} |
||
195 | \item [Example:] |
||
196 | \end{description} |
||
197 | |||
198 | \begin{tt} |
||
199 | \begin{verbatim} |
||
200 | BYTE buff[0xFFFFF]; /* buffer for sampling */ |
||
201 | |||
202 | void main() { |
||
203 | sys_init(\&s); |
||
204 | keyb_init(NULL); |
||
205 | clear(); |
||
206 | |||
207 | sound_init(0x4000, TICK); |
||
208 | sound_info(); |
||
209 | |||
210 | cprintf("Recording..."); |
||
211 | sound_sample(buff, 44000, 0x8FFFF, DMA_OP | PCM8 | SYNCH); |
||
212 | ... |
||
213 | } |
||
214 | \end{verbatim} |
||
215 | \end{tt} |
||
216 | |||
217 | \begin{intest} |
||
218 | SOUND\_PLAY\index{sound\_play()} |
||
219 | \end{intest} |
||
220 | |||
221 | \begin{description} |
||
222 | \item [\textbf{void sound\_play(BYTE {*}buff, DWORD sps, DWORD len, BYTE t);}] |
||
223 | \item [\textbf{Description:}] It plays \texttt{len} bytes taken from the \texttt{b} |
||
224 | buffer |
||
225 | at the frequency of \texttt{sps} samples per second with the mode expressed by |
||
226 | \texttt{t}. As far as the values of \texttt{t} are concerned, the reader can |
||
227 | refer to \texttt{sound\_sample}. |
||
228 | \end{description} |
||
229 | |||
230 | \begin{intest} |
||
231 | DMA\_GETPAGE\index{dma\_getpage()} |
||
232 | \end{intest} |
||
233 | |||
234 | \begin{description} |
||
235 | \item [\textbf{BYTE {*}dma\_getpage(DWORD {*}dim);}] |
||
236 | \item [\textbf{Description:}] It allocates a buffer having size \texttt{dim} fitting |
||
237 | for |
||
238 | use in DMA operations. Such a usage is possible only if the buffer does not |
||
239 | contain bytes whose address differs in the Most Significant Bits. The best way |
||
240 | to achieve this feature is to allocate buffers sized less than 64K starting from |
||
241 | addresses having the LSB equal to 0. This job is performed by |
||
242 | \texttt{dma\_getpage}. It should be noted that such a feature is necessary only |
||
243 | using DMA-Raw-Mode, since the buffer allocation is automatically performed by |
||
244 | \texttt{sound\_init} when using DMA-Double-Buffering and DMA-Self-Bufering |
||
245 | modes. |
||
246 | \end{description} |
||
247 | |||
248 | \begin{description} |
||
249 | \item [Example:] |
||
250 | \end{description} |
||
251 | |||
252 | \begin{tt} \begin{verbatim} |
||
253 | void main(void) { |
||
254 | BYTE *p; |
||
255 | int i; |
||
256 | |||
257 | /* Monitors the time stolen by the DMA */ |
||
258 | /* to the CPU during a 10 Khz sampling */ |
||
259 | sys_init(&s); |
||
260 | keyb_init(NULL); |
||
261 | ... |
||
262 | clear(); |
||
263 | p = dma_getpage(0xFFFF); |
||
264 | sound_init(0x200, TICK); |
||
265 | sound_info(); |
||
266 | |||
267 | for (i = 0; i < 80; i++) cprintf("_"); |
||
268 | cprintf("ref_time: %f ", myrif); |
||
269 | cprintf("Unloaded system: %f", load(&myrif)); |
||
270 | |||
271 | cprintf("DMA Recording..."); |
||
272 | sound_sample(p, 10000, 0xFFFF, DMA_OP | PCM8 | NOBUFF); |
||
273 | ... |
||
274 | \end{verbatim} |
||
275 | \end{tt} |
||
276 | |||
277 | \begin{intest} |
||
278 | SOUND\_WAIT\index{sound\_wait()} |
||
279 | \end{intest} |
||
280 | |||
281 | \begin{description} |
||
282 | \item [\textbf{void sound\_wait(void);}] |
||
283 | \item [\textbf{Description:}] It is the synchronization primitive for synchronous |
||
284 | operations. The task calling \texttt{sound\_wait()} blocks itself until the |
||
285 | synchronous operation is finished. The call to this function is mandatory for |
||
286 | synchronous operations. On the other hand, using the function in conjunction |
||
287 | with an asynchronous operation is an error. |
||
288 | \end{description} |
||
289 | |||
290 | \begin{description} |
||
291 | \item [Example:] |
||
292 | \end{description} |
||
293 | |||
294 | \begin{tt} |
||
295 | \begin{verbatim} |
||
296 | sound_sample(buff, 44000, 0x8FFFF, DMA_OP | PCM8 | SYNCH); |
||
297 | ... |
||
298 | /* waits until the sampling termination */ |
||
299 | sound_wait(); |
||
300 | ... |
||
301 | \end{verbatim} |
||
302 | \end{tt} |