~ubuntu-branches/ubuntu/breezy/muse/breezy

« back to all changes in this revision

Viewing changes to synti/stklib/RtAudio.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Kobras
  • Date: 2004-02-07 15:18:22 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040207151822-es27xxkzbcxkebjm
Tags: 0.6.3-1
* New upstream version.
* Added patches:
  + [10_alsa_init_fix] New, from upstream CVS.
    Initialize direction variable when setting Alsa parameters.
  + [10_canvas_translation_fix] New, from upstream CVS.
    Do not translate tooltips twice in canvas popup.
  + [10_checkbox_fix] New, from upstream CVS.
    Use proper set/test methods on metronome checkboxes.
  + [10_html_doc_cleanup] New.
    Fix links and HTML errors in documentation.
  + [20_allow_system_timer] New.
    The new upstream version fails by default if the real-time clock
    could not be accessed (usually the case when not running suid-root).
    This patch reverts the old behaviour of falling back to the more
    inaccurate system timer.
* Updated patches:
  + [11_PIC_fixes_fixup] Rediffed.
* Removed patches:
  + [20_no_atomic_asm] Merged upstream.
* debian/compat: Splice out debhelper compatibility level from rules file.
* debian/control: Build-depend on latest jack release by default.
  Closes: #228788
* debian/control: Bump standards version.
* debian/control: Use auto-generated debconf dependency via misc:Depends.
* debian/control: Minor tweaks to the long description.
* debian/control: Tighten fluidsynth build dependency to sane version.
* debian/muse.doc-base: New. Register HTML documentation with doc-base.
* debian/templates: Tiny rewording, and typo fix.
* debian/templates, debian/po/*: Switch to po-debconf for translations.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/******************************************/
2
 
/*
3
 
  RtAudio.cpp
4
 
  Realtime Sound I/O Object for STK
5
 
  by Gary P. Scavone, 1998-2000.
6
 
 
7
 
  The sound output sections of this object
8
 
  were originally based in part on code by
9
 
  Doug Scott (SGI), Tim Stilson (Linux),
10
 
  and R. Marsanyi (DirectSound).  The latest
11
 
  DirectSound code was re-written by Dave
12
 
  Chisholm at CCRMA.
13
 
 
14
 
  This object provides a standard API
15
 
  across all platforms for STK realtime
16
 
  audio input/output.  Multi-channel
17
 
  support is supported when provided by
18
 
  the soundcard.
19
 
 
20
 
  Only 16-bit integer input/output
21
 
  routines are written for the moment
22
 
  though it would be simple to overload
23
 
  the methods for other data types.
24
 
*/
25
 
/******************************************/
26
 
 
27
 
#include "RtAudio.h"
28
 
 
29
 
#if (defined(__STK_REALTIME_) && defined(__OS_IRIX_))
30
 
 
31
 
#define NUM_FRAGMENTS 4
32
 
 
33
 
RtAudio :: RtAudio(int channels, MY_FLOAT srate, const char *mode, int device)
34
 
{
35
 
  ALconfig audio_port_config;
36
 
  long queue_size;
37
 
  ALpv pvs[2];
38
 
  char msg[256];
39
 
 
40
 
  // initialize resources
41
 
  audio_port_out = 0;
42
 
  audio_port_in = 0;
43
 
 
44
 
  // check mode string
45
 
  if (strcmp(mode,"play") && strcmp(mode,"record") && strcmp(mode,"duplex")) {
46
 
    sprintf(msg, "RtAudio: constructor parameter 'mode' must be play, record, or duplex only.\n");
47
 
    throw StkError(msg, StkError::FUNCTION_SYNTAX);
48
 
  }
49
 
 
50
 
  /* Create ALconfig structure */
51
 
  audio_port_config = alNewConfig();
52
 
  if (!audio_port_config) {
53
 
    sprintf(msg,"RtAudio: Couldn't create SGI ALconfig: %s\n",
54
 
            alGetErrorString(oserror()));
55
 
    throw StkError(msg, StkError::SOUNDCARD_CONTROL);
56
 
  }
57
 
 
58
 
  /* Configure channels */
59
 
  stk_chans = channels;
60
 
  if(alSetChannels(audio_port_config, stk_chans) < 0) {
61
 
    sprintf(msg,"RtAudio: SGI error configuring %d channels: %s\n",
62
 
            channels, alGetErrorString(oserror()));
63
 
    throw StkError(msg, StkError::SOUNDCARD_CAPS);
64
 
  }
65
 
 
66
 
  /* Size the output queue */
67
 
  queue_size = RT_BUFFER_SIZE * NUM_FRAGMENTS; // in sample frames
68
 
  if(alSetQueueSize(audio_port_config, queue_size) < 0) {
69
 
    sprintf(msg,"RtAudio: SGI error configuring output queue size: %s\n",
70
 
            alGetErrorString(oserror()));
71
 
    throw StkError(msg, StkError::SOUNDCARD_CONTROL);
72
 
  }
73
 
 
74
 
  if ( !strcmp(mode,"play") || !strcmp(mode,"duplex") ) { // playback only
75
 
 
76
 
    /* Open the output audio port */
77
 
    audio_port_out = alOpenPort("STK output port", "w", audio_port_config);
78
 
    if(!audio_port_out) {
79
 
      sprintf(msg,"RtAudio: SGI error ... cannot initialize output audio port: %s\n",
80
 
              alGetErrorString(oserror()));
81
 
      throw StkError(msg, StkError::SOUNDCARD_CONTROL);
82
 
    }
83
 
 
84
 
    /* Set sample rate parameters */
85
 
    pvs[0].param = AL_MASTER_CLOCK;
86
 
    pvs[0].value.i = AL_CRYSTAL_MCLK_TYPE;
87
 
    pvs[1].param = AL_RATE;
88
 
    pvs[1].value.ll = alDoubleToFixed((double)srate);
89
 
    if (alSetParams(AL_DEFAULT_OUTPUT, pvs, 2) < 0) { /* set output SR */
90
 
      sprintf(msg,"RtAudio: SGI error ... cannot set sample rate parameters: %s\n",
91
 
              alGetErrorString(oserror()));
92
 
      throw StkError(msg, StkError::SOUNDCARD_CONTROL);
93
 
    }
94
 
 
95
 
    /* Tell port to accept refill at buffers - 1 */
96
 
    alSetFillPoint(audio_port_out, RT_BUFFER_SIZE * (NUM_FRAGMENTS - 1));
97
 
  }
98
 
  else if ( !strcmp(mode,"record")  || !strcmp(mode,"duplex") ) { // record only
99
 
 
100
 
    /* Open the input audio port */
101
 
    audio_port_in = alOpenPort("STK input port", "r", audio_port_config);
102
 
    if(!audio_port_in) {
103
 
      sprintf(msg,"RtAudio: SGI error ... cannot initialize input audio port: %s\n",
104
 
              alGetErrorString(oserror()));
105
 
      throw StkError(msg, StkError::SOUNDCARD_CONTROL);
106
 
    }
107
 
 
108
 
    /* Set sample rate parameters */
109
 
    pvs[0].param = AL_MASTER_CLOCK;
110
 
    pvs[0].value.i = AL_CRYSTAL_MCLK_TYPE;
111
 
    pvs[1].param = AL_RATE;
112
 
    pvs[1].value.ll = alDoubleToFixed((double)srate);
113
 
    if (alSetParams(AL_DEFAULT_INPUT, pvs, 2) < 0) { /* set input SR */
114
 
      sprintf(msg,"RtAudio: SGI error ... cannot set sample rate parameters: %s\n",
115
 
              alGetErrorString(oserror()));
116
 
      throw StkError(msg, StkError::SOUNDCARD_CONTROL);
117
 
    }
118
 
 
119
 
    /* tell port to accept refill at buffers - 1 */
120
 
    alSetFillPoint(audio_port_in, 0);  
121
 
  }
122
 
 
123
 
  alFreeConfig(audio_port_config);
124
 
  audio_port_config = 0;
125
 
}
126
 
 
127
 
RtAudio :: ~RtAudio()
128
 
{
129
 
  if (audio_port_out) alClosePort(audio_port_out);
130
 
  audio_port_out=0;
131
 
 
132
 
  if (audio_port_in) alClosePort(audio_port_in);
133
 
  audio_port_in=0;
134
 
}
135
 
 
136
 
int RtAudio :: playBuffer(INT16 *buf, int bufsize)
137
 
{
138
 
    alWriteFrames(audio_port_out, buf, bufsize/stk_chans);
139
 
    return 0;
140
 
}
141
 
 
142
 
int RtAudio :: recordBuffer(INT16 *buf, int bufsize)
143
 
{
144
 
    alReadFrames(audio_port_in, buf, bufsize/stk_chans);
145
 
    return 0;
146
 
}
147
 
 
148
 
 
149
 
/* Linux ALSA Sound API here */
150
 
 
151
 
#elif (defined(__STK_REALTIME_) && defined(__ALSA_API_))
152
 
 
153
 
RtAudio :: RtAudio(int channels, MY_FLOAT srate, const char *mode, int device)
154
 
{
155
 
  int card, dev, err, nChoices = 0;
156
 
  int data_format, default_card;
157
 
  unsigned int mask;
158
 
  snd_pcm_channel_params_t params;
159
 
        struct snd_ctl_hw_info info;
160
 
        snd_pcm_info_t pcminfo;
161
 
        snd_pcm_channel_info_t chninfo;
162
 
  snd_pcm_channel_setup_t setup;
163
 
  snd_ctl_t *chandle;
164
 
  bool print_list = FALSE;
165
 
  char msg[256];
166
 
 
167
 
  // check mode string
168
 
  if (strcmp(mode,"play") && strcmp(mode,"record") && strcmp(mode,"duplex")) {
169
 
    sprintf(msg, "RtAudio: constructor parameter 'mode' must be play, record, or duplex only.\n");
170
 
    throw StkError(msg, StkError::FUNCTION_SYNTAX);
171
 
  }
172
 
 
173
 
  if (channels < 1) {
174
 
    sprintf(msg, "RtAudio: number of channels = %d not supported!\n", channels);
175
 
    throw StkError(msg, StkError::FUNCTION_SYNTAX);
176
 
  }
177
 
 
178
 
  // check to make sure we have card(s) and/or ALSA drivers available
179
 
  mask = snd_cards_mask();
180
 
  if (!mask) {
181
 
    sprintf(msg, "RtAudio: no ALSA soundcards reported available.\n");
182
 
    throw StkError(msg, StkError::SOUNDCARD_NOT_FOUND);
183
 
  }
184
 
 
185
 
  ohandle = 0;
186
 
  ihandle = 0;
187
 
  outbuf = 0;
188
 
  inbuf = 0;
189
 
 
190
 
  if (!strcmp(mode, "play"))
191
 
    direction = SND_PCM_INFO_PLAYBACK;
192
 
  else if (!strcmp(mode, "record"))
193
 
    direction = SND_PCM_INFO_CAPTURE;
194
 
  else
195
 
    direction = SND_PCM_INFO_DUPLEX;
196
 
 
197
 
  // The proliferation of multichannel soundcards carries with it a wide range
198
 
  // of special requirements. Often, a card will need to be fed a special data
199
 
  // or channel format.  So, we need to probe the available card(s) to determine
200
 
  // these requirements.  If no device is specified as a constructor argument,
201
 
  // I'll start probing at the default card number (which can be set with the
202
 
  // ALSA_CARD environment variable) and then any other existing cards until I
203
 
  // find a device that will meet our needs (or not).  If a specified device 
204
 
  // does not exist or will not work, I'll print a list of available audio
205
 
  // devices and let the user select one.
206
 
  if (device == -1) {
207
 
    default_card = snd_defaults_pcm_card();
208
 
  }
209
 
  else { // check device specified as argument
210
 
    if (!(mask & (1<<device))) {
211
 
      default_card = 0;
212
 
      print_list = TRUE;
213
 
      printf("\n");
214
 
    }
215
 
    else {
216
 
      default_card = device;
217
 
    }
218
 
  }
219
 
 
220
 
  card = default_card;
221
 
  while (card<SND_CARDS) {
222
 
    if (mask & (1<<card)) {
223
 
      if ((err = snd_ctl_open(&chandle, card)) < 0) {
224
 
        fprintf(stderr,"RtAudio: ALSA error on control open (%d): %s\n",
225
 
                card, snd_strerror(err));
226
 
        continue;
227
 
      }
228
 
      if ((err = snd_ctl_hw_info(chandle, &info)) < 0) {
229
 
        fprintf(stderr,"RtAudio: ALSA error on control hardware info (%d): %s\n",
230
 
                card, snd_strerror(err));
231
 
        snd_ctl_close(chandle);
232
 
        continue;
233
 
      }
234
 
      for (dev=0; dev<(int)info.pcmdevs; dev++) {
235
 
        /* get information for each device */
236
 
        if ((err = snd_ctl_pcm_info(chandle, dev, &pcminfo)) < 0) {
237
 
          fprintf(stderr,"RtAudio: ALSA error on control PCM info (%d): %s\n",
238
 
                  card, snd_strerror(err));
239
 
          continue;
240
 
        }
241
 
        if (pcminfo.flags & direction) { // a device exists for the given mode
242
 
          if ( (direction == SND_PCM_INFO_PLAYBACK) ||
243
 
               (direction == SND_PCM_INFO_DUPLEX) ) {
244
 
            if ((err=snd_pcm_open(&ohandle, card, dev, SND_PCM_OPEN_PLAYBACK))!=0) {
245
 
              fprintf(stderr,"RtAudio: ALSA PCM playback open error (%d): %s\n",
246
 
                      card, snd_strerror(err));
247
 
              continue;
248
 
            }
249
 
            // we have a device open ... get the channel information (direction specific)
250
 
            memset(&chninfo, 0, sizeof(chninfo));
251
 
            chninfo.channel = SND_PCM_CHANNEL_PLAYBACK;
252
 
            if ((err = snd_pcm_channel_info(ohandle, &chninfo)) < 0) {
253
 
              fprintf(stderr,"RtAudio: ALSA error on PCM playback info (%d): %s\n",
254
 
                      card, snd_strerror(err));
255
 
              snd_pcm_close(ohandle);
256
 
              continue;
257
 
            }
258
 
            // check number of channels and sample rate
259
 
            if ((chninfo.max_voices >= channels) && (chninfo.min_rate <= (int)srate)
260
 
                && (chninfo.max_rate >= (int)srate)) { // this card will work 
261
 
              dev_ochans = (channels >= chninfo.min_voices) ? channels : chninfo.min_voices;
262
 
              if (direction == SND_PCM_INFO_PLAYBACK) {
263
 
                // playback only ... jump out of loop and proceed
264
 
                // duplex case continue to capture check
265
 
                if (print_list) {
266
 
                  printf("Audio Card %d, Device %d: %s\n", card, dev, info.name);
267
 
                  nChoices++;
268
 
                  snd_pcm_close(ohandle);
269
 
                  continue;
270
 
                }
271
 
                goto have_good_device;
272
 
              }
273
 
            } else { // this device won't work
274
 
              snd_pcm_close(ohandle);
275
 
              continue;
276
 
            }
277
 
          }
278
 
          if ( (direction == SND_PCM_INFO_CAPTURE) ||
279
 
              (direction == SND_PCM_INFO_DUPLEX) ) {
280
 
            if ((err=snd_pcm_open(&ihandle, card, dev, SND_PCM_OPEN_CAPTURE))!=0) {
281
 
              fprintf(stderr,"RtAudio: ALSA PCM capture open error (%d): %s\n",
282
 
                      card, snd_strerror(err));
283
 
              if (direction == SND_PCM_INFO_DUPLEX)
284
 
                snd_pcm_close(ohandle);
285
 
              continue;
286
 
            }
287
 
            // we have a device open ... get the channel information (direction specific)
288
 
            memset(&chninfo, 0, sizeof(chninfo));
289
 
            chninfo.channel = SND_PCM_CHANNEL_CAPTURE;
290
 
            if ((err = snd_pcm_channel_info(ihandle, &chninfo)) < 0) {
291
 
              fprintf(stderr,"RtAudio: ALSA error on PCM capture info (%d): %s\n",
292
 
                      card, snd_strerror(err));
293
 
              snd_pcm_close(ihandle);
294
 
              if (direction == SND_PCM_INFO_DUPLEX)
295
 
                snd_pcm_close(ohandle);
296
 
              continue;
297
 
            }
298
 
            // check number of channels and sample rate
299
 
            if ((chninfo.max_voices >= channels) && (chninfo.min_rate <= (int)srate)
300
 
                && (chninfo.max_rate >= (int)srate)) { // this card will work 
301
 
              dev_ichans = (channels >= chninfo.min_voices) ? channels : chninfo.min_voices;
302
 
              if (print_list) {
303
 
                printf("Audio Card %d, Device %d: %s\n", card, dev, info.name);
304
 
                nChoices++;
305
 
                snd_pcm_close(ihandle);
306
 
                if (direction == SND_PCM_INFO_DUPLEX)
307
 
                  snd_pcm_close(ohandle);
308
 
                continue;
309
 
              }
310
 
              goto have_good_device; // jump out of loop and proceed
311
 
            } else { // this device won't work
312
 
              snd_pcm_close(ihandle);
313
 
              if (direction == SND_PCM_INFO_DUPLEX)
314
 
                snd_pcm_close(ohandle);
315
 
            }
316
 
          }
317
 
        }
318
 
      }
319
 
    }
320
 
    if (default_card == 0) card++;
321
 
    else { // default card != 0, now start with card 0 and keep searching
322
 
      if (card == default_card) card = 0; // first time only
323
 
      else {
324
 
        card++;
325
 
        if (card == default_card) card++; // skip over default card
326
 
      }
327
 
    }
328
 
  }
329
 
 
330
 
  if (print_list && nChoices) {
331
 
    char choice[16];
332
 
    printf("\nType an audio card number from above: ");
333
 
    fgets(choice, 16, stdin);
334
 
    card = atoi(choice);
335
 
    printf("Select a device for the same card: ");
336
 
    fgets(choice, 16, stdin);
337
 
    printf("\n");
338
 
    dev = atoi(choice);
339
 
    // re-open the device(s)
340
 
    if ( (direction == SND_PCM_INFO_PLAYBACK) ||
341
 
         (direction == SND_PCM_INFO_DUPLEX) ) {
342
 
      if ((err=snd_pcm_open(&ohandle, card, dev, SND_PCM_OPEN_PLAYBACK))!=0) {
343
 
        sprintf(msg, "RtAudio: ALSA PCM playback open error (%d:%d): %s\n",
344
 
                card, dev, snd_strerror(err));
345
 
        throw StkError(msg, StkError::SOUNDCARD_CAPS);
346
 
      }
347
 
    }
348
 
    if ( (direction == SND_PCM_INFO_CAPTURE) ||
349
 
        (direction == SND_PCM_INFO_DUPLEX) ) {
350
 
      if ((err=snd_pcm_open(&ihandle, card, dev, SND_PCM_OPEN_CAPTURE))!=0) {
351
 
        sprintf(msg, "RtAudio: ALSA PCM capture open error (%d:%d): %s\n",
352
 
                card, dev, snd_strerror(err));
353
 
        if (direction == SND_PCM_INFO_DUPLEX)
354
 
          snd_pcm_close(ohandle);
355
 
        throw StkError(msg, StkError::SOUNDCARD_CAPS);
356
 
      }
357
 
    }
358
 
    goto have_good_device;
359
 
  }
360
 
 
361
 
  // if we got here, no devices were found to meet the requested functionality
362
 
  sprintf(msg, "RtAudio: no ALSA device found for requested service!\n");
363
 
  throw StkError(msg, StkError::SOUNDCARD_CAPS);
364
 
 
365
 
 have_good_device: // the current value of card and dev are what we will use
366
 
 
367
 
  // The hardware sometimes requires more channels of data than we necessarily
368
 
  // want to work with in STK.  In fact, sometimes the hardware requires a
369
 
  // different number of output channels than input channels.  Thus, we need to
370
 
  // remember all values.
371
 
  stk_chans = channels;
372
 
 
373
 
  // If duplex mode, the format will come from the capture device info.  I'm assuming
374
 
  // that both directions will have the same data format.
375
 
  if (chninfo.formats & SND_PCM_FMT_S16_LE) {
376
 
    data_format = SND_PCM_SFMT_S16_LE;
377
 
    bytes_per_sample = 2;
378
 
  }
379
 
  else if (chninfo.formats & SND_PCM_FMT_S32_LE) {
380
 
    data_format = SND_PCM_SFMT_S32_LE;
381
 
    bytes_per_sample = 4;
382
 
  }
383
 
  else {
384
 
    sprintf(msg, "RtAudio: only ALSA S16_LE and S32_LE data formats at the moment!\n");
385
 
    throw StkError(msg);
386
 
  }
387
 
 
388
 
  // global channel parameters (not direction specific)
389
 
  memset(&params, 0, sizeof(params));
390
 
  params.mode=SND_PCM_MODE_BLOCK;
391
 
  params.stop_mode=SND_PCM_STOP_ROLLOVER; 
392
 
  params.buf.block.frags_max=3;
393
 
  params.buf.block.frags_min=1;
394
 
  params.format.interleave=1;
395
 
  params.format.format=data_format; // this should depend on the card, unless we use the plugin
396
 
  params.format.rate=(int)srate;
397
 
 
398
 
  // We need to set the channel parameters, flush, and prepare for each direction of use.
399
 
  // Thus, if doing duplex, we need to do these for both directions.  First do it for
400
 
  // playback and duplex.
401
 
  if ((direction == SND_PCM_INFO_PLAYBACK) || (direction == SND_PCM_INFO_DUPLEX)) {
402
 
    params.channel=SND_PCM_CHANNEL_PLAYBACK;
403
 
    params.start_mode=SND_PCM_START_FULL;
404
 
    params.format.voices=dev_ochans;
405
 
    // The fragsize is in bytes per frame = RT_BUFFER_SIZE * dev_chans * bytes_per_sample.
406
 
    // ALSA requires that all reads and write be done in fragsize increments.
407
 
    ofragsize = (int) (dev_ochans * bytes_per_sample * RT_BUFFER_SIZE);
408
 
    params.buf.block.frag_size=ofragsize;
409
 
    if ((err=snd_pcm_channel_params(ohandle, &params))!=0) {
410
 
      // try to close what was opened!
411
 
      snd_pcm_close(ohandle);
412
 
      sprintf(msg, "RtAudio: Cannot set ALSA audio device parameters for playback: %s\n",
413
 
              snd_strerror(err));
414
 
      throw StkError(msg, StkError::SOUNDCARD_CONTROL);
415
 
    }
416
 
 
417
 
    // now check the actual values, because sometimes they are not what we requested
418
 
    memset(&setup, 0, sizeof(setup));
419
 
    setup.channel=SND_PCM_CHANNEL_PLAYBACK;
420
 
    if ((err=snd_pcm_channel_setup(ohandle, &setup))<0) {
421
 
      snd_pcm_close(ohandle);
422
 
      sprintf(msg, "RtAudio: Cannot get ALSA audio device setup info: %s\n",
423
 
              snd_strerror(err));
424
 
      throw StkError(msg, StkError::SOUNDCARD_CONTROL);
425
 
    } else {
426
 
      if (setup.format.rate != (int) srate) {
427
 
        // try to close what was opened!
428
 
        snd_pcm_close(ohandle);
429
 
        sprintf(msg, "RtAudio: Soundcard doesn't seem to support requested sample rate: %.2f!\n",
430
 
                srate);
431
 
        throw StkError(msg, StkError::SOUNDCARD_CAPS);
432
 
      }
433
 
      if (setup.buf.block.frag_size != ofragsize) ofragsize = setup.buf.block.frag_size;
434
 
    }
435
 
 
436
 
    // allocate and clear the output buffer
437
 
    outbuf = (unsigned char*) new char[ofragsize];
438
 
    memset(outbuf, 0, ofragsize);
439
 
 
440
 
    // I'm not sure what this does and I'm not sure it actually helps.
441
 
    if ((err=snd_pcm_playback_flush(ohandle))!=0) {
442
 
      // try to free and close what was opened!
443
 
      snd_pcm_close(ohandle);
444
 
      if (outbuf) delete [] outbuf;
445
 
      sprintf(msg, "RtAudio: Cannot flush ALSA channel buffers for playback!\n");
446
 
      throw StkError(msg, StkError::SOUNDCARD_CONTROL);
447
 
    }
448
 
 
449
 
    if ((err=snd_pcm_channel_prepare(ohandle, params.channel))!=0) {
450
 
      // try to close what was opened!
451
 
      snd_pcm_close(ohandle);
452
 
      if (outbuf) delete [] outbuf;
453
 
      sprintf(msg, "RtAudio: Cannot prepare ALSA channel for playback!\n");
454
 
      throw StkError(msg, StkError::SOUNDCARD_CONTROL);
455
 
    }
456
 
  }
457
 
 
458
 
  // Now do it for capture and duplex.
459
 
  if ((direction == SND_PCM_INFO_CAPTURE) || (direction == SND_PCM_INFO_DUPLEX)) {
460
 
    params.channel=SND_PCM_CHANNEL_CAPTURE;
461
 
    params.start_mode=SND_PCM_START_DATA;
462
 
    params.format.voices=dev_ichans;
463
 
    // The fragsize is in bytes per frame = RT_BUFFER_SIZE * dev_chans * bytes_per_sample.
464
 
    // ALSA requires that all reads and write be done in fragsize increments.
465
 
    ifragsize = (int) (dev_ichans * bytes_per_sample * RT_BUFFER_SIZE);
466
 
    params.buf.block.frag_size=ifragsize;
467
 
    if ((err=snd_pcm_channel_params(ihandle, &params))!=0) {
468
 
      // try to close what was opened!
469
 
      snd_pcm_close(ihandle);
470
 
      if (direction == SND_PCM_INFO_DUPLEX) {
471
 
        if (outbuf) delete [] outbuf;
472
 
        snd_pcm_close(ohandle);
473
 
      }
474
 
      sprintf(msg, "RtAudio: Cannot set ALSA audio device parameters for capture: %s\n",
475
 
              snd_strerror(err));
476
 
      throw StkError(msg, StkError::SOUNDCARD_CONTROL);
477
 
    }
478
 
 
479
 
    // now check the actual values, because sometimes they are not what we requested
480
 
    memset(&setup, 0, sizeof(setup));
481
 
    setup.channel=SND_PCM_CHANNEL_CAPTURE;
482
 
    if ((err=snd_pcm_channel_setup(ihandle, &setup))<0) {
483
 
      // try to close what was opened!
484
 
      snd_pcm_close(ihandle);
485
 
      if (direction == SND_PCM_INFO_DUPLEX) {
486
 
        if (outbuf) delete [] outbuf;
487
 
        snd_pcm_close(ohandle);
488
 
      }
489
 
      sprintf(msg, "RtAudio: Cannot get ALSA audio device setup info: %s\n",
490
 
              snd_strerror(err));
491
 
      throw StkError(msg, StkError::SOUNDCARD_CONTROL);
492
 
    } else {
493
 
      if (setup.format.rate != (int) srate) {
494
 
        // try to close what was opened!
495
 
        snd_pcm_close(ihandle);
496
 
        if (direction == SND_PCM_INFO_DUPLEX) {
497
 
          if (outbuf) delete [] outbuf;
498
 
          snd_pcm_close(ohandle);
499
 
        }
500
 
        sprintf(msg, "RtAudio: Soundcard doesn't seem to support requested sample rate: %.2f!\n",
501
 
                srate);
502
 
        throw StkError(msg, StkError::SOUNDCARD_CAPS);
503
 
      }
504
 
 
505
 
      if (setup.buf.block.frag_size != ifragsize) ifragsize = setup.buf.block.frag_size;
506
 
    }
507
 
 
508
 
    // allocate and clear the input buffer
509
 
    inbuf = (unsigned char*) new char[ifragsize];
510
 
    memset(inbuf, 0, ifragsize);
511
 
 
512
 
    if ((err=snd_pcm_capture_flush(ihandle))!=0) {
513
 
      // try to close what was opened!
514
 
      snd_pcm_close(ihandle);
515
 
      if (inbuf) delete [] inbuf;
516
 
      if (direction == SND_PCM_INFO_DUPLEX) {
517
 
        if (outbuf) delete [] outbuf;
518
 
        snd_pcm_close(ohandle);
519
 
      }
520
 
      sprintf(msg, "RtAudio: Cannot flush ALSA channel buffers for capture!\n");
521
 
      throw StkError(msg, StkError::SOUNDCARD_CONTROL);
522
 
    }
523
 
 
524
 
    if ((err=snd_pcm_channel_prepare(ihandle, params.channel))!=0) {
525
 
      // try to close what was opened!
526
 
      snd_pcm_close(ihandle);
527
 
      if (inbuf) delete [] inbuf;
528
 
      if (direction == SND_PCM_INFO_DUPLEX) {
529
 
        if (outbuf) delete [] outbuf;
530
 
        snd_pcm_close(ohandle);
531
 
      }
532
 
      sprintf(msg, "RtAudio: Cannot prepare ALSA channel for capture!\n");
533
 
      throw StkError(msg, StkError::SOUNDCARD_CONTROL);
534
 
    }
535
 
  }
536
 
}
537
 
 
538
 
RtAudio :: ~RtAudio()
539
 
{
540
 
  if ((direction == SND_PCM_INFO_PLAYBACK) || (direction == SND_PCM_INFO_DUPLEX)) {
541
 
    snd_pcm_playback_drain(ohandle);
542
 
    snd_pcm_close(ohandle);
543
 
  }
544
 
  if ((direction == SND_PCM_INFO_CAPTURE) || (direction == SND_PCM_INFO_DUPLEX)) {
545
 
    snd_pcm_close(ihandle);
546
 
  }
547
 
  if (outbuf) delete [] outbuf;
548
 
  if (inbuf) delete [] inbuf;
549
 
}
550
 
 
551
 
int RtAudio :: playBuffer(INT16 *buf, int bufsize)
552
 
{
553
 
  // The argument bufsize is the number of audio samples (INT16s) in buf.
554
 
  int err, i;
555
 
  static char msg[256];
556
 
  unsigned char *temp;
557
 
  static int channel = 1;
558
 
  static int counter = 0;
559
 
  static int extra_chans = dev_ochans - stk_chans;
560
 
 
561
 
  // performance optimization occurs when the following conditions are met
562
 
  if ((extra_chans == 0) && (bytes_per_sample == 2) && (bufsize * 2 == ofragsize)) {
563
 
    // we don't need to use outbuf
564
 
    if ((err=snd_pcm_write(ohandle, buf, ofragsize))!=ofragsize) {
565
 
      sprintf(msg, "RtAudio: ALSA audio write error!\n");
566
 
      throw StkError(msg, StkError::SOUNDCARD_CONTROL);
567
 
    }
568
 
  } else {
569
 
    for (i=0; i<bufsize; i++) {
570
 
      // write the i-th sample to outbuf
571
 
      temp = (unsigned char *) &buf[i];
572
 
      // shift data to the two highest bytes of each output sample
573
 
      counter += bytes_per_sample-2;
574
 
      outbuf[counter++] = temp[0];
575
 
      outbuf[counter++] = temp[1];
576
 
      channel++;
577
 
 
578
 
      if (channel > stk_chans) {
579
 
        // because we created outbuf with calloc(), we shouldn't have to write zeros here
580
 
        counter += bytes_per_sample * extra_chans;
581
 
        channel = 1;
582
 
      }
583
 
 
584
 
      if (counter >= ofragsize) {
585
 
        if ((err=snd_pcm_write(ohandle, outbuf, ofragsize))!=ofragsize) {
586
 
          sprintf(msg, "RtAudio: ALSA audio write error!\n");
587
 
          throw StkError(msg, StkError::SOUNDCARD_CONTROL);
588
 
        }
589
 
        counter = 0;
590
 
      }
591
 
    }
592
 
  }
593
 
 
594
 
  return 0;
595
 
}
596
 
 
597
 
int RtAudio :: recordBuffer(INT16 *buf, int bufsize)
598
 
{
599
 
  // The argument bufsize is the number of audio samples (INT16s) in buf.
600
 
  int err, i;
601
 
  static char msg[256];
602
 
  unsigned char *temp;
603
 
  static int channel = 1;
604
 
  static int counter = 0;
605
 
  static int extra_chans = dev_ichans - stk_chans;
606
 
 
607
 
  // performance optimization occurs when the following conditions are met
608
 
  if ((extra_chans == 0) && (bytes_per_sample == 2) && (bufsize * 2 == ifragsize)) {
609
 
    // we don't need to use inbuf
610
 
    if ((err=snd_pcm_read(ihandle, buf, ifragsize))!=ifragsize) {
611
 
      sprintf(msg, "RtAudio: ALSA audio read error!\n");
612
 
      throw StkError(msg, StkError::SOUNDCARD_CONTROL);
613
 
    }
614
 
  } else {
615
 
    for (i=0; i<bufsize; i++) {
616
 
      if (counter == 0) {
617
 
        if ((err=snd_pcm_read(ihandle, inbuf, ifragsize))!=ifragsize) {
618
 
          sprintf(msg, "RtAudio: ALSA audio read error!\n");
619
 
          throw StkError(msg, StkError::SOUNDCARD_CONTROL);
620
 
        }
621
 
      }
622
 
 
623
 
      temp = (unsigned char *) &buf[i];
624
 
      // take data from the two highest bytes of each input sample
625
 
      counter += bytes_per_sample-2;
626
 
      temp[0] = inbuf[counter++];
627
 
      temp[1] = inbuf[counter++];
628
 
      channel++;
629
 
 
630
 
      if (channel > stk_chans) {
631
 
        // just skip over the extra channels
632
 
        counter += bytes_per_sample * extra_chans;
633
 
        channel = 1;
634
 
      }
635
 
      if (counter >= ifragsize) counter = 0;
636
 
    }
637
 
  }
638
 
 
639
 
  return 0;
640
 
}
641
 
 
642
 
 
643
 
/* Linux OSS Sound API here */
644
 
 
645
 
#elif (defined(__STK_REALTIME_) && defined(__OSS_API_))
646
 
 
647
 
// Define the maximum number of dsp devices that we'll attempt
648
 
// to probe before giving up.
649
 
#define MAX_DSP_DEVS 8
650
 
#define DAC_NAME "/dev/dsp"
651
 
// The number of fragments can be made larger than 2 if the sound
652
 
// system performance is poor.
653
 
#define NUM_FRAGMENTS 4
654
 
 
655
 
RtAudio :: RtAudio(int channels, MY_FLOAT srate, const char *mode, int device)
656
 
{
657
 
  char device_name[16];
658
 
  int fragsize;
659
 
  int fragment_size_log;
660
 
  int format;
661
 
  int chans = channels;
662
 
  int speed;
663
 
  int i, nChoices = 0;
664
 
  bool print_list = FALSE;
665
 
  char msg[256];
666
 
 
667
 
  // check mode string
668
 
  if (strcmp(mode,"play") && strcmp(mode,"record") && strcmp(mode,"duplex")) {
669
 
    sprintf(msg, "RtAudio: constructor parameter 'mode' must be play, record, or duplex only.\n");
670
 
    throw StkError(msg, StkError::FUNCTION_SYNTAX);
671
 
  }
672
 
 
673
 
  if (channels < 1) {
674
 
    sprintf(msg, "RtAudio: number of channels = %d not supported!\n", channels);
675
 
    throw StkError(msg, StkError::FUNCTION_SYNTAX);
676
 
  }
677
 
 
678
 
  fragsize = RT_BUFFER_SIZE * channels * 2; // in bytes
679
 
  fragment_size_log = (int)(log10((double)fragsize)/log10(2.0));
680
 
  long temp = ((long) NUM_FRAGMENTS << 16) + fragment_size_log;
681
 
 
682
 
  // /dev/dsp should be a link to the default pcm device under OSS
683
 
  strcpy(device_name, DAC_NAME);
684
 
 
685
 
  // The OSS API doesn't really give us a means for probing the
686
 
  // capabilities of devices.  Thus, we'll just pursue a brute
687
 
  // force method of opening devices until we either find something
688
 
  // that doesn't complain or we have to give up.  We'll start with
689
 
  // the default device, then try /dev/dsp0, /dev/dsp1, etc...
690
 
 
691
 
  if (device != -1) {
692
 
    // start with device specified as argument
693
 
    sprintf(device_name, "%s%d", DAC_NAME, device);
694
 
  }
695
 
 
696
 
  for (i=0; i<=MAX_DSP_DEVS; i++) {
697
 
 
698
 
    // if the default device doesn't work, try some others
699
 
    if (i > 0) sprintf(device_name, "%s%d", DAC_NAME, i-1);
700
 
 
701
 
    if (device != -1 && i == 1) {
702
 
      // the specified device didn't work ... now print other options
703
 
      print_list = TRUE;
704
 
      printf("\n");
705
 
    }
706
 
 
707
 
    if (!strcmp(mode,"play")) { // playback only
708
 
      if ((audio_fd = open(device_name, O_WRONLY, 0)) == -1) {
709
 
        // Open device failed ... either busy or doesn't exist
710
 
        if (errno == EBUSY)
711
 
          fprintf(stderr,"RtAudio: OSS PCM playback device (%s) is busy and cannot be opened.\n",
712
 
                  device_name);
713
 
        continue;
714
 
      }
715
 
    }
716
 
    else if (!strcmp(mode,"record")) { // record only
717
 
      if ((audio_fd = open(device_name, O_RDONLY, 0)) == -1) {
718
 
        // Open device failed ... either busy or doesn't exist
719
 
        if (errno == EBUSY)
720
 
          fprintf(stderr,"RtAudio: OSS PCM record device (%s) is busy and cannot be opened.\n",
721
 
                  device_name);
722
 
        continue;
723
 
      }
724
 
    }
725
 
    else if (!strcmp(mode,"duplex")) { // duplex mode
726
 
      if ((audio_fd = open(device_name, O_RDWR, 0)) == -1) {
727
 
        // Open device failed ... either busy or doesn't exist
728
 
        if (errno == EBUSY)
729
 
          fprintf(stderr,"RtAudio: OSS PCM device (%s) is busy and cannot be opened for duplex operation.\n",
730
 
                  device_name);
731
 
        continue;
732
 
      }
733
 
      int caps;
734
 
      if (ioctl(audio_fd, SNDCTL_DSP_GETCAPS, &caps)) {
735
 
        close(audio_fd);
736
 
        fprintf(stderr,"RtAudio: OSS error getting device (%s) capabilities for duplex operation.\n",
737
 
                device_name);
738
 
        continue;
739
 
      }
740
 
      if (!(caps & DSP_CAP_DUPLEX)) {
741
 
        close(audio_fd);
742
 
        fprintf(stderr,"RtAudio: OSS reports device (%s) does not support duplex operation.\n",
743
 
                device_name);
744
 
        continue;
745
 
      }
746
 
      if (ioctl(audio_fd, SNDCTL_DSP_SETDUPLEX, 0)) {
747
 
        close(audio_fd);
748
 
        fprintf(stderr,"RtAudio: OSS error setting device (%s) for duplex operation.\n",
749
 
                device_name);
750
 
        continue;
751
 
      }
752
 
    }
753
 
 
754
 
    // Setup the number and size of the fragments
755
 
    if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &temp)) {
756
 
      close(audio_fd);
757
 
      fprintf(stderr,"RtAudio: OSS error setting fragment size for device (%s).\n",
758
 
              device_name);
759
 
      continue;
760
 
    }
761
 
 
762
 
    // Setup the data format ... we're only supporting 16-bit little-endian data for now
763
 
    format = AFMT_S16_LE;
764
 
    if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format) == -1) {
765
 
      close(audio_fd);
766
 
      fprintf(stderr,"RtAudio: OSS error setting data format for device (%s).\n",
767
 
              device_name);
768
 
      continue;
769
 
    }
770
 
 
771
 
    // Check the see whether the device supports the requested format
772
 
    if (format != AFMT_S16_LE) {
773
 
      close(audio_fd);
774
 
      fprintf(stderr,"RtAudio: OSS error ... audio device (%s) doesn't support 16-bit signed LE format.\n",
775
 
              device_name);
776
 
      continue;
777
 
    }
778
 
 
779
 
    // Setup the number of channels
780
 
    if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &chans) == -1) {
781
 
      close(audio_fd);
782
 
      fprintf(stderr,"RtAudio: OSS error setting %d channels on  device (%s).\n",
783
 
              channels, device_name);
784
 
      continue;
785
 
    }
786
 
 
787
 
    // Check to see whether the device supports the requested number of channels
788
 
    if (chans != channels ) {
789
 
      close(audio_fd);
790
 
      fprintf(stderr,"RtAudio: OSS error ... audio device (%s) doesn't support %d channels.\n",
791
 
              device_name, channels);
792
 
      continue;
793
 
    }
794
 
 
795
 
    // Setup the sampling rate
796
 
    speed = (int) srate;
797
 
    if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &speed)==-1) {
798
 
      close(audio_fd);
799
 
      fprintf(stderr,"RtAudio: OSS error setting sample rate = %f on  device (%s).\n",
800
 
              srate, device_name);
801
 
      continue;
802
 
    }
803
 
    
804
 
    // Check to see whether the device supports the requested sample rate
805
 
    if (abs(speed - (int)srate) > 100) {
806
 
      close(audio_fd);
807
 
      fprintf(stderr,"RtAudio: OSS error ... audio device (%s) doesn't support sample rate of %f.\n",
808
 
              device_name, srate);
809
 
      continue;
810
 
    }
811
 
 
812
 
    if (print_list) {
813
 
      close(audio_fd);
814
 
      printf("Audio Device %d: %s\n", i-1, device_name);
815
 
      nChoices++;
816
 
      continue;
817
 
    }
818
 
 
819
 
    // If we got here, we found a device that meets our needs.  Return to the caller.
820
 
    return;
821
 
  }
822
 
 
823
 
  // If we got here and print_list = TRUE, then we need to ask the user to specify
824
 
  // a device from the printed list.  Then we have to go through the whole process
825
 
  // of opening and checking the device capabilities again, as we did above.  We
826
 
  // can't assume the user always types a valid device number.  We can thank OSS
827
 
  // for the kludgy-ness of this whole process.
828
 
  if (print_list && nChoices ) {
829
 
    char choice[16];
830
 
    printf("\nType an audio device number from above: ");
831
 
    fgets(choice, 16, stdin);
832
 
    i = atoi(choice);
833
 
    printf("\n");
834
 
    sprintf(device_name, "%s%d", DAC_NAME, i);
835
 
 
836
 
    // Now redo the above with the specified card.
837
 
    if (!strcmp(mode,"play")) { // playback only
838
 
      if ((audio_fd = open(device_name, O_WRONLY, 0)) == -1) {
839
 
        // Open device failed ... either busy or doesn't exist
840
 
        sprintf(msg, "RtAudio: OSS PCM playback device (%s) cannot be opened.\n",
841
 
                device_name);
842
 
        throw StkError(msg, StkError::SOUNDCARD_CONTROL);
843
 
      }
844
 
    }
845
 
    else if (!strcmp(mode,"record")) { // record only
846
 
      if ((audio_fd = open(device_name, O_RDONLY, 0)) == -1) {
847
 
        // Open device failed ... either busy or doesn't exist
848
 
        sprintf(msg, "RtAudio: OSS PCM record device (%s) cannot be opened.\n",
849
 
                device_name);
850
 
        throw StkError(msg, StkError::SOUNDCARD_CONTROL);
851
 
      }
852
 
    }
853
 
    else if (!strcmp(mode,"duplex")) { // duplex mode
854
 
      if ((audio_fd = open(device_name, O_RDWR, 0)) == -1) {
855
 
        // Open device failed ... either busy or doesn't exist
856
 
        sprintf(msg, "RtAudio: OSS PCM device (%s) cannot be opened for duplex operation.\n",
857
 
                device_name);
858
 
        throw StkError(msg, StkError::SOUNDCARD_CONTROL);
859
 
      }
860
 
      int caps;
861
 
      if (ioctl(audio_fd, SNDCTL_DSP_GETCAPS, &caps)) {
862
 
        close(audio_fd);
863
 
        sprintf(msg, "RtAudio: OSS error getting device (%s) capabilities for duplex operation.\n",
864
 
                device_name);
865
 
        throw StkError(msg, StkError::SOUNDCARD_CAPS);
866
 
      }
867
 
      if (!(caps & DSP_CAP_DUPLEX)) {
868
 
        close(audio_fd);
869
 
        sprintf(msg, "RtAudio: OSS reports device (%s) does not support duplex operation.\n",
870
 
                device_name);
871
 
        throw StkError(msg, StkError::SOUNDCARD_CAPS);
872
 
      }
873
 
      if (ioctl(audio_fd, SNDCTL_DSP_SETDUPLEX, 0)) {
874
 
        close(audio_fd);
875
 
        sprintf(msg, "RtAudio: OSS error setting device (%s) for duplex operation.\n",
876
 
                device_name);
877
 
        throw StkError(msg, StkError::SOUNDCARD_CONTROL);
878
 
      }
879
 
    }
880
 
 
881
 
    // Setup the number and size of the fragments
882
 
    if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &temp)) {
883
 
      close(audio_fd);
884
 
      sprintf(msg, "RtAudio: OSS error setting fragment size for device (%s).\n",
885
 
              device_name);
886
 
      throw StkError(msg, StkError::SOUNDCARD_CONTROL);
887
 
    }
888
 
 
889
 
    // Setup the data format ... we're only supporting 16-bit little-endian data for now
890
 
    format = AFMT_S16_LE;
891
 
    if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format) == -1) {
892
 
      close(audio_fd);
893
 
      sprintf(msg,"RtAudio: OSS error setting data format for device (%s).\n",
894
 
              device_name);
895
 
      throw StkError(msg, StkError::SOUNDCARD_CONTROL);
896
 
    }
897
 
 
898
 
    // Check the see whether the device supports the requested format
899
 
    if (format != AFMT_S16_LE) {
900
 
      close(audio_fd);
901
 
      sprintf(msg,"RtAudio: OSS error ... audio device (%s) doesn't support 16-bit signed LE format.\n",
902
 
              device_name);
903
 
      throw StkError(msg, StkError::SOUNDCARD_CAPS);
904
 
    }
905
 
 
906
 
    // Setup the number of channels
907
 
    if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &chans) == -1) {
908
 
      close(audio_fd);
909
 
      sprintf(msg, "RtAudio: OSS error setting %d channels on  device (%s).\n",
910
 
              channels, device_name);
911
 
      throw StkError(msg, StkError::SOUNDCARD_CONTROL);
912
 
    }
913
 
 
914
 
    // Check to see whether the device supports the requested number of channels
915
 
    if (chans != channels ) {
916
 
      close(audio_fd);
917
 
      sprintf(msg, "RtAudio: OSS error ... audio device (%s) doesn't support %d channels.\n",
918
 
              device_name, channels);
919
 
      throw StkError(msg, StkError::SOUNDCARD_CAPS);
920
 
    }
921
 
 
922
 
    // Setup the sampling rate
923
 
    speed = (int) srate;
924
 
    if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &speed)==-1) {
925
 
      close(audio_fd);
926
 
      sprintf(msg, "RtAudio: OSS error setting sample rate = %f on  device (%s).\n",
927
 
              srate, device_name);
928
 
      throw StkError(msg, StkError::SOUNDCARD_CONTROL);
929
 
    }
930
 
    
931
 
    // Check to see whether the device supports the requested sample rate
932
 
    if (abs(speed - (int)srate) > 100) {
933
 
      close(audio_fd);
934
 
      sprintf(msg,"RtAudio: OSS error ... audio device (%s) doesn't support sample rate of %f.\n",
935
 
              device_name, srate);
936
 
      throw StkError(msg, StkError::SOUNDCARD_CAPS);
937
 
    }
938
 
 
939
 
    // If we got here, the specified device works ... return to the caller.
940
 
    return;
941
 
  }
942
 
 
943
 
  // If we got here, no device was found to meet the requested functionality
944
 
  sprintf(msg, "RtAudio: No OSS device found for requested service!\n");
945
 
  throw StkError(msg, StkError::SOUNDCARD_CAPS);
946
 
}
947
 
 
948
 
RtAudio :: ~RtAudio()
949
 
{
950
 
  if (audio_fd) close(audio_fd);
951
 
  audio_fd=0;
952
 
}
953
 
 
954
 
int RtAudio :: playBuffer(INT16 *buf, int bufsize)
955
 
{
956
 
  // The argument bufsize is the number of audio samples (INT16s) in buf.
957
 
  // The OSS write() routine takes its buffer size in bytes, thus the
958
 
  // multiplication by two.  While it is not necessary to call this function
959
 
  // with fragsize buffers (which should equal RT_BUFFER_SIZE * channels * 2),
960
 
  // its behavior is apparently optimized for such.
961
 
  static char msg[256];
962
 
 
963
 
  if (write(audio_fd, buf, 2*bufsize) == -1) {
964
 
    sprintf(msg, "RtAudio: OSS audio write error!\n");
965
 
    throw StkError(msg, StkError::SOUNDCARD_CONTROL);
966
 
  }
967
 
  return 0;
968
 
}
969
 
 
970
 
int RtAudio :: recordBuffer(INT16 *buf, int bufsize)
971
 
{
972
 
  // The argument bufsize is the number of audio samples (INT16s) in buf.
973
 
  // The OSS read() routine takes its buffer size in bytes, thus the
974
 
  // multiplication by two.  While it is not necessary to call this function
975
 
  // with fragsize buffers (which should equal RT_BUFFER_SIZE * channels * 2),
976
 
  // its behavior is apparently optimized for such.
977
 
  static char msg[256];
978
 
 
979
 
  if (read(audio_fd, buf, 2*bufsize) == -1) {
980
 
    sprintf(msg, "RtAudio: OSS audio read error!\n");
981
 
    throw StkError(msg, StkError::SOUNDCARD_CONTROL);
982
 
  }
983
 
  return 0;
984
 
}
985
 
 
986
 
 
987
 
#elif (defined(__STK_REALTIME_) && defined(__OS_Win_) )
988
 
/*
989
 
  WINDOZE:
990
 
 
991
 
  If anyone needed substantiation as to why Microsoft doesn't deserve
992
 
  to exist, just read through the following code and compare it to
993
 
  any of the other supported APIs in this file.  Dave, thanks for
994
 
  your hard work to get things running better ... it is appreciated.
995
 
  But personally, I'm disgusted with Microsoft and their pure
996
 
  incompetence (GPS, 10/2000).
997
 
 
998
 
  AUDIO OUTPUT:
999
 
 
1000
 
  There are several ways to go about handling sound output
1001
 
  under DirectSound.  We choose to always write new buffers of
1002
 
  data behind the read pointer of the DS play buffer. This is
1003
 
  safe (compared to trying to lead the pointer) but inherently
1004
 
  produces a delay equivalent to the entire sound buffer (plus
1005
 
  any other delays that Windows provides). Our default parameters
1006
 
  cause an inherent delay of about 30 ms b/c of this. To change
1007
 
  this, adjust the NUM_FRAGMENTS definition in RtAudio.h
1008
 
 
1009
 
  AUDIO INPUT:
1010
 
 
1011
 
  We chose to use a complex but stable scheme of keeping our own internal
1012
 
  buffer separate from the DS input buffer. This take up more CPU time
1013
 
  but is safer than using the Sleep() function for critical parts of
1014
 
  code. Users are then given copies of this data (or pointers into our
1015
 
  actual internal buffer, if they use the overloaded version of
1016
 
  recordBuffer(INT16**) A separate thread (under control of the WinMM
1017
 
  timer) takes care of transfering data from the DS buffer to our own buffer.
1018
 
  You can expect a total delay of about 100 - 150 ms for fully duplexed
1019
 
  audio - it seems impossible to get directx to perform any better than this.
1020
 
 
1021
 
  In addition, the windows version has stopPlay, startPlay, startRecord
1022
 
  and stopRecord methods b/c DirectX does not automatically stop I/O if
1023
 
  no fresh data is sent.
1024
 
 
1025
 
  The DirectSoundCapture API is only available with DirectX versions
1026
 
  5.0 and higher.
1027
 
 */
1028
 
 
1029
 
RtAudio :: RtAudio(int channels, MY_FLOAT srate, const char *mode, int device)
1030
 
{
1031
 
  HRESULT result;
1032
 
  BYTE* audioPtr;
1033
 
  DWORD dataLen;
1034
 
  HWND hWnd = GetForegroundWindow();
1035
 
        WAVEFORMATEX waveFormat;
1036
 
        LPGUID directSoundGuid = NULL;
1037
 
        int i, devNum = 0;
1038
 
 
1039
 
  // Initialize the DirectSound object and buffer pointers to NULL
1040
 
  directSoundObject = NULL;
1041
 
  directSoundBuffer = NULL;
1042
 
  directSoundCaptureObject = NULL;
1043
 
  directSoundCaptureBuffer = NULL;
1044
 
  inputBuffer = NULL;
1045
 
 
1046
 
        // Some basic initialization stuff
1047
 
        sampleRate = srate;
1048
 
        nextRecordRead = 0;
1049
 
        nextRecordWrite = 0;
1050
 
        internalError = false;
1051
 
        playing = false;
1052
 
        recording = false;
1053
 
        numDevices = 0;
1054
 
        nextWritePos = 0;
1055
 
 
1056
 
  // Define the wave format structure (16-bit PCM, srate, channels)
1057
 
  ZeroMemory(&waveFormat, sizeof(WAVEFORMATEX));
1058
 
  waveFormat.wFormatTag = WAVE_FORMAT_PCM;
1059
 
  waveFormat.nChannels = channels;
1060
 
  waveFormat.nSamplesPerSec = (unsigned long) srate;
1061
 
  waveFormat.wBitsPerSample = 16;
1062
 
  waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
1063
 
  waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
1064
 
 
1065
 
  // check mode string
1066
 
  if (strcmp(mode,"play") && strcmp(mode,"record") && strcmp(mode,"duplex")) {
1067
 
    sprintf(errormsg, "RtAudio: constructor parameter 'mode' must be play, record, or duplex only.\n");
1068
 
    throw StkError(errormsg, StkError::FUNCTION_SYNTAX);
1069
 
  }
1070
 
 
1071
 
  if (channels < 1) {
1072
 
    sprintf(errormsg, "RtAudio: number of channels = %d not supported!\n", channels);
1073
 
    throw StkError(errormsg, StkError::FUNCTION_SYNTAX);
1074
 
  }
1075
 
 
1076
 
        // PLAYBACK INITIALIZATION
1077
 
        if ( (!strcmp(mode,"play")) || (!strcmp(mode,"duplex")) ) {
1078
 
 
1079
 
    DSBUFFERDESC directSoundBufferDescription;
1080
 
 
1081
 
    if (device == -1) {
1082
 
      // use default device
1083
 
      if (FAILED(result = DirectSoundCreate(NULL, &directSoundObject, NULL))) {
1084
 
        sprintf(errormsg,"RtAudio: Unable to create default direct sound object: %s\n", getErrorMessage(result));
1085
 
        throw StkError(errormsg,StkError::SOUNDCARD_NOT_FOUND);
1086
 
      }
1087
 
      goto have_good_output_device;
1088
 
    } else {
1089
 
      // Enumerate through the devices, trying the user specified device first.
1090
 
      // If that fails, prompt for action.
1091
 
      if (FAILED(result = DirectSoundEnumerate((LPDSENUMCALLBACK)SoundDeviceEnumCallback, this))) {
1092
 
        sprintf(errormsg,"RtAudio: Unable to enumerate through sound devices: %s\n", getErrorMessage(result));
1093
 
        throw StkError(errormsg,StkError::SOUNDCARD_NOT_FOUND);
1094
 
      }
1095
 
      if (device >=0 && device < numDevices) {
1096
 
        // try user specified device if within bounds
1097
 
        directSoundGuid = devices[device].guid;
1098
 
        result = DirectSoundCreate(directSoundGuid, &directSoundObject, NULL);
1099
 
        if (result == DS_OK) goto have_good_output_device;
1100
 
      }
1101
 
    }
1102
 
 
1103
 
    printf("\n");
1104
 
    for (i=0; i<numDevices; i++) {
1105
 
      printf("Playback Device %d:  %s\n", i, devices[i].description);
1106
 
    }
1107
 
    printf("\nPlease type a sound device number from above: ");
1108
 
    char choice[16];
1109
 
    fgets(choice, 16, stdin);
1110
 
    devNum = atoi(choice);
1111
 
    if (devNum >=0 && devNum < numDevices) {
1112
 
      directSoundGuid = devices[devNum].guid;
1113
 
      if (FAILED(result = DirectSoundCreate(directSoundGuid, &directSoundObject, NULL))) {
1114
 
        sprintf(errormsg,"RtAudio: Unable to create direct sound object: %s\n", getErrorMessage(result));
1115
 
        throw StkError(errormsg,StkError::SOUNDCARD_CAPS);
1116
 
      }
1117
 
    } else {
1118
 
      throw StkError("RtAudio: Invalid device number specified!",StkError::SOUNDCARD_NOT_FOUND);
1119
 
    }
1120
 
 
1121
 
    have_good_output_device:
1122
 
 
1123
 
                // Set cooperative level
1124
 
                if (FAILED(result = directSoundObject->SetCooperativeLevel(hWnd, DSSCL_PRIORITY))) {
1125
 
                        sprintf(errormsg,"RtAudio: Unable to set cooperative level: %s\n", getErrorMessage(result));
1126
 
                        throw StkError(errormsg,StkError::SOUNDCARD_CONTROL);
1127
 
                }
1128
 
 
1129
 
    // Get DS device capabilites
1130
 
    DSCAPS directSoundCapabilities;
1131
 
    ZeroMemory(&directSoundCapabilities, sizeof(DSCAPS));
1132
 
    directSoundCapabilities.dwSize = sizeof(DSCAPS);
1133
 
    if (FAILED(result = directSoundObject->GetCaps(&directSoundCapabilities))) {
1134
 
                        sprintf(errormsg,"RtAudio: Unable to get DS capabilities: %s\n", getErrorMessage(result));
1135
 
      throw StkError(errormsg,StkError::SOUNDCARD_CAPS);
1136
 
    }
1137
 
 
1138
 
                /* Even though we will write to the secondary buffer, we need
1139
 
       to access the primary buffer to set the correct output format.
1140
 
       The default is 8-bit, 22 kHz!
1141
 
    */
1142
 
                LPDIRECTSOUNDBUFFER directSoundPrimaryBuffer;
1143
 
                // Setup the DS primary buffer description.
1144
 
                ZeroMemory(&directSoundBufferDescription, sizeof(DSBUFFERDESC));
1145
 
                directSoundBufferDescription.dwSize = sizeof(DSBUFFERDESC);
1146
 
                directSoundBufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER;
1147
 
                // Obtain the primary buffer
1148
 
                if (FAILED(result = directSoundObject->CreateSoundBuffer(&directSoundBufferDescription,
1149
 
                                                             &directSoundPrimaryBuffer, NULL))) {
1150
 
                        sprintf(errormsg,"RtAudio: Unable to access DS primary buffer: %s\n", getErrorMessage(result));
1151
 
                        throw StkError(errormsg,StkError::SOUNDCARD_CONTROL);
1152
 
                }
1153
 
 
1154
 
    // Set the primary DS buffer sound format.
1155
 
                if (FAILED(result = directSoundPrimaryBuffer->SetFormat(&waveFormat))) {
1156
 
                        sprintf(errormsg,"RtAudio: Unable to set DS primary buffer format: %s\n", getErrorMessage(result));
1157
 
                        throw StkError(errormsg,StkError::SOUNDCARD_CONTROL);
1158
 
                }
1159
 
 
1160
 
                // Setup the secondary DS buffer description. Try to do it in hardware
1161
 
                directSoundBufferSize = channels * RT_BUFFER_SIZE * NUM_FRAGMENTS * sizeof(INT16);
1162
 
                ZeroMemory(&directSoundBufferDescription, sizeof(DSBUFFERDESC));
1163
 
                directSoundBufferDescription.dwSize = sizeof(DSBUFFERDESC);
1164
 
                directSoundBufferDescription.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_LOCHARDWARE;
1165
 
                directSoundBufferDescription.dwBufferBytes = directSoundBufferSize;
1166
 
                directSoundBufferDescription.lpwfxFormat = &waveFormat;
1167
 
 
1168
 
                // Try to create the secondary DS buffer. If that doesn't work, try for
1169
 
    // software - if that doesn't work, throw an exception.
1170
 
                if (FAILED(result = directSoundObject->CreateSoundBuffer(&directSoundBufferDescription, &directSoundBuffer, NULL))) {
1171
 
                        directSoundBufferDescription.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_LOCSOFTWARE;
1172
 
                        if (FAILED(result = directSoundObject->CreateSoundBuffer(&directSoundBufferDescription, &directSoundBuffer, NULL))) {
1173
 
                                sprintf(errormsg,"RtAudio: Unable to create secondary DS buffer: %s\n", getErrorMessage(result));
1174
 
                                throw StkError(errormsg,StkError::SOUNDCARD_CONTROL);
1175
 
                        }
1176
 
                }
1177
 
 
1178
 
                // Get the buffer size
1179
 
                DSBCAPS dsbcaps;
1180
 
                dsbcaps.dwSize = sizeof(DSBCAPS);
1181
 
                directSoundBuffer->GetCaps(&dsbcaps);
1182
 
                directSoundBufferSize = dsbcaps.dwBufferBytes;
1183
 
 
1184
 
    // Lock the DS buffer
1185
 
                if (FAILED(result = directSoundBuffer->Lock(0, directSoundBufferSize, (LPLPVOID) &audioPtr, &dataLen, NULL, NULL, 0))) {
1186
 
                        sprintf(errormsg,"RtAudio: Unable to lock DS buffer: %s\n", getErrorMessage(result));
1187
 
                        throw StkError(errormsg,StkError::SOUNDCARD_CONTROL);
1188
 
                }
1189
 
 
1190
 
    // Zero the DS buffer
1191
 
    ZeroMemory(audioPtr, dataLen);
1192
 
 
1193
 
    // Unlock the DS buffer
1194
 
                if (FAILED(result = directSoundBuffer->Unlock(audioPtr, dataLen, NULL, 0))) {
1195
 
                        sprintf(errormsg,"RtAudio: Unable to unlock DS buffer: %s\n", getErrorMessage(result));
1196
 
                        throw StkError(errormsg,StkError::SOUNDCARD_CONTROL);
1197
 
                }
1198
 
        } // end of play initialization
1199
 
 
1200
 
 
1201
 
        // RECORDING INITIALIZATION
1202
 
  if ( (!strcmp(mode,"record")) || (!strcmp(mode,"duplex")) ) {
1203
 
 
1204
 
    DSCBUFFERDESC directSoundCaptureDescription;
1205
 
 
1206
 
    if (device == -1) {
1207
 
      // use default device
1208
 
      if (FAILED(result = DirectSoundCaptureCreate(NULL, &directSoundCaptureObject, NULL))) {
1209
 
        sprintf(errormsg,"RtAudio: Unable to create default direct sound capture object: %s\n", getErrorMessage(result));
1210
 
        throw StkError(errormsg,StkError::SOUNDCARD_NOT_FOUND);
1211
 
      }
1212
 
      goto have_good_input_device;
1213
 
    } else {
1214
 
      // Enumerate through the devices, trying the user specified device first.
1215
 
      // If that fails, prompt for action.
1216
 
      if (FAILED(result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)SoundDeviceEnumCallback, this))) {
1217
 
        sprintf(errormsg,"RtAudio: Unable to enumerate through sound capture devices: %s\n", getErrorMessage(result));
1218
 
        throw StkError(errormsg,StkError::SOUNDCARD_NOT_FOUND);
1219
 
      }
1220
 
      if (device >=0 && device < numDevices) {
1221
 
        // try user specified device if within bounds
1222
 
        directSoundGuid = devices[device].guid;
1223
 
        result = DirectSoundCaptureCreate(directSoundGuid, &directSoundCaptureObject, NULL);
1224
 
        if (result == DS_OK) goto have_good_input_device;
1225
 
      }
1226
 
    }
1227
 
 
1228
 
    printf("\n");
1229
 
    for (i=0; i<numDevices; i++) {
1230
 
      printf("Capture Device %d:  %s\n", i, devices[i].description);
1231
 
    }
1232
 
    printf("\nPlease type a sound device number from above: ");
1233
 
    char choice[16];
1234
 
    fgets(choice, 16, stdin);
1235
 
    devNum = atoi(choice);
1236
 
    if (devNum >=0 && devNum < numDevices) {
1237
 
      directSoundGuid = devices[devNum].guid;
1238
 
      if (FAILED(result = DirectSoundCaptureCreate(directSoundGuid, &directSoundCaptureObject, NULL))) {
1239
 
        sprintf(errormsg,"RtAudio: Unable to create direct sound capture object: %s\n",getErrorMessage(result));
1240
 
        throw StkError(errormsg,StkError::SOUNDCARD_CAPS);
1241
 
      }
1242
 
    } else {
1243
 
      throw StkError("RtAudio: Invalid device number specified!\n", StkError::SOUNDCARD_NOT_FOUND);
1244
 
    }
1245
 
 
1246
 
    have_good_input_device:
1247
 
 
1248
 
    // Setup the DS Capture buffer description
1249
 
    ZeroMemory(&directSoundCaptureDescription, sizeof(DSCBUFFERDESC));
1250
 
    directSoundCaptureDescription.dwSize = sizeof(DSCBUFFERDESC);
1251
 
    directSoundCaptureDescription.dwFlags = 0;
1252
 
    directSoundCaptureBufferSize = (DWORD)(waveFormat.nAvgBytesPerSec * DS_CAPTURE_BUFFER_SIZE);
1253
 
    directSoundCaptureDescription.dwBufferBytes = directSoundCaptureBufferSize;
1254
 
    directSoundCaptureDescription.dwReserved = 0;
1255
 
    directSoundCaptureDescription.lpwfxFormat = &waveFormat;
1256
 
 
1257
 
    // Create the DS Capture buffer
1258
 
    if (FAILED(result = directSoundCaptureObject->CreateCaptureBuffer(&directSoundCaptureDescription, &directSoundCaptureBuffer, NULL))) {
1259
 
                        sprintf(errormsg,"RtAudio: Unable to create DS capture buffer: %s\n", getErrorMessage(result));
1260
 
                        throw StkError(errormsg,StkError::SOUNDCARD_CONTROL);
1261
 
    }
1262
 
 
1263
 
    // Lock the DS Capture buffer
1264
 
    if (FAILED(result = directSoundCaptureBuffer->Lock(0, directSoundCaptureBufferSize, (LPLPVOID) &audioPtr, &dataLen, NULL, NULL, 0))) {
1265
 
                        sprintf(errormsg,"RtAudio: Unable to lock DS capture buffer: %s\n", getErrorMessage(result));
1266
 
      throw StkError(errormsg,StkError::SOUNDCARD_CONTROL);
1267
 
    }
1268
 
 
1269
 
    // Zero the DS Capture buffer
1270
 
    ZeroMemory(audioPtr, dataLen);
1271
 
 
1272
 
    // Size and allocate our inputBuffer
1273
 
    inputBufferSize = (long) (sampleRate * channels * 2 * sizeof(INT16));
1274
 
    inputBuffer = (BYTE *) new BYTE[inputBufferSize];
1275
 
 
1276
 
    //Zero our internal input buffer
1277
 
    ZeroMemory(inputBuffer, inputBufferSize);
1278
 
 
1279
 
    // Unlock the DS Capture buffer
1280
 
    if (FAILED(result = directSoundCaptureBuffer->Unlock(audioPtr, dataLen, NULL, 0))) {
1281
 
                        sprintf(errormsg,"RtAudio: Unable to unlock DS capture buffer: %s\n", getErrorMessage(result));
1282
 
                        throw StkError(errormsg,StkError::SOUNDCARD_CONTROL);
1283
 
    }
1284
 
 
1285
 
    // Start the DS Capture buffer input
1286
 
    if (FAILED(result = directSoundCaptureBuffer->Start(DSCBSTART_LOOPING))) {
1287
 
                        sprintf(errormsg,"RtAudio: Unable to start DS capture buffer looping: %s\n", getErrorMessage(result));
1288
 
                        throw StkError(errormsg,StkError::SOUNDCARD_CONTROL);
1289
 
    }
1290
 
 
1291
 
    //CALLBACK STUFF HERE
1292
 
    if ((timerID = timeSetEvent (TIMER_PERIOD, TIMER_RESOLUTION, PeriodicCallbackFn, (DWORD) this, TIME_PERIODIC)) == NULL) {
1293
 
                        throw StkError("RtAudio: Couldn't start periodic timer callback function for audio input.\n",StkError::PROCESS_THREAD);
1294
 
    }
1295
 
                recording = true;
1296
 
 
1297
 
  } // end of record initialization
1298
 
 
1299
 
  if ( (!strcmp(mode,"play")) || (!strcmp(mode,"duplex")) ) {
1300
 
    // Start the DS buffer playback
1301
 
    if (FAILED(result = directSoundBuffer->Play(0, 0, DSBPLAY_LOOPING ))) {
1302
 
                        sprintf(errormsg,"RtAudio: Unable to start DS buffer looping: %s\n", getErrorMessage(result));
1303
 
                        throw StkError(errormsg,StkError::SOUNDCARD_CONTROL);
1304
 
    }
1305
 
                playing = true;
1306
 
  }
1307
 
}
1308
 
 
1309
 
RtAudio :: ~RtAudio()
1310
 
{
1311
 
        // Cleanup the DS buffers
1312
 
  if (directSoundBuffer)        {
1313
 
          directSoundBuffer->Stop();
1314
 
          directSoundBuffer->Release();
1315
 
          directSoundBuffer = NULL;
1316
 
        }
1317
 
  if (directSoundCaptureBuffer) {
1318
 
          directSoundCaptureBuffer->Stop();
1319
 
          directSoundCaptureBuffer->Release();
1320
 
          directSoundCaptureBuffer = NULL;
1321
 
        }
1322
 
 
1323
 
  // Cleanup the DS objects
1324
 
  if (directSoundObject) {
1325
 
          directSoundObject->Release();
1326
 
          directSoundObject = NULL;
1327
 
        }
1328
 
  if (directSoundCaptureObject) {
1329
 
          directSoundCaptureObject->Release();
1330
 
          directSoundCaptureObject = NULL;
1331
 
        }
1332
 
        if (timerID) {
1333
 
                timeKillEvent (timerID);
1334
 
  }
1335
 
  if (inputBuffer) {
1336
 
    delete [] inputBuffer;
1337
 
    inputBuffer = 0;
1338
 
  }
1339
 
}
1340
 
 
1341
 
int RtAudio :: playBuffer(short *buf, int bufsize)
1342
 
{
1343
 
        if (!playing) startPlay();
1344
 
 
1345
 
        HRESULT result;
1346
 
  LPVOID buffer1 = NULL;
1347
 
  LPVOID buffer2 = NULL;
1348
 
  DWORD bufferSize1 = 0;
1349
 
  DWORD bufferSize2 = 0;
1350
 
  DWORD playPos, safePos;
1351
 
        int samplesToWrite;
1352
 
 
1353
 
        do {
1354
 
    // The user may send us a buffer of data that is too large
1355
 
    // for us to stream in at once, so set up a loop and check
1356
 
    // the size of their buffer.
1357
 
                samplesToWrite = bufsize;
1358
 
                if (samplesToWrite > RT_BUFFER_SIZE  ) {
1359
 
                        samplesToWrite = RT_BUFFER_SIZE ;
1360
 
                }
1361
 
 
1362
 
                // Find out where the read and "safe write" pointers are.
1363
 
                if (FAILED(result = directSoundBuffer->GetCurrentPosition(&playPos, &safePos))) {
1364
 
                        sprintf(errormsg,"RtAudio: Unable to get current DS position: %s\n", getErrorMessage(result));
1365
 
                        throw StkError(errormsg,StkError::SOUNDCARD_CONTROL);
1366
 
                }
1367
 
 
1368
 
                if( playPos < nextWritePos ) playPos += directSoundBufferSize; // unwrap offset
1369
 
                DWORD endWrite = nextWritePos + samplesToWrite * sizeof(INT16);
1370
 
 
1371
 
    //printf("bufsize = %d ", bufsize);
1372
 
                // Check whether the entire write region is behind the play pointer.
1373
 
                while ( playPos < endWrite ) {
1374
 
                        // If we are here, then we must wait until the play pointer
1375
 
                        // gets beyond the write region.  To do so, we can use the
1376
 
      // Sleep() function (which has questionable accuracy).
1377
 
                        // Sleep until safePos catches up. Calculate number of
1378
 
                        // milliseconds to wait as:
1379
 
                        //   time = distance * (milliseconds/second) * fudgefactor /
1380
 
                        //          ((bytes/sample) * (samples/second))
1381
 
                        // A "fudgefactor" less than 1 is used because it was found
1382
 
                        // that sleeping too long was MUCH worse than sleeping for
1383
 
                        // several shorter periods.
1384
 
                        DWORD millis = (DWORD) (((endWrite - playPos) * 900.0) / ( sizeof(INT16) * sampleRate));
1385
 
      //printf(". ");
1386
 
                        Sleep( millis );
1387
 
 
1388
 
                        // Wake up, find out where we are now
1389
 
                        result = directSoundBuffer->GetCurrentPosition( &playPos, &safePos );
1390
 
                        if( result != DS_OK ) return -1;
1391
 
                        if( playPos < nextWritePos ) playPos += directSoundBufferSize; // unwrap offset
1392
 
                }
1393
 
 
1394
 
          // Lock free space in the buffer
1395
 
                result = directSoundBuffer->Lock (nextWritePos, samplesToWrite * sizeof(INT16), &buffer1, &bufferSize1, &buffer2, &bufferSize2, 0);
1396
 
                if (SUCCEEDED(result)) {
1397
 
                        // Copy the buffer into the DS
1398
 
                        CopyMemory(buffer1, buf, bufferSize1);
1399
 
                        if(NULL != buffer2) CopyMemory(buffer2, buf+(bufferSize1/sizeof(INT16)), bufferSize2);
1400
 
 
1401
 
                        // Update our buffer offset and unlock sound buffer
1402
 
                        if (FAILED(directSoundBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2))) {
1403
 
                                throw StkError("RtAudio: Unable to unlock DS buffer\n",StkError::SOUNDCARD_CONTROL);
1404
 
                        }
1405
 
                        nextWritePos = (nextWritePos + bufferSize1 + bufferSize2) % directSoundBufferSize;
1406
 
                }       else {
1407
 
                        sprintf(errormsg,"RtAudio: Unable to lock DS buffer: %s\n", getErrorMessage(result));
1408
 
                        throw StkError(errormsg,StkError::SOUNDCARD_CONTROL);
1409
 
                }
1410
 
 
1411
 
                //update how many samples still need to be written - possibly no more
1412
 
                bufsize -= samplesToWrite;
1413
 
                buf += samplesToWrite;
1414
 
        } while (bufsize > 0);
1415
 
 
1416
 
        return 0;
1417
 
}
1418
 
 
1419
 
int RtAudio :: recordBuffer(short *buf, int bufsize)
1420
 
{
1421
 
        if (!recording) startRecord();
1422
 
 
1423
 
        if (internalError) {
1424
 
                throw StkError("RtAudio: Read failure in windoze capture thread.\n",
1425
 
                   StkError::SOUNDCARD_CONTROL);
1426
 
        }
1427
 
  else {
1428
 
                UINT length; // length of data to copy
1429
 
                while (bufsize > 0) {
1430
 
                        if (nextRecordWrite > nextRecordRead) {
1431
 
                                length = nextRecordWrite - nextRecordRead;
1432
 
                                if (length > bufsize * sizeof(INT16)) {
1433
 
          // there may be more data available than our user wants
1434
 
                                        length = bufsize * sizeof(INT16);
1435
 
                                }
1436
 
                                CopyMemory(buf, inputBuffer+nextRecordRead, length);
1437
 
                                nextRecordRead += length;
1438
 
                                bufsize -= length / sizeof(INT16);
1439
 
                                buf += length / sizeof(INT16);
1440
 
                        }
1441
 
      else if (nextRecordWrite == nextRecordRead) {
1442
 
        // no data is currently available to return to the user -
1443
 
                                // so we sleep for the time necesary to produce the desired
1444
 
        // number of samples
1445
 
                                Sleep((DWORD) (bufsize / sampleRate * 1000));
1446
 
                        }
1447
 
      else {
1448
 
        // this means that our write pointer must have wrapped around -
1449
 
        // in this case we return the last part ofthe buffer and save the
1450
 
        // readable beginning of the buffer to be copied next time around
1451
 
        // the loop, rather than do two copies here - just simpler code
1452
 
                                length = inputBufferSize - nextRecordRead;
1453
 
                                if (length > bufsize * sizeof(INT16)) {
1454
 
          // there may be more data available than our user wants
1455
 
                                        length = bufsize * sizeof(INT16);
1456
 
                                        CopyMemory(buf, inputBuffer+nextRecordRead, length);
1457
 
          // dont fully wrap around - we didn't use all data
1458
 
                                        nextRecordRead += length;
1459
 
                                }
1460
 
        else {
1461
 
                                        CopyMemory(buf, inputBuffer+nextRecordRead, length);
1462
 
                                        nextRecordRead = 0; // we wrap around
1463
 
                                }
1464
 
                                bufsize -= length / sizeof(INT16);
1465
 
                                buf += length / sizeof(INT16);
1466
 
                        }
1467
 
                }
1468
 
        }
1469
 
        return 0;
1470
 
}
1471
 
 
1472
 
/**** Windoze specific overload of recordBuffer ****/
1473
 
int RtAudio :: recordBuffer(INT16** buf)
1474
 
{
1475
 
        if (!recording) startRecord();
1476
 
 
1477
 
  if (internalError) {
1478
 
                throw StkError("RtAudio: Read failure in windoze capture thread.\n",StkError::SOUNDCARD_CONTROL);
1479
 
 
1480
 
        } else if (nextRecordRead == nextRecordWrite) {
1481
 
    // no new data
1482
 
                return 0;
1483
 
 
1484
 
        } else {
1485
 
                BYTE* temp = inputBuffer + nextRecordRead;
1486
 
                *buf = (INT16*) temp;
1487
 
                UINT length;
1488
 
 
1489
 
                if (nextRecordWrite > nextRecordRead) {
1490
 
                        length = nextRecordWrite - nextRecordRead;
1491
 
                        nextRecordRead = nextRecordWrite;
1492
 
                } else {
1493
 
      /* This means that our write pointer must have wrapped around -
1494
 
         in this case we return the last part ofthe buffer and save the
1495
 
         readable begining of the buffer to be returned next call to
1496
 
         recordBuffer, rather than have some complex two pointer wrap
1497
 
         around scheme.
1498
 
      */
1499
 
                        length = inputBufferSize - nextRecordRead;
1500
 
                        nextRecordRead = 0;
1501
 
                }
1502
 
 
1503
 
    // We divide by two so that we return number of samples, not bytes
1504
 
                return (length/2);
1505
 
        }
1506
 
}
1507
 
 
1508
 
/**** Windows specific start and stop functions ****/
1509
 
void RtAudio :: stopPlay()
1510
 
{
1511
 
        if (!playing) return;
1512
 
 
1513
 
        HRESULT result;
1514
 
        BYTE* audioPtr;
1515
 
  DWORD dataLen;
1516
 
 
1517
 
        //stop the buffer
1518
 
  if (FAILED(result = directSoundBuffer->Stop())) {
1519
 
                sprintf(errormsg,"RtAudio: Unable to stop DS buffer looping: %s\n", getErrorMessage(result));
1520
 
                throw StkError(errormsg,StkError::SOUNDCARD_CONTROL);
1521
 
  }
1522
 
 
1523
 
        // Lock the DS buffer and clear it so if we start to play again, we won't have old data playing
1524
 
        if (FAILED(result = directSoundBuffer->Lock(0, directSoundBufferSize, (LPLPVOID) &audioPtr, &dataLen, NULL, NULL, 0))) {
1525
 
                sprintf(errormsg,"RtAudio: Unable to lock DS buffer: %s\n", getErrorMessage(result));
1526
 
                throw StkError(errormsg,StkError::SOUNDCARD_CONTROL);
1527
 
        }
1528
 
 
1529
 
        // Zero the DS buffer
1530
 
        ZeroMemory(audioPtr, dataLen);
1531
 
 
1532
 
        // Unlock the DS buffer
1533
 
        if (FAILED(result = directSoundBuffer->Unlock(audioPtr, dataLen, NULL, 0))) {
1534
 
                sprintf(errormsg,"RtAudio: Unable to unlock DS buffer: %s\n", getErrorMessage(result));
1535
 
                throw StkError(errormsg,StkError::SOUNDCARD_CONTROL);
1536
 
        }
1537
 
        //if we start playing again, we must begin at beginning of buffer
1538
 
        nextWritePos = 0;
1539
 
 
1540
 
        playing = false;
1541
 
}
1542
 
 
1543
 
void RtAudio :: startPlay()
1544
 
{
1545
 
        if (playing) return;
1546
 
 
1547
 
        HRESULT result;
1548
 
  if (FAILED(result = directSoundBuffer->Play(0, 0, DSBPLAY_LOOPING ))) {
1549
 
                sprintf(errormsg,"RtAudio: Unable to restart DS buffer: %s\n", getErrorMessage(result));
1550
 
                throw StkError(errormsg,StkError::SOUNDCARD_CONTROL);
1551
 
  }
1552
 
        playing = true;
1553
 
}
1554
 
 
1555
 
void RtAudio :: stopRecord()
1556
 
{
1557
 
        if (!recording) return;
1558
 
 
1559
 
        HRESULT result;
1560
 
        BYTE* audioPtr;
1561
 
  DWORD dataLen;
1562
 
 
1563
 
        // stop the buffer
1564
 
  if (FAILED(result = directSoundCaptureBuffer->Stop())) {
1565
 
                sprintf(errormsg,"RtAudio: Unable to stop DS capture buffer looping: %s\n", getErrorMessage(result));
1566
 
                throw StkError(errormsg,StkError::SOUNDCARD_CONTROL);
1567
 
  }
1568
 
 
1569
 
        // Lock the DS buffer and clear it so if we start to play again, we won't have old data playing
1570
 
        if (FAILED(result = directSoundCaptureBuffer->Lock(0, directSoundCaptureBufferSize, (LPLPVOID) &audioPtr, &dataLen, NULL, NULL, 0))) {
1571
 
                sprintf(errormsg,"RtAudio: Unable to lock DS capture buffer: %s\n", getErrorMessage(result));
1572
 
                throw StkError(errormsg,StkError::SOUNDCARD_CONTROL);
1573
 
        }
1574
 
 
1575
 
        // Zero the DS buffer
1576
 
        ZeroMemory(audioPtr, dataLen);
1577
 
 
1578
 
        // Unlock the DS buffer
1579
 
        if (FAILED(result = directSoundCaptureBuffer->Unlock(audioPtr, dataLen, NULL, 0))) {
1580
 
                sprintf(errormsg,"RtAudio: Unable to unlock DS capture buffer: %s\n", getErrorMessage(result));
1581
 
                throw StkError(errormsg,StkError::SOUNDCARD_CONTROL);
1582
 
        }
1583
 
        // If we start playing again, we must begin at beginning of buffer
1584
 
        recording = false;
1585
 
}
1586
 
 
1587
 
void RtAudio :: startRecord()
1588
 
{
1589
 
        if (recording) return;
1590
 
 
1591
 
        HRESULT result;
1592
 
        if (FAILED(result = directSoundCaptureBuffer->Start(DSCBSTART_LOOPING))) {
1593
 
                sprintf(errormsg,"RtAudio: Unable to restart DS capture buffer looping: %s\n", getErrorMessage(result));
1594
 
                throw StkError(errormsg,StkError::SOUNDCARD_CONTROL);
1595
 
  }
1596
 
 
1597
 
        recording = true;
1598
 
}
1599
 
 
1600
 
 
1601
 
/**** Internal Utilities ****/
1602
 
 
1603
 
void RtAudio::getInputSamples()
1604
 
{
1605
 
  /* This function is called periodically to get samples from
1606
 
     the direct sound capture buffer and transfer them into our
1607
 
     own buffer.
1608
 
  */
1609
 
  HRESULT result;
1610
 
  LPVOID buffer1 = NULL;
1611
 
  LPVOID buffer2 = NULL;
1612
 
  DWORD size1 = 0;
1613
 
  DWORD size2 = 0;
1614
 
  DWORD capturePos, safePos;
1615
 
  static UINT nextDirectSoundReadPosition = 0;
1616
 
  int numBytesToLock;
1617
 
 
1618
 
  // Find out where the write and "safe read" pointers are.
1619
 
  if (FAILED(result = directSoundCaptureBuffer->GetCurrentPosition(&capturePos, &safePos))) {
1620
 
                internalError = true;
1621
 
                return;
1622
 
        }
1623
 
 
1624
 
        if (!recording) {
1625
 
    // The user doesn't want us to continue recording, so we must
1626
 
    // skip over info until they call startRecord().
1627
 
          if (safePos < nextDirectSoundReadPosition)
1628
 
      safePos += directSoundCaptureBufferSize; //unwrap offset
1629
 
                numBytesToLock = safePos - nextDirectSoundReadPosition; //or in this case, num bytes to skip...
1630
 
                nextDirectSoundReadPosition = (nextDirectSoundReadPosition + numBytesToLock) % directSoundCaptureBufferSize;
1631
 
                nextRecordWrite = nextRecordRead;
1632
 
                return;
1633
 
        }
1634
 
 
1635
 
        if (safePos == nextDirectSoundReadPosition) {
1636
 
    // If this case, no input samples are yet ready so we must wait until
1637
 
    // some are. If this happens alot, we should increase the period of
1638
 
    // our callback function.
1639
 
                return;
1640
 
        }
1641
 
 
1642
 
  if ( safePos < nextDirectSoundReadPosition )
1643
 
    safePos += directSoundCaptureBufferSize; //unwrap offset
1644
 
        numBytesToLock = safePos - nextDirectSoundReadPosition;
1645
 
        UINT availableSpace = inputBufferSize - nextRecordWrite;
1646
 
 
1647
 
        /* This code is rather long and complex, b/c it must handle the data
1648
 
     transfer from the direct sound capture buffer to our own internal
1649
 
     buffer, and both, one, or neither buffer may wrap around.
1650
 
  */
1651
 
  if (SUCCEEDED(result = directSoundCaptureBuffer->Lock(nextDirectSoundReadPosition, numBytesToLock, &buffer1, &size1, &buffer2, &size2, 0))) {
1652
 
                if (availableSpace > size1) {
1653
 
      // we have more than enough space in our internal buffer to hold the data
1654
 
        CopyMemory((inputBuffer + nextRecordWrite), buffer1, size1);
1655
 
        availableSpace -= size1;
1656
 
        nextRecordWrite += size1;
1657
 
 
1658
 
                } else if (availableSpace == size1) {
1659
 
      // we have exactly enough space
1660
 
                        CopyMemory((inputBuffer + nextRecordWrite), buffer1, size1);
1661
 
                        availableSpace = inputBufferSize;
1662
 
        nextRecordWrite = 0;
1663
 
 
1664
 
                } else {
1665
 
      // we need to wrap around to the begining of the buffer, ie availableSpace < size1
1666
 
                        CopyMemory((inputBuffer + nextRecordWrite), buffer1, availableSpace);
1667
 
                        size1 -= availableSpace;
1668
 
                        CopyMemory(inputBuffer,(BYTE*)buffer1+availableSpace, size1);
1669
 
                        availableSpace = inputBufferSize - size1;
1670
 
                        nextRecordWrite = size1;
1671
 
                }
1672
 
 
1673
 
    if (buffer2 != NULL) {
1674
 
      // this means that the DS buffer wrapped around, and we need to
1675
 
      // deal with second data portion
1676
 
                        if (availableSpace > size2) {
1677
 
        // we have more than enough space in our internal buffer to hold data
1678
 
                                CopyMemory((inputBuffer + nextRecordWrite), buffer2, size2);
1679
 
                                nextRecordWrite += size2;
1680
 
 
1681
 
                        } else if (availableSpace == size2) {
1682
 
        // we have exactly enough space
1683
 
                                CopyMemory((inputBuffer + nextRecordWrite), buffer2, size2);
1684
 
                                nextRecordWrite = 0;
1685
 
 
1686
 
                        } else {
1687
 
        // we need to wrap around to the begining of the buffer, ie availableSpace < size2
1688
 
                                CopyMemory((inputBuffer + nextRecordWrite), buffer2, availableSpace);
1689
 
                                size2 -= availableSpace;
1690
 
                                CopyMemory(inputBuffer,(BYTE*)buffer2+availableSpace, size2);
1691
 
                                nextRecordWrite = size2;
1692
 
                        }
1693
 
                }
1694
 
 
1695
 
                // Update our buffer offset and unlock sound buffer
1696
 
                directSoundCaptureBuffer->Unlock (buffer1, size1, buffer2, size2);
1697
 
                nextDirectSoundReadPosition = (nextDirectSoundReadPosition + size1 + size2) % directSoundCaptureBufferSize;
1698
 
        } else {
1699
 
    // we were unable to lock the buffer
1700
 
                internalError = true;
1701
 
                return;
1702
 
        }
1703
 
}
1704
 
 
1705
 
//This static callback function is used by the windows multimedia timer for recording
1706
 
void CALLBACK RtAudio::PeriodicCallbackFn(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
1707
 
{
1708
 
  // dwUser contains ptr to our RtAudio object
1709
 
  RtAudio * soundIO = (RtAudio *) dwUser;
1710
 
  (soundIO->getInputSamples)();
1711
 
}
1712
 
 
1713
 
//Windows forces you to use a callback function to enumerate through sound devices...
1714
 
bool CALLBACK RtAudio::SoundDeviceEnumCallback(LPGUID lpguid,LPCSTR lpcstrDescription,LPCSTR lpcstrModule, LPVOID lpContext)
1715
 
//bool CALLBACK RtAudio::SoundDeviceEnumCallback(LPGUID guid, LPCSTR desc, LPCSTR module, LPVOID context)
1716
 
{
1717
 
        ((RtAudio *) lpContext)->addDevice(lpguid,(char*) lpcstrDescription,(char*) lpcstrModule);
1718
 
 
1719
 
  /*
1720
 
        if (numDevices < MAX_DEVICES) {
1721
 
                if (guid != NULL) {
1722
 
                        // make our own copy of the device ID, although probably not necesary
1723
 
                        devices[numDevices].guid = (LPGUID) LocalAlloc(LPTR, sizeof(GUID));
1724
 
                        memcpy(devices[numDevices].guid, guid, sizeof(GUID));
1725
 
                        devices[numDevices].moduleName = module;
1726
 
                        devices[numDevices].description = (char *)desc;
1727
 
                }
1728
 
    else {
1729
 
                        devices[numDevices].guid = NULL;
1730
 
                        devices[numDevices].description = "Default Device";
1731
 
                        devices[numDevices].moduleName = "";
1732
 
                }
1733
 
                numDevices++;
1734
 
        }
1735
 
  */
1736
 
        return true;
1737
 
}
1738
 
 
1739
 
void RtAudio::addDevice(LPGUID guid, char* description, char* moduleName)
1740
 
{
1741
 
        if (numDevices < MAX_DEVICES) {
1742
 
                if (guid != NULL) {
1743
 
                        // make our own copy of the device ID, although probably not necesary
1744
 
                        devices[numDevices].guid = (LPGUID) LocalAlloc(LPTR, sizeof(GUID));
1745
 
                        memcpy(devices[numDevices].guid,guid,sizeof(GUID));
1746
 
                        devices[numDevices].moduleName = moduleName;
1747
 
                        devices[numDevices].description = description;
1748
 
                }
1749
 
    else {
1750
 
                        devices[numDevices].guid = NULL;
1751
 
                        devices[numDevices].description = "Default Device";
1752
 
                        devices[numDevices].moduleName = "";
1753
 
                }
1754
 
                numDevices++;
1755
 
        }
1756
 
}
1757
 
 
1758
 
char* RtAudio::getErrorMessage(int code) {
1759
 
        switch (code) {
1760
 
  case DSERR_ALLOCATED:
1761
 
    return "Direct Sound already allocated";
1762
 
 
1763
 
  case DSERR_CONTROLUNAVAIL:
1764
 
    return "Direct Sound control unavailable";
1765
 
 
1766
 
  case DSERR_INVALIDPARAM:
1767
 
    return "Direct Sound invalid parameter";
1768
 
 
1769
 
  case DSERR_INVALIDCALL:
1770
 
    return "Direct Sound invalid call";
1771
 
 
1772
 
  case DSERR_GENERIC:
1773
 
    return "Direct Sound generic error";
1774
 
 
1775
 
  case DSERR_PRIOLEVELNEEDED:
1776
 
    return "Direct Sound Priority level needed";
1777
 
 
1778
 
  case DSERR_OUTOFMEMORY:
1779
 
    return "Direct Sound out of memory";
1780
 
 
1781
 
  case DSERR_BADFORMAT:
1782
 
    return "Direct Sound bad format";
1783
 
 
1784
 
  case DSERR_UNSUPPORTED:
1785
 
    return "Direct Sound unsupported error";
1786
 
 
1787
 
  case DSERR_NODRIVER:
1788
 
    return "Direct Sound no driver error";
1789
 
 
1790
 
  case DSERR_ALREADYINITIALIZED:
1791
 
    return "Direct Sound already initialized";
1792
 
 
1793
 
  case DSERR_NOAGGREGATION:
1794
 
    return "Direct Sound no aggregation";
1795
 
 
1796
 
  case DSERR_BUFFERLOST:
1797
 
    return "Direct Sound buffer lost";
1798
 
 
1799
 
  case DSERR_OTHERAPPHASPRIO:
1800
 
    return "Direct Sound other app has priority";
1801
 
 
1802
 
  case DSERR_UNINITIALIZED:
1803
 
    return "Direct Sound uninitialized";
1804
 
 
1805
 
  default:
1806
 
    return "Direct Sound unknown error";
1807
 
        }
1808
 
}
1809
 
 
1810
 
#endif