[Stk] basic questions about play.cpp
Richard Dobson
richarddobson@blueyonder.co.uk
Mon, 30 Jan 2006 18:57:21 +0000
Helena Troy wrote:
> Hello,
>
> I have still a few question about play.cpp. (Did I pick a hard example
> to start with? Does anyone have a reccomendation of a good example to
> start with?)
>
It' not ane specially hard example as examples go, but like most STK programs it
does involve the selected audio API according to platform, and of course fluency
with C++; do you have any comprehensive texts covering that (e.g. Soustrup,
Deitel & Deitel)? If not, you could try "Thinking in C++", a free downloadable book:
http://mindview.net/Books/TICPP/ThinkingInCPP2e.html
Some inline replies:
> 1) - Is the second parameterof tick() (int buffersize) included in
> tick() to conform with the typedef for "RtAudioCallback"?
yes. In this respect there is not any serious difference between C++ and C,
except that C++ typically is more strict.
>
> 2) - How is the first parameter (char buffer) initialized? (I guess it
> must come from the FileWaveIn object passed thru the dataPointer
> parameterer, but I really can't tell how this initialization happens)
>
In this example the buffer size is decided largely by the audio subsystem (See
e.g. RTaudio.cpp; but STK can request a size). This in turn depends on what API
is being used (DIrectSouhnd or ASIO on WIndows, OSS or Alsa on Linux, CoreAudio
on OS X); in most cases the buffer is supplied by the host audio subsytem, and
not expressly allocated by STK at all; STK meremly asks the host how bug the
buffer is.
For example, in the DirectSound version, the buffer is declared as :
LPDIRECTSOUNDBUFFER buffer;
And this is eventually initialised with a call to DirectSound:
// Obtain the primary buffer
result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
In play.cpp, the relevant code is:
int bufferSize = RT_BUFFER_SIZE;
try {
dac = new RtAudio(0, channels, 0, 0, format, (int)Stk::sampleRate(),
&bufferSize, 4);
}
You could to use the debugger to step into all the dac->calls (including the
constructor) to find out just where the buffer comes from.
> 3) - The global StkFrames frames varible is declared at the beginning of
> the code, but (why) doesn't it have to be instantiated somewhere in the
> program with a call to 'new'?
>
This is a basic C++ question. "frames" is declared as a global variable (in
effect, on the stack - it is a full-blown object, not a pointer), and this uses
the default constructor (the first one shown in the class definition in Stk.h)
to initialse it to all zeros.
Later in play.cpp, it is initialised with a call to resize():
// Resize the StkFrames object appropriately.
frames.resize( bufferSize, channels );
C++ new is used to allocate an object dynamically (on the heap). It is a
fundamental matter to understand the difference. Funnily enough, C++ programmers
go to some lengths to avoid direct calls to new in application-level code; they
prefer to have as much allocation as possible handled inside objects (as
demonstrated by STkFrames); which means everything can be declared as a local or
global variable. It is impossible to explain this here - it is a fundamental
principle of OOP, and books have been written about it!
> 4) - Is function of tick() to move a pointer along the audio file
> passed to 'play' so that the system knows where to start when it needs
> to read the next chunk of data from the file? If you pass a very small
> file to play, I guess tick might never be called?
>
You have pretty much got this. The pointer starts out at the beginning of the
audio data (in effect position 0); so tick() will always be called at least
once. Study the RtWvIn class, together with FileRead.cpp; you will see that deep
down it uses the standard stdio fopen/fread etc calls to read the file, parse
the header, and find "position 0" of the audio data itself.
Richard Dobson