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