CSL  6.0
PAIO.cpp
Go to the documentation of this file.
1 //
2 // PAIO.cpp -- DAC IO using PortAudio
3 // See the copyright notice and acknowledgment of authors in the file COPYRIGHT
4 //
5 
6 #include "PAIO.h"
7 #include <iostream>
8 
9 using namespace csl;
10 
11 // Constructors
12 
13 //PAIO::PAIO() : IO() {
14 // Pa_Initialize();
15 // mStatus = kIONew;
16 //}
17 
18 PAIO::PAIO(unsigned sr, unsigned bs, int in_stream, int out_stream, unsigned in_chans, unsigned out_chans)
19  : IO(sr, bs, in_stream, out_stream, in_chans, out_chans) {
20  Pa_Initialize();
21  mStatus = kIONew;
22  this->initialize(sr, bs, in_stream, out_stream, in_chans, out_chans);
23 }
24 
26 //#ifdef CSL_DEBUG
27  logMsg("PAIO::destructor");
28 //#endif
29  if (mStatus == kIORunning)
30  stop();
31  if (mStatus == kIOOpen)
32  close();
33  if (mInputParameters != NULL)
34  free(mInputParameters);
35  if (mOutputParameters != NULL)
36  free(mOutputParameters);
37 }
38 
39 // The PortAudio callback function
40 
41 static int pa_callback (const void * inputPointer, void * outputPointer,
42  unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *outTime,
43  PaStreamCallbackFlags statusFlags, void * userData) {
44  PAIO * paio = (PAIO *) userData; // cast the user data pointer as a PAIO guy
45  sample * out = (float *) outputPointer;
46  if (paio->mStatus != kIORunning)
47  return 0;
48  if (paio->mGraph == 0) { // if there's no input graph, just play silence...
49 // memset(out, 0, (framesPerBuffer * numOutChannels * sizeof(sample)));
50  return 0;
51  }
52  Buffer * outBuffer = & (paio->mOutputBuffer);
53 // unsigned numOutChannels = outBuffer->mNumChannels;
54  outBuffer->mNumFrames = framesPerBuffer;
55 #ifdef CSL_DEBUG
56  logMsg("PAIO::callback (%x)", paio->mGraph);
57 #endif
58  paio->mNumFramesPlayed += framesPerBuffer;
59  if (paio->mNumInChannels > 0) {
60  paio->mInputPointer = (float *) inputPointer; // get the I/O buffer pointers
61  paio->mInputBuffer.mNumFrames = framesPerBuffer; // interleaved
62  }
63  paio->pullInput(*outBuffer, out);
64  return 0;
65 }
66 
67 // PA error handler
68 
69 void PAIO::handleError(PaError err) throw(CException) {
70  Pa_Terminate();
71  logMsg(kLogError, "An error occured while using PortAudio");
72  logMsg(kLogError, "Error number: %d", err);
73  logMsg(kLogError, "Error message: %s", Pa_GetErrorText(err));
74  throw IOError("Portaudio error");
75 }
76 
77 // Open port audio
78 
79 void PAIO::open() throw(CException) {
80  PaError err;
81  if (mStatus == kIOOpen) // already open
82  return;
83  if (mStatus != kIOInit) {
84  logMsg(kLogError, "Error opening PortAudio in state %d\n", mStatus);
85  return;
86  } // Allocate the IO buffers
93 //#ifdef CSL_DEBUG
94  logMsg("PAIO::open");
95 //#endif
96  err = Pa_OpenStream (&mStream, // the big open_stream call
97  mInputParameters, // set up input device
98  mOutputParameters, // set up output device
99  (double) CGestalt::frameRate(),
101  0, // stream flags
102  pa_callback, // our callback function (see above)
103  this); // user data = this PAIO object
104 
105  if (err != paNoError) {
106 #ifdef CSL_DEBUG
107  logMsg("Error opening PortAudio: %s", Pa_GetErrorText(err ));
108 #endif
109  throw IOError("Error opening PortAudio");
110  }
111 #ifdef DO_TIMING
112  mThisSec = mTimeVals = mTimeSum = 0;
113 #endif
114  mStatus = kIOOpen;
115 }
116 
117 // Start PA IO
118 
119 void PAIO::start() throw(CException) {
120  PaError err;
121  if (mStatus == kIORunning) // already running
122  return;
123  if (mStatus != kIOOpen) { // wrong state
124  logMsg(kLogError, "Error starting PortAudio in state %d\n", mStatus);
125  return;
126  }
127 //#ifdef CSL_DEBUG
128  logMsg("PAIO::start");
129 //#endif
130  err = Pa_StartStream(mStream);
131  if (err != paNoError)
132  handleError(err);
134 }
135 
136 // Stop
137 
138 void PAIO::stop() throw(CException) {
139  PaError err;
140  if (mStatus != kIORunning) {
141  logMsg(kLogError, "Error stopping PortAudio in state %d\n", mStatus);
142  return;
143  }
144 //#ifdef CSL_DEBUG
145  logMsg("PAIO::stop");
146 //#endif
147  err = Pa_StopStream(mStream);
148  if (err != paNoError)
149  handleError(err);
150  mStatus = kIOOpen;
151 }
152 
153 // Close
154 
155 void PAIO::close() throw(CException) {
156  PaError err;
157  if (mStatus != kIOOpen) {
158  logMsg(kLogError, "Error closing PortAudio in state %d\n", mStatus);
159  return;
160  }
161 //#ifdef CSL_DEBUG
162  logMsg("PAIO::close");
163 //#endif
164  err = Pa_CloseStream(mStream);
165  if (err != paNoError)
166  return handleError(err);
171  Pa_Terminate();
172  mStatus = kIOInit;
173 }
174 
175 // test the IO's graph
176 
177 void PAIO::test() throw(CException) {
179  outBuffer.allocateBuffers();
180 #ifdef CSL_DEBUG
181  logMsg("PAIO::test");
182 #endif
183  if (mGraph != 0) {
184  try {
185  mGraph->nextBuffer(outBuffer);
186  } catch (CException ex) { // handler: log error and play silence
187  logMsg(kLogError, "An error occured in the CSL nextBuffer method: %s\n", ex.mMessage.c_str());
188  throw ex; // swallow the error
189  }
190  }
191 }
192 
193 // Protected init method does all the set up and device allocation
194 
195 void PAIO::initialize(unsigned sr, unsigned bs, int is, int os, unsigned ic, unsigned oc) {
196  const PaDeviceInfo *pdi;
197  IODevice * devPtr;
198  // set the global frame rate and block size
199 //#ifdef CSL_DEBUG
200  logMsg("PAIO::init");
201 //#endif
202  if (sr != CGestalt::frameRate())
204  if (bs != CGestalt::blockSize())
206  // set the global # IO channels
207  if (ic != CGestalt::numInChannels())
209  mNumInChannels = ic;
210  if (oc != CGestalt::numOutChannels())
212  mNumOutChannels = oc;
213 
214  if (is < 0)
215  is = (int)Pa_GetDefaultInputDevice();
216  if (os < 0)
217  os = (int)Pa_GetDefaultOutputDevice();
218 
219  mChannelMap = new unsigned[mNumOutChannels]; // Allocate memory for the channel map
220 
221  for(unsigned i = 0; i < mNumOutChannels; i++) // initialize mapping all channels to themselves.
222  mChannelMap[i] = i;
223 
224  mInputBuffer.setSize(ic, bs); // set receiver's buffers
225  mOutputBuffer.setSize(oc, bs);
226 
227  mNumRealInChannels = 0;
229  PaDeviceIndex numDevices = Pa_GetDeviceCount(); // count the PA devices
230  if (numDevices < 0 )
231  logMsg(kLogFatal, "Pa_CountDevices returned 0x%x\n", numDevices);
232  // iterate over the devices, adding PADevices to the mDevices vector
233  for (int i = 0; i < numDevices; i++) {
234  pdi = Pa_GetDeviceInfo(i);
235  devPtr = new IODevice(pdi->name, i,
236  pdi->maxInputChannels, pdi->maxOutputChannels,
237  (i == (int)Pa_GetDefaultInputDevice()), (i == (int)Pa_GetDefaultOutputDevice()));
238  devPtr->mFrameRates.push_back(pdi->defaultSampleRate); // V19 mod
239  mDevices.push_back(devPtr);
240  mNumRealInChannels += pdi->maxInputChannels;
241  mNumRealOutChannels += pdi->maxOutputChannels;
242  }
243 
244  // set the receiver's state variables
245  if (ic == 0) { // Port Audio can't open a device with 0 channels
246  mInDev = paNoDevice; // In such case, "No device" has to be specified.
247  mInputParameters = NULL;
248  } else {
249  mInDev = is;
250  // setup input/output params. portaudio V19 change
251  mInputParameters = (PaStreamParameters*)malloc(sizeof(PaStreamParameters));
253  mInputParameters->device = mInDev;
254  mInputParameters->sampleFormat = paFloat32;
255  mInputParameters->suggestedLatency = (PaTime) 0;
256  mInputParameters->hostApiSpecificStreamInfo = NULL;
257  }
258  if (oc == 0) { // Port Audio can't open a device with 0 channels
259  mOutDev = paNoDevice; // In such case, "No device" has to be specified.
260  mOutputParameters = NULL;
261  } else {
262  mOutDev = os;
263  mOutputParameters = (PaStreamParameters*)malloc(sizeof(PaStreamParameters));
265  mOutputParameters->device = mOutDev;
266  mOutputParameters->sampleFormat = paFloat32;
267  mOutputParameters->suggestedLatency = (PaTime) 0;
268  mOutputParameters->hostApiSpecificStreamInfo = NULL;
269  }
270  // print out the device table
271  logMsg("PAIO set-up %d in, %d out", mNumInChannels, mNumOutChannels);
272  mStatus = kIOInit; // set status flag
273 //#ifdef CSL_DEBUG
274  logMsg(" Found %d PortAudio devices: %d in, %d out", numDevices, mNumRealInChannels, mNumRealOutChannels);
275  for (unsigned i = 0; i < mDevices.size(); i++) {
276  mDevices[i]->dump();
277  }
278 //#endif
279 }
void logMsg(const char *format,...)
These are the public logging messages.
Definition: CGestalt.cpp:292
long mTimeSum
for printing run-time statistics
Definition: CSL_Core.h:797
unsigned mNumFrames
num frames used in each buffer
Definition: CSL_Core.h:113
#define csl_min(a, b)
bool mAreBuffersAllocated
are the buffers allocated?
Definition: CSL_Core.h:120
AdditiveInstrument.h – Sum-of-sines synthesis instrument class.
Definition: Accessor.h:17
void handleError(PaError result)
print the error message
Definition: PAIO.cpp:69
PaStream * mStream
the PortAudio stream we play out/get data from
Definition: PAIO.h:35
void pullInput(Buffer &outBuffer, SampleBuffer out=0)
get a buffer from the CSL graph
Definition: CSL_Core.cpp:1425
void start()
start the callbacks
Definition: PAIO.cpp:119
void test()
test the IO's graph
Definition: PAIO.cpp:177
static unsigned numOutChannels()
default number of output channels
Definition: CGestalt.cpp:59
PaDeviceIndex mInDev
Definition: PAIO.h:41
void stop()
stop the callbacks
Definition: PAIO.cpp:138
IODeviceVector mDevices
Definition: PAIO.h:42
~PAIO()
Destructor.
Definition: PAIO.cpp:25
PaDeviceIndex mOutDev
IO device numbers.
Definition: PAIO.h:41
static void setNumOutChannels(unsigned numChannels)
Definition: CGestalt.cpp:94
virtual void nextBuffer(Buffer &outputBuffer)
get a buffer of Frames – this is the core CSL "pull" function; the given buffer can be written into...
Definition: CSL_Core.cpp:726
void freeBuffers()
fcn to free them
Definition: CSL_Core.cpp:141
static void setNumInChannels(unsigned numChannels)
Definition: CGestalt.cpp:93
void setSize(unsigned numChannels, unsigned numFrames)
Definition: CSL_Core.cpp:75
UnitGenerator * mGraph
the root of my client DSP graph, often a mixer or panner
Definition: CSL_Core.h:777
PaStreamParameters * mOutputParameters
Definition: PAIO.h:39
static unsigned blockSize()
the default block size
Definition: CGestalt.cpp:57
float sample
(could be changed to int, or double)
Definition: CSL_Types.h:191
void open()
open the IO
Definition: PAIO.cpp:79
IO – the abstract I/O scheduling class; subclasses interface to specific I/O APIs.
Definition: CSL_Core.h:752
static unsigned frameRate()
default frame rate
Definition: CGestalt.cpp:51
static void setBlockSize(unsigned blockSize)
Definition: CGestalt.cpp:92
static unsigned numInChannels()
default number of input channels
Definition: CGestalt.cpp:58
long mThisSec
Definition: CSL_Core.h:797
static int pa_callback(const void *inputPointer, void *outputPointer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *outTime, PaStreamCallbackFlags statusFlags, void *userData)
Definition: PAIO.cpp:41
static void setFrameRate(unsigned frameRate)
Definition: CGestalt.cpp:81
unsigned mNumFramesPlayed
counter of frames I've played
Definition: CSL_Core.h:784
vector< float > mFrameRates
the vector of frame rates I support
Definition: CSL_Core.h:826
unsigned * mChannelMap
the output channel remapping array
Definition: CSL_Core.h:782
unsigned mNumOutChannels
outputs
Definition: CSL_Core.h:788
IO Error.
IO_Status mStatus
status flag
Definition: CSL_Core.h:791
unsigned mNumRealOutChannels
physical outputs
Definition: CSL_Core.h:790
The PortAudio IO class.
Definition: PAIO.h:21
Buffer – the multi-channel sample buffer class (passed around between generators and IO guys)...
Definition: CSL_Core.h:106
void close()
close the IO
Definition: PAIO.cpp:155
Buffer mOutputBuffer
the output buffer I use (passed to nextBuffer calls)
Definition: CSL_Core.h:779
unsigned mNumRealInChannels
physical inputs
Definition: CSL_Core.h:789
Buffer mInputBuffer
the most recent input buffer (if it's turned on)
Definition: CSL_Core.h:778
unsigned mNumInChannels
inputs
Definition: CSL_Core.h:787
PAIO(unsigned s_rate=CSL_mFrameRate, unsigned b_size=CSL_mBlockSize, int in_device=-1, int out_device=-1, unsigned in_chans=0, unsigned out_chans=2)
Definition: PAIO.cpp:18
void allocateBuffers()
fcn to malloc storage buffers
Definition: CSL_Core.cpp:122
SampleBuffer mInputPointer
the buffer for holding the sound card input (if open)
Definition: CSL_Core.h:781
long mTimeVals
Definition: CSL_Core.h:797
IO Device class – a holder for a sound interface with name, id, # IO channels, etc.
Definition: CSL_Core.h:815
PaStreamParameters * mInputParameters
PA IO stream parameters.
Definition: PAIO.h:38
void initialize(unsigned sr, unsigned bs, int is, int os, unsigned ic, unsigned oc)
Actually initialize PortAudio driver.
Definition: PAIO.cpp:195
Base class of CSL exceptions (written upper-case). Has a string message.