Annotation of www/audio-port.html, Revision 1.11
1.8 naddy 1: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
2: "http://www.w3.org/TR/html4/loose.dtd">
1.1 espie 3: <html>
4: <head>
5: <meta http-equiv="Content-Type"
6: content="text/html; charset=iso-8859-1">
7: <meta name="resource-type"
8: content="document">
9: <meta name="description"
10: CONTENT="How to make an OpenBSD port; audio">
11: <meta name="keywords"
12: content="openbsd,ports,audio">
13: <meta name="distribution"
14: content="global">
15: <meta name="copyright"
1.6 horacio 16: content="This document copyright 1998-2002 by OpenBSD.">
1.1 espie 17: <title>Porting audio applications to OpenBSD</title>
18: <link rev="made" HREF="mailto:www@openbsd.org">
19: </head>
20: <body text="#000000" bgcolor="#FFFFFF" link="#23238E">
1.7 jsyn 21: <a href="index.html"><img alt="[OpenBSD]" height="30" width="141" src="images/smalltitle.gif" border="0"></a>
1.1 espie 22:
23: <h1>Porting audio applications to OpenBSD</h1>
24:
25: <p>
26: This document currently deals with sampled sounds issues only. Contributions
27: dealing with synthesizers and waveform tables are welcome.
28:
29: </p>
1.8 naddy 30: <p>
1.1 espie 31: Audio applications tend to be hard to port, as this is a domain where
32: interfaces are not standardized at all, though approaches don't vary
33: much between operating systems.
1.8 naddy 34: </p>
1.1 espie 35:
1.8 naddy 36: <h2><font color="#e00000">Using <code>ossaudio</code></font></h2>
1.1 espie 37:
38: The <code>ossaudio</code> emulation is possibly the simplest way, but
39: it won't always work, and it is not such a great idea usually.
40: <ul>
41: <li>It redefines <code>ioctl</code>. If the code to port uses
42: <code>ioctl</code> for more than audio, you will have to
43: <code>#undef ioctl</code> and use the bare form with
44: <code>_ossioctl</code>.
45:
46: <li>Some features of linux sound are not emulated.
47:
48: <li>Applications with correct linux sound support that is not
49: Intel-specific tend to use these features.
50:
51: </ul>
52:
1.8 naddy 53: <h2><font color="#e00000">Using existing NetBSD or FreeBSD code</font></h2>
1.1 espie 54: Since we share part of the audio interface with NetBSD and FreeBSD,
55: starting from a NetBSD port is reasonable. Be aware that some files
56: changed places, and that some entries in <code>sys/audioio.h</code>
57: are obsolete. Also, many ports tend to be incorrectly coded and to
58: work on only one type of machine. Some changes are bound to be
59: necessary, though. Read through the next part.
60:
1.8 naddy 61: <h2><font color="#e00000">Writing OpenBSD code</font></h2>
1.11 ! sthen 62:
! 63: <h3><font color="#0000e0">libsndio</font></h3>
! 64: <p>
! 65: OpenBSD has its own audio layer provided by the sndio library,
! 66: documented in
! 67: <a href="http://www.openbsd.org/cgi-bin/man.cgi?query=sio_open&sektion=4">sio_open(4)</a>.
! 68: Until it's merged into this page, you can find further information
! 69: about programming for this API in the guide,
! 70: <a href="http://caoua.org/alex/obsd/libsndio.html">hints on
! 71: writing and porting audio code</a>.
! 72: sndio allows user processes to access
! 73: <a href="http://www.openbsd.org/cgi-bin/man.cgi?query=audio&sektion=4">audio(4)</a>
! 74: hardware and the
! 75: <a href="http://www.openbsd.org/cgi-bin/man.cgi?query=aucat&sektion=1">aucat(1)</a>
! 76: audio server in a uniform way.
! 77: It supports full-duplex operation, and when used with the
! 78: <a href="http://www.openbsd.org/cgi-bin/man.cgi?query=aucat&sektion=1">aucat(1)</a>
! 79: server it supports resampling and format conversions on the fly.
! 80: </p>
! 81:
1.8 naddy 82: <h3><font color="#0000e0">Hardware independence</font></h3>
1.1 espie 83:
84: <p>
85: <strong>YOU SHOULDN'T ASSUME ANYTHING ABOUT THE AUDIO HARDWARE USED.
86: </strong><br>
87: Wrong code is code that only checks the <code>a_info.play.precision</code>
88: field against 8 or 16 bits, and assumes unsigned or signed samples based
89: on soundblaster behavior. You should check the sample type explicitly,
90: and code according to that. Simple example:
1.8 naddy 91: </p>
1.1 espie 92: <pre>
93: AUDIO_INIT_INFO(&a_info);
94: a_info.play.encoding = AUDIO_ENCODING_SLINEAR;
95: a_info.play.precision = 16;
96: a_info.play.sample_rate = 22050;
97: error = ioctl(audio, AUDIO_SETINFO, &a_info);
98: if (error)
99: /* deal with it */
100: error = ioctl(audio, AUDIO_GETINFO, &a_info);
101: switch(a_info.play.encoding)
102: {
103: case AUDIO_ENCODING_ULINEAR_LE:
104: case AUDIO_ENCODING_ULINEAR_BE:
105: if (a_info.play.precision == 8)
106: /* ... */
107: else
108: /* ... */
109: break;
110: case ...
111:
112: default:
113: /* don't forget to deal with what you don't know !!! For instance, */
114: fprintf(stderr,
115: "Unsupported audio format (%d), ask ports@ about that\n",
116: a_info.play.encoding);
117:
118: }
119: /* now don't forget to check what sampling frequency you actually got */
120: </pre>
121:
1.8 naddy 122: <p>
1.1 espie 123: This is about the smallest code fragment that will deal with most issues.
124:
1.10 aanriot 125: <h3><font color="#0000e0">16 bit formats and endianness</font></h3>
1.1 espie 126: In normal usage, you just ask for an encoding type (e.g.,
1.9 saad 127: <code>AUDIO_ENCODING_SLINEAR</code>), and you retrieve
1.10 aanriot 128: an encoding with endianness (e.g., <code>AUDIO_ENCODING_SLINEAR_LE</code>).
129: Considering that a soundcard does not have to use the same endianness
1.1 espie 130: as your platform, you should be prepared to deal with that.
131: The easiest way is probably to prepare a full audio buffer, and to use
1.10 aanriot 132: <code>swab(3)</code> if an endianness change is required.
1.1 espie 133: Dealing with external samples usually amounts to:
134: <ol>
135: <li>Parsing the sample format,
136: <li>Getting the sample in,
1.10 aanriot 137: <li>Swapping endianness if it is not your native format,
1.1 espie 138: <li>Computing what you want to output into a buffer,
1.10 aanriot 139: <li>Swapping endianness if the sound card is not in your native format,
1.1 espie 140: <li>Playing the buffer.
141: </ol>
142: Obviously, you may be able to remove steps 3 and 5 if you are simply
143: playing a sound sample which happens to be in your sound card native
144: format.
145:
1.8 naddy 146: <h3><font color="#0000e0">Audio quality</font></h3>
1.1 espie 147: <p>
148: Hardware may have some weird limitations, such as being unable to get
149: over 22050 Hz in stereo, but up to 44100 in mono. In such cases, you
150: should give the user a change to state his preferences, then try your
151: best to give the best performance possible. For instance, it is stupid
152: to limit the frequency to 22050 Hz because you are outputting stereo.
153: What if the user does not have a stereo sound system connected to his
154: audio card output ?
155: </p>
156:
157: <p>
158: It is also stupid to hardcode soundblaster-like limitations into your
159: program. You should be aware of these, but do try to get over the
160: 22050 Hz/stereo barrier and check the results.
161: </p>
162:
163: <h4>Sampling frequency</h4>
164: You should definitely check the sampling frequency your card gives you
165: back. A 5% discrepancy already amounts to a half-tone, and some people
166: have much more accurate hearing than that, though most of us won't
167: notice a thing. Your application should be able to perform
168: resampling on the fly, possibly naively, or through devious
169: applications of Shannon's resampling formula if you can.
170:
171: <h4>Dynamic range</h4>
172: <p>
173: Samples don't always use the full range of values they could. First,
174: samples recorded with a low gain will not sound very loud on the
175: machine, forcing the user to turn the volume up.
176: Second, on machines with badly isolated audio, low sound output means
177: you mostly hear your machine heart-beat, and not the sound you expected.
178: Finally, dumb conversion from 16 bits to 8 bits may leave you with only
179: 4 bits of usable audio, which makes for an awfully bad quality.
180: </p>
181: <p>
182: If possible, the best solution is probably to scan the whole stream
183: you are going to play ahead of time, and to scale it so that it fits
184: the full dynamic range. If you can't afford that, but you can manage
185: to get a bit of look-ahead on what you're going to play, you can
186: adjust the volume boost on the fly, you just have to make sure
187: that the boost factor stays at a low frequency compared to the
1.3 jufi 188: sound you want to play, and that you get absolutely <em>no
189: overflows</em> -- those will always sound much worse than the
1.1 espie 190: improvement you're trying to achieve.<br>
191: As sound volume perception is logarithmic, using arithmetic shifts is usually
192: enough. If your data is signed, you should explicitly code the shift as
193: a division, as C <code>>></code> operator is not portable on
194: signed data.
195: </p>
196: <p>
197: If all else fails, you should at least try to provide the user with
198: a volume scaling option.
199: </p>
200:
1.8 naddy 201: <h3><font color="#0000e0">Audio performance</font></h3>
1.1 espie 202: <p>
203: Low-end applications usually don't have much to worry about. Keep in
204: mind that some of us do use OpenBSD on low-end 68030, and that if a
205: sound application can run on that, it should.
206: </p>
207:
208: <p>
209: Don't forget to run benches. Theoretical optimizations are just that:
210: theoretical. Some hard figures should be collected to check what's a
211: sizeable improvement, and what's not.
212: </p>
213:
214: <p>
215: For high performance audio applications, such as mpegI-layer3, some
216: points should be taken into account:
1.8 naddy 217: </p>
1.1 espie 218: <ul>
219: <li>The audio interface does provide you with the natural hardware
220: blocksize. Using multiples of that for your output buffer is
221: essential. Keep in mind that <code>write</code>, as a system call,
222: incurs a high cost compared to internal audio processing.
223:
224: <li>Bandwidth is a very important factor when dealing with audio.
225: A useful way to optimize an audio player is to see it as a
226: decompressor. The longer you can keep with the compressed data, the
227: better usually. Very short loops that do very little processing are
228: usually a bad idea. It is generally much better to combine all
229: processing into one loop.
230:
231: <li>Some formats do incur more overhead than others. The
232: <code>AUDIO_GETENC</code> <code>ioctl</code> should be used
233: to retrieve all formats that the audio device provides.
234: Be especially aware of the
235: <code>AUDIO_ENCODINGFLAG_EMULATED</code> flag. If your
236: application is already able to output all kinds of weird formats,
237: and reasonably optimized for that, try to use a native format at
238: all costs. On the other hand, the emulation code present in the
239: audio device can be assumed to be reasonably optimal, so don't
240: replace it with quickly hacked up code.
241: </ul>
242:
243: <p>A model you may have to follow to get optimal results is to first
244: compile a small test program that enquires about the specific audio
245: hardware available, then proceed to configure your program so that it
246: deals optimally with this hardware. You may reasonably expect people
247: who want good audio performance to recompile your port when they change
248: hardware, provided it makes a difference.
249: </p>
250:
1.8 naddy 251: <h3><font color="#0000e0">Real time or synchronized</font></h3>
1.1 espie 252: <p>
253: Considering that OpenBSD is not real time, you may still wish to write
254: audio applications that are mostly real time, for instance games. In
255: such a case, you will have to lower the blocksize so that the sound
256: effects don't get out of synch with the current game. The problem
257: with this if that the audio device may get starved, which yields
258: horrible results.
259: </p>
260: <p>
261: In case you simply want audio to be synchronized with some graphics
262: output, but the behavior of your program is predictable, synchronization
263: is easier to achieve. You just play your audio samples, and ask the
264: audio device what you are currently playing with
265: <code>AUDIO_GETOOFFS</code>, then use that information to
266: post-synchronize graphics. Provided you ask sufficiently often (say,
267: every tenth of a second), and as long as you have enough horse-power to
268: run your application, you can get very good synchronization that way.
269: You might have to tweak the figures by a constant offset, as there is
270: some lag between what the audio reports, what's currently playing, and
271: the time it takes for XWindow to display something.
272: </p>
1.8 naddy 273: <h2><font color="#e00000">Contributing code back</font></h2>
1.1 espie 274: <p>In the case of audio applications, working with the original program's
275: author is very important. If his code does only work with soundblaster
276: cards for instance, there is a good chance he will have to cope with
277: other technology soon.
278: </p>
279:
280: <p>
281: <strong>If you don't sent your comments to him by then, your work will
282: have been useless</strong>.</p>
1.8 naddy 283: <p>
1.1 espie 284: It may also be that the author has already noticed whatever problems
285: you are currently dealing with, and is addressing them in his current
286: development tree. If the patches you are writing amount to more than
287: a handful of lines, cooperation is almost certainly a very good idea.
1.8 naddy 288: </p>
1.1 espie 289:
290: <hr>
291: <a href="porting.html"><img height=24 width=24 src=back.gif
292: border=0 alt=Porting></a>
1.8 naddy 293: <a href="mailto:www@openbsd.org">www@openbsd.org</a>
1.11 ! sthen 294: <br><small>$OpenBSD: audio-port.html,v 1.10 2007/06/01 19:54:48 aanriot Exp $</small>
1.1 espie 295: </body>
296: </html>