Author: Andrei Borovsky, anb@symmetrica.net
Project home page: www.symmetrica.net/newac. You will find some additional NewAC stuff there.
This document covers the following topics:
NewAC and ACS - Disambiguation
Introduction to NewAC Programming
What other libraries you need to use all the features of NewAC
NewAC and ACS - Disambiguation
I was developing Audio Components Suite (ACS) in 2002-2005 and then released ACS development to other people. Not long ago I decided to revive my old ACS code, but since the name has been already in use by the other project, I renamed my components to New Audio Components (NewAC). NewAC is more similar to the ACS 2.3 than the new ACS 2.4.
What's new in NewAC 1.0.1
What's new in NewAC 1.0
What's new in ACS 2.3
What's new in ACS 2.2
There are also some other minor changes and fixes in ACS.
Thanks Section
Several people have made contributions to the ACS code. Among those I want to thank specially:
Lev Amelin (leo-soft@yandex.ru) - for improved and extended TMP3Out component.
Thomas la Cour, tlc@top-house.dk, http://www.top-house.dk/~nr161/delphi/ - for providing Monkey Audio input/output components.
Jan Henrik Ejme (jan.h.ejme@xhlp.com) - for adding ACM-plaing support.
Thomas Grelle (grelle@online.de) - for improving CDRip support.
Jan Bartels (ATR Industrie-Elektronik GmbH & Co. KG, Viersen, Germany) - for some useful corrections and suggestions.
And all other folks who sent me their comments and suggestions.
Introduction to NewAC Programming
The New Audio Components package is a set of components designed to handle different sound processing tasks, such as reading and storing data in different audio formats, working with sound hardware, audio streams mixing and so on.
Most of the components in the New Audio Components package belong to one of three categories: input components, output components, converter components. There are also two components that do not fit into this scheme. These arfe TCDPlayer component and TMixer component.
The input components acquire audio input from some source (device, disk file, etc.) and convert it into a digital audio stream which is the internal audio representation in NewAC. The output components take in the digital audio produced by input components and send it to some audio output device or store it on disk in a specified audio file format. Converter components perform different operations on audio streams. These components take in a digital audio stream and output a stream which is modified according to the function of the component. The following diagram illustrates the flow of audio data in the NewAC processing chain:
All components are linked via their Input properties. Arrows show connections bwtween components (from WaveOut1 to AudioIn1). Audio data flows through the chain in the opposite direction - from AudioIn1 to WaveOut1. In this example we read audio data from the soundcard input component AudioIn1 (input component), pass it through the RateConverter1 component (converter component) and store in a *.wav file via WaveOut1 component (output component).
The converter component is not a necessary element in this chain. In many cases you will just connect input and output components together to convert data from one format to the other or to perform I/O with some particular device. As you can see NewAC isn't just a collection of components implementing interfaces to some hardware or file formats. It is rather a set of building blocks with which you can construct a complete sound-processing application.
The driving force of this sound processing chain is an output component. Output components use internal thread objects that call data-retrieving functions of the input/converter components attached to the output component. Note that NewAC provides you with several ways to set the amount of CPU time consumed by these threads: TheradPriority, Delay, and SuspendWhenIdle properties. You can use this features to set the best performance/CPU usage ratio in your NewAC applications.
Suppose you want your application to convert data from audio CD tracks to Ogg Vorbis audio compression format. First, you put into your form a TCDIn input component that reads data from CD tracks (don't confuse this component with TCDPlayer component which is designed to play CD tracks). Now you need an output component, and in our case it is VorbisOut. In order to chain two components together you have to assign an instance of the TCDIn component to the VorbisOut's Input property:
VorbisOut1.Input := CDIn1;
Now set the CD track you want to be converted:
CDIn1.StartTrack := 1;
CDIn1.EndTrack := 1;
This tells the component to read only one track (the first track on the CD).
Now you have to set up a file name for an output file:
VorbisOut1.FileName := 'Track1.ogg';
And desired compression ratio:
VorbisOut1.Compression := 0.1;
Believe it or not, you have now set up everything for the data conversion. In order to perform the conversion, simply call:
VorbisOut1.Run;
The actual compression process runs in its own thread, while your main thread can do something else. You can control how conversion goes on by checking VorbisOut1's Progress property. When the conversion is finished, the VorbisOut1.OnDone property will be called.
You get access to an input component's data directly in a non-threaded way. The following example shows how data can be obtained from an audio CD with the TCDIn component.
var Len, DataSize : Integer; Data : Pointer; begin ... CDIn1.StartTrack := 1; CDIn1.EndTrack := 1; CDIn1.Init; Len := CDIn1.GetData(Data, DataSize); while Len <> 0 do begin // Process CD data Len := CDIn1.GetData(Data, DataSize); end;
CDIn1.Flush;
Let's take another example. Suppose, we want to get stereo audio data from a *.wav file, convert it to mono and save to another *.wav file. We will need an instance of the TWaveIn component, which reads data from a *.wav file, an instance of the TMSConverter component that converts stereo strem to mono and vice versa, and an instance of the TWaveOut component that writes data to a *.wav file. Now we chain these three components:
WaveIn1.FileName := 'input.wav'; MSConverter1.Input := WaveIn1; WaveOut1.Input := MSConverter1; WaveOut1.FileName := 'output.wav'; WaveOut1.Run;
Converter components take input from input components or from other converters and output data to output components or other converters. It is possible to chain any number of converters this way. There is a special converter in NewAC called AudioMixer. This component takes in two audio streams and mixes them into a single output stream. In the new version of NewAC AudioMixer can also concatenate to incoming audio streams, i.e. make one stream where two input streams go consecutively
You can call the output component’s Stop method to terminate an ongoing playback at any time, but because of the multithreaded nature of NewAC the playback doesn’t stop at once after the Stop method has returned. There are two ways for your application to be notified when the playback has stopped. OnDone event is raised only after playback is actually stopped so you can use OnDone event handler to get notified when your App’s audio chain finishes playing. Sometimes you don’t want to wait for OnDone event. For example it is a good practice to stop any current output in the Application’s Form OnClose Event. When handling an OnClose event you cannot wait for an OnDone event to know when to proceed with a program's termination. You can call the WaitForStop method instead:
WaveOut1.Stop(False); WaveOut1.WaitForStop; // Now output is actually done
After you have called the Stop method you may call WaitForStop to know exactly when the output is done. This way you can wait for the playback being stopped in the same method (the OnClose handler, for example) where you called Stop. WaitForStop blocks until the audio processing chain goes idle. When called on already stopped chain WaitForStop returns immediately (so you don't have to check if component is playing to call Stop/WaitForStop sequence). If you use WaitForStop to get notified when output is done you probably don’t want OnDone event to be raised at all. You can disable OnDone event generation for some particular Stop call by passing False value to Stop method (Stop's parameter is set to True by default so calling Stop; is equivalent to calling Stop(True);).
In some cases you may want to start the next audio task automatically right after the previous task has been finished. Suppose you build an audio player with a kind of playlist. You want the files in the playlist to be played one after another. When the current file playback or other output operation is finished output component generates OnDone event indicating it has finished current output operation. Starting from the NewAC version 1.0 you can set new input source component (or reset current input properties) from OnDone event handler. See AudioPlayer demo program for an example.
This topic is thoroughly described in the farther documentation, but people send me so many questions on it that I decided to put an additional explanation here.
The actual input and output is performed in NewAC by threads. It is natural to put the thread into the suspended state when it has no job to do and resume the thread when it has one. However, when developing under Kylix IDE suspending and resuming threads may be inconvenient since every time such an operation is performed, signals are emitted. These signals are trapped by the IDE, and the program execution stops. That is why SuspendWhenIdle property has been introduced. The idea behind this property is that when you develop an application under Kylix, you set this property to False, so that the NewAC threads don’t get suspended. When you’re preparing the final release, you set this property to True which makes the threads to be suspended when there is no job for them and thus reduces CPU load.
Under Linux the default value of SuspendWhenIdle property is False so threads don’t get suspended by default. Under Windows, where there is no problem with signals the default value of this property is True and there is no need to change it.
Two following pictures show the CPU load with SuspendWhenIdle set to False and True respectively. The high plateau on the right side of the first picture corresponds to the high CPU cycles consumption by the idle thread not being suspended.
Output components' threads are designed in such a way that when an exception occures within the thread, it is caught by the thread procedure itself and isn't propagated. To be informed about exceptions that might arise during thread execution, assign a handler to the OnThreadException event of the output component. A reference to the exception object is passed to this event handler, so that you can analyse the exception.
Starting from the ACS version 2.2 most of the components that have Input property (output and converter components) allow assigning new input on the fly (i.e. while the component is doing playback). It is important to remember that when changing input on the fly, new input audio stream parameters must be thhe same as the old ones. Note that TAudioProcessor Component doesn't allow modifing Input property while it is playing. InputList component allows modifing all input items at anytime except the item, currently being played. You can switch to other InputList's item on the fly by changing the components CurrentInput property.
This section explains how to avoid some errors that are most often encountered by the programmers beginning to use NewAC.
Some of NewAC components require certain shared libraries, which are not included in the package but are publicly available and may be found on many sites. In order to use VorbisIn and VorbisOut components you will need Ogg Vorbis shared libraries. The original libraries are available at www.xiph.org Important note: the alternative versions of Ogg Vorbis libraries specially adapted for use in Delphi applications are available. It is recommended to use the adapted libraries with NewAC. You can download required libraries and sources from the NewAC Site.
TMP3In component requires smpeg and SDL libraries. These libraries are included into windlls.zip archive (see below).
TFLACIn and TFLACOut components depend on libFLAC.dll library under Windows and libFLAC.so library under Linux.
TMP3ToWav component requires MADLib.dll library.
Monkey Audio components require MacDLL.dll library. This library is included into windlls.zip archive (see below). You can also download it with Monkey Audio SDK available on the Net.
Under Windows TCDIn component requires CDRip.dll library distibuted under GPL (I use the variant of the library distributed with NeoAudio). TMP3Out component requires lame_enc.dll (under Windows) or libmp3lame.so (under Linux).
Note on using LAME: LAME is an encoder created for educational purposes only. It may be illegal to use LAME in your Country. Check this out.
It is important to note that since all libraries required by NewAC components are loaded dynamically at run-time, you can use NewAC as a whole without these libraries. Of course, those components requiring certain library will only work if the library is found.
You can download all Windows dlls required by NewAC components in binary form. You can also download libraries' sources
.Installation
If you have installed previous version of ACS or NewAC, uninstall it before installing the new version. Click Component->Install Packages menu item. In the opened dialog box select the Audio Components Suite package and click "Remove" button. Make sure to remove all the previous version files from the IDE search path.
To install New Audio Components package, first compile the package. Create or select directory where you want the components to be installed (you can use your Delphi lib directory). We will call this directory NewAC directory. Now go to the Source directory of the NewAC distribution, and copy all the files to the NewAC directory. Go to the NewAC directory, open NewAC.dpk file in your IDE. Press "Compile" button in the package manager window. Press Install button.. After this the two new tabs: "Audio I/O" and "Audio Processing" will appear on the components palette. Unless you have selected your Delphi lib directory as NewAC directory, you will have to add the NewAC installation directory to the Delphi libraries search path. This can be done on the "Library" page of the "Environment Options" dialog box (Tools->Environment Options... menu item).
Copyright © 2002-2007 Andrei Borovsky. All rights reserved.