[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