NewAC Components Writer's Guide

This tutorial will teach you how to write input and output components for the NewAC components suite. In this tutorial we will write two simple components - TDemoWaveIn and TDemoWaveOut designed for reading and writing audio data stored in Wave files in raw PCM format. These components are defined in the file ComponentsDemo.pas (which you can find in the Demos\ComponentsDemo folder). There are TWaveIn and TWaveOut components in the NewAC package that are more sophisticated and more suitable for handling Wave files in real live. The two components dicussed here are just demos. TDemoWaveIn and TDemoWaveOut are writting so as to make it clear how NewAC works. But they are not the only examples. Any NewAC component may be used as a demo and the base for createing new components.

So you want to exted NewAC by adding some new audio format support. Good thought :) In fact writing new components for NerwAC is quite easy. Due to the object-oriented nature of NewAC you don't have to write everything from scratch. When you write an input component you take one of the NewAC classes (usually TAuFileIn) as your base class and override some of its methods in your new class. When you write an output component you usually make a new class descending from TAuFileOut and override some of the base class' methods in your new class. In case of the input component descending from TAuFileIn you have to override four or three base class' methods (depending on what functionality you want to provide), and in case of the output component that descends from TAuFileOut you allways have to override just three base methods.

Let's first take a look at how data is passed within NewAC. NewAC handles data as the flow of digital audio frames. Each sample consists of one or more integer samples (the number of samples in the frame is equal to the number of channels, 1 - for mono, 2 - for stereo and so on). The 8-bit samples are unsingned Bytes, and the 16-bit samples are signed SmallInts. The samples for all channels are interleaved. Thus one sample for mono 8-bit sound is 1 byte long, while one sample for stereo 16-bit sound is 4 bytes long. As far as I know there is some ambiguity in English terminology regarding frames and samples. What we call "frames" here is often called "samples", and NewAC sometimes speaks of samples instead of frames.

Writing an Input Component

Your main goal as an input component writer is to decode audio data from the format you are working with into the NewAC format and to provide additional parameters for representing an audio stream. These additional parameters are the number of bits per sample (8 or 16), the number of channels, and the sample rate in Hz. The additional parameter that you may, but not required to, provide is the audio stream size in bytes. Note that when you provide the audio stream size it is the size of the decoded audio stream, not the size of the formatted stream you are decoding from.

What are these three methods that you have to override in your new input component? Take a file metaphor. When working with files you need at least the three functions: for opening the file, for reading the file (this is usually done in a loop) and for closing the file when you are done. The three methods of TAuFileIn that you have to override do just that - opening reading and closing the file (or, more generally, - a stream). The forth method, which is not mandatory, performs seeking in the input stream.

Writing an Output Component

When writing an output component you allways have to override three methoods: Prepare, DoOutput and Done. The file metaphor may again be useful. Prepare corresponds to opening the file (for writing), DoOutput performs actual data output (it is called in a loop by NewAC) and Done performs operations analogous to closing the file. Among other things an output component inherits from TAuFileOut the FInput property. This property points to an input component (assigned to the output component's  Input published property). Note that FInput has type of TAuInput, and not TAuFileIn. The TAuInput class is the base class for all  NewAC input classes, not only those that deal with streams. Your output component initializes its input by calling the FInput.Init method and reads incoming audio parameters from FInput's properties and sets up encoder accordingly. The DoOutput method usually calls either Input's GetData method (which is described above) or the CopyData method that is based on GetData but provides a different interface. When the output component finishes its job it calls the FInput.Flush method to close the input.