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

« back to all changes in this revision

Viewing changes to driver/alsa9audio.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
 
//  MusE
3
 
//  Linux Music Editor
4
 
//    $Id: alsa9audio.cpp,v 1.4 2002/02/27 11:52:58 muse Exp $
5
 
//  (C) Copyright 2000 Werner Schweer (ws@seh.de)
6
 
//=========================================================
7
 
 
8
 
#include "config.h"
9
 
 
10
 
#ifdef AUDIO
11
 
#ifdef ALSACVS
12
 
#include <alsa/asoundlib.h>
13
 
#else
14
 
#include <sys/asoundlib.h>
15
 
#endif
16
 
#if (SND_LIB_MAJOR==0) && (SND_LIB_MINOR==9)
17
 
#include <fcntl.h>
18
 
#include <stdio.h>
19
 
#include <unistd.h>
20
 
#include <errno.h>
21
 
#include <qstring.h>
22
 
#include <sys/ioctl.h>
23
 
#include <sys/time.h>
24
 
 
25
 
#include "globals.h"
26
 
#include "audiodev.h"
27
 
 
28
 
//---------------------------------------------------------
29
 
//   AlsaAudioDevice
30
 
//---------------------------------------------------------
31
 
 
32
 
class AlsaAudioDevice : public AudioDevice {
33
 
      int card;
34
 
      int dev;
35
 
      snd_pcm_t* playbackHandle;
36
 
      snd_pcm_t* captureHandle;
37
 
 
38
 
   public:
39
 
      AlsaAudioDevice(int c, int d, int f, const QString& s)
40
 
         : AudioDevice(s) {
41
 
            card = c;
42
 
            dev  = d;
43
 
            _rwFlags = f;
44
 
            playbackHandle = 0;
45
 
            captureHandle = 0;
46
 
            }
47
 
      virtual QString open(int);
48
 
      virtual void close();
49
 
      virtual int read(unsigned char* p, int n);
50
 
      virtual int write(const unsigned char* p, int n);
51
 
      virtual int selectrfd() const;
52
 
      virtual int selectwfd() const;
53
 
      virtual void start() const;
54
 
      virtual void stop () const;
55
 
      };
56
 
 
57
 
static int buffer_time = -1;
58
 
static int avail_min   = -1;
59
 
 
60
 
static size_t bits_per_sample;
61
 
static size_t bits_per_frame;
62
 
static size_t chunk_bytes;
63
 
static int chunk_size = -1;
64
 
 
65
 
//---------------------------------------------------------
66
 
//   xrun
67
 
//    playback write error handler
68
 
//---------------------------------------------------------
69
 
 
70
 
void xrun(snd_pcm_t* handle)
71
 
      {
72
 
      snd_pcm_status_t *status;
73
 
      int res;
74
 
 
75
 
      snd_pcm_status_alloca(&status);
76
 
      if ((res = snd_pcm_status(handle, status))<0) {
77
 
            printf("status error: %s", snd_strerror(res));
78
 
            exit(EXIT_FAILURE);
79
 
            }
80
 
      int state = snd_pcm_status_get_state(status);
81
 
      if (state == SND_PCM_STATE_XRUN) {
82
 
            struct timeval now, diff, tstamp;
83
 
            gettimeofday(&now, 0);
84
 
            snd_pcm_status_get_trigger_tstamp(status, &tstamp);
85
 
            timersub(&now, &tstamp, &diff);
86
 
            if (debugMsg)
87
 
                  fprintf(stderr, "xrun >= %.3f ms\n", diff.tv_sec * 1000 + diff.tv_usec / 1000.0);
88
 
            if ((res = snd_pcm_prepare(handle))<0) {
89
 
                  printf("xrun: prepare error: %s", snd_strerror(res));
90
 
                  exit(EXIT_FAILURE);
91
 
                  }
92
 
            return;     // ok, data should be accepted again
93
 
            }
94
 
      else {
95
 
            printf("ALSA xrun: read/write error in state %d\n", state);
96
 
            }
97
 
      }
98
 
 
99
 
//---------------------------------------------------------
100
 
//   setParams
101
 
//---------------------------------------------------------
102
 
 
103
 
static void setParams(snd_pcm_t* handle)
104
 
      {
105
 
      //-----------------------------------------------
106
 
      //   HW parameters
107
 
 
108
 
      snd_pcm_hw_params_t* hwparams;
109
 
      snd_pcm_hw_params_alloca(&hwparams);
110
 
      int err = snd_pcm_hw_params_any(handle, hwparams);
111
 
      if (err < 0) {
112
 
            printf("Broken configuration for this PCM: no configurations available");
113
 
            exit(EXIT_FAILURE);
114
 
            }
115
 
 
116
 
      err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
117
 
      if (err < 0) {
118
 
            printf("ALSA: Access type not available");
119
 
            exit(EXIT_FAILURE);
120
 
            }
121
 
 
122
 
      err = snd_pcm_hw_params_set_format(handle, hwparams, SND_PCM_FORMAT_S16_LE);
123
 
      if (err < 0) {
124
 
            printf("ALSA: Sample format non available");
125
 
            exit(EXIT_FAILURE);
126
 
            }
127
 
      err = snd_pcm_hw_params_set_channels(handle, hwparams, 2);
128
 
      if (err < 0) {
129
 
            printf("ALSA: Channels count non available");
130
 
            exit(EXIT_FAILURE);
131
 
            }
132
 
 
133
 
      snd_pcm_hw_params_set_rate_near(handle, hwparams, sampleRate, 0);
134
 
 
135
 
      //
136
 
      // buffer
137
 
      //
138
 
// war 4
139
 
      buffer_time = snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, segmentSize*3);
140
 
      buffer_time = snd_pcm_hw_params_set_period_size_near(handle, hwparams, segmentSize, 0);
141
 
 
142
 
      err = snd_pcm_hw_params(handle, hwparams);
143
 
      if (err < 0) {
144
 
            printf("Unable to install hw params:");
145
 
            exit(EXIT_FAILURE);
146
 
            }
147
 
      chunk_size      = snd_pcm_hw_params_get_period_size(hwparams, 0);
148
 
      int buffer_size = snd_pcm_hw_params_get_buffer_size(hwparams);
149
 
 
150
 
// printf("segment %d chunk %d, buffer %d\n", segmentSize, chunk_size, buffer_size);
151
 
 
152
 
      if (chunk_size == int(buffer_size)) {
153
 
            printf("Can't use period equal to buffer size (%u == %u)", chunk_size, buffer_size);
154
 
            exit(EXIT_FAILURE);
155
 
            }
156
 
 
157
 
      //-----------------------------------------------
158
 
      //   SW parameters
159
 
 
160
 
      snd_pcm_sw_params_t *swparams;
161
 
      snd_pcm_sw_params_alloca(&swparams);
162
 
      snd_pcm_sw_params_current(handle, swparams);
163
 
      int xfer_align = snd_pcm_sw_params_get_xfer_align(swparams);
164
 
      err = snd_pcm_sw_params_set_sleep_min(handle, swparams, 0);
165
 
      size_t n;
166
 
      if (avail_min < 0)
167
 
            n = chunk_size;
168
 
      else
169
 
            n = int (snd_pcm_hw_params_get_rate(hwparams, 0) * (double) avail_min / 1000000);
170
 
      snd_pcm_sw_params_set_avail_min(handle, swparams, n);
171
 
      snd_pcm_sw_params_set_xfer_align(handle, swparams, xfer_align);
172
 
      if (snd_pcm_sw_params(handle, swparams) < 0) {
173
 
            printf("unable to install sw params:");
174
 
            exit(EXIT_FAILURE);
175
 
            }
176
 
 
177
 
      bits_per_sample = snd_pcm_format_physical_width(SND_PCM_FORMAT_S16_LE);
178
 
      bits_per_frame  = bits_per_sample * 2; // 2=channels
179
 
      chunk_bytes     = chunk_size * bits_per_frame / 8;
180
 
 
181
 
//      printf("bits/frame %d,  real chunk_size = %i buffer %d, chunk %d\n",
182
 
//         bits_per_frame, chunk_size, buffer_size, chunk_size);
183
 
      }
184
 
 
185
 
//---------------------------------------------------------
186
 
//   open
187
 
//---------------------------------------------------------
188
 
 
189
 
QString AlsaAudioDevice::open(int rw)
190
 
      {
191
 
      int openFlags = SND_PCM_NONBLOCK;
192
 
 
193
 
      //---------------------------------------------------
194
 
      //  setup playback stream
195
 
      //---------------------------------------------------
196
 
 
197
 
      if (rw & 1) {
198
 
            snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
199
 
            int err = snd_pcm_open(&playbackHandle, "default", stream, openFlags);
200
 
        if (err < 0)
201
 
                return QString("Alsa open: ")+QString(snd_strerror(err));
202
 
            setParams(playbackHandle);
203
 
            int res = snd_pcm_prepare(playbackHandle);
204
 
            if (res <0) {
205
 
                  printf("prepare error: %s", snd_strerror(res));
206
 
                  exit(EXIT_FAILURE);
207
 
                  }
208
 
            }
209
 
      if (rw & 2) {
210
 
            snd_pcm_stream_t stream = SND_PCM_STREAM_CAPTURE;
211
 
            int err = snd_pcm_open(&captureHandle, "default", stream, openFlags);
212
 
        if (err < 0)
213
 
                return QString("Alsa open: ")+QString(snd_strerror(err));
214
 
            setParams(captureHandle);
215
 
            }
216
 
      return QString("OK");
217
 
      }
218
 
 
219
 
//---------------------------------------------------------
220
 
//   read
221
 
//---------------------------------------------------------
222
 
 
223
 
int AlsaAudioDevice::read(unsigned char* buffer, int frames)
224
 
      {
225
 
      if (captureHandle == 0)
226
 
            return 0;
227
 
      int n = 0;
228
 
      while (frames > 0) {
229
 
            int rv = snd_pcm_readi(captureHandle, buffer, frames);
230
 
            if (rv == -EAGAIN || (rv >= 0 && rv < frames))
231
 
                  snd_pcm_wait(captureHandle, 1000);
232
 
            else if (rv == -EPIPE)
233
 
                  xrun(captureHandle);
234
 
            else if (rv < 0) {
235
 
                  fprintf(stderr, "AlsaAudioDevice: read(0x%x, 0x%x, %d+%d) failed: %s\n",
236
 
                    unsigned(captureHandle), unsigned(buffer), frames, n, snd_strerror(rv));
237
 
                  return rv;
238
 
                  }
239
 
            else {
240
 
                  n      += rv;
241
 
                  frames -= rv;
242
 
                  buffer   += rv * bits_per_frame / 8;
243
 
                  }
244
 
            }
245
 
      return n;
246
 
      }
247
 
 
248
 
//---------------------------------------------------------
249
 
//   start
250
 
//---------------------------------------------------------
251
 
 
252
 
void AlsaAudioDevice::start() const
253
 
      {
254
 
#if 0
255
 
      int err;
256
 
      if (captureHandle) {
257
 
              err = snd_pcm_start(captureHandle);
258
 
            if (err == -EPIPE)
259
 
                  xrun(playbackHandle);
260
 
            else if (err < 0)
261
 
                    printf("Alsa capture go: %s\n", snd_strerror(err));
262
 
            }
263
 
      if (playbackHandle) {
264
 
              int err = snd_pcm_start(playbackHandle);
265
 
            if (err == -EPIPE)
266
 
                  xrun(playbackHandle);
267
 
            else if (err < 0) {
268
 
                    printf("Alsa playback go: %s\n", snd_strerror(err));
269
 
                  }
270
 
            }
271
 
#endif
272
 
      }
273
 
 
274
 
//---------------------------------------------------------
275
 
//   stop
276
 
//---------------------------------------------------------
277
 
 
278
 
void AlsaAudioDevice::stop() const
279
 
      {
280
 
      if (captureHandle) {
281
 
              int err = snd_pcm_pause(captureHandle, 1);
282
 
            if (err < 0)
283
 
                    printf("Alsa capture pause: %s\n", snd_strerror(err));
284
 
            }
285
 
      if (playbackHandle) {
286
 
              int err = snd_pcm_pause(playbackHandle, 1);
287
 
            if (err < 0)
288
 
                    printf("Alsa playback pause: %s\n", snd_strerror(err));
289
 
            }
290
 
      }
291
 
 
292
 
//---------------------------------------------------------
293
 
//   write
294
 
//---------------------------------------------------------
295
 
 
296
 
int AlsaAudioDevice::write(const unsigned char* buffer, int n)
297
 
      {
298
 
      if (playbackHandle == 0)
299
 
            return 0;
300
 
      int result    = 0;
301
 
      int framesize = bits_per_frame/8;
302
 
      while (n > 0) {
303
 
            int r = snd_pcm_writei(playbackHandle, buffer, n);
304
 
            if (r == -EAGAIN) {
305
 
                  snd_pcm_wait(playbackHandle, 1000);
306
 
                  continue;
307
 
                  }
308
 
            else if (r == -EPIPE) {
309
 
                  xrun(playbackHandle);
310
 
                  continue;
311
 
                  }
312
 
            else if (r < 0) {
313
 
                  fprintf(stderr, "AlsaAudioDevice: write(0x%x, 0x%x, %d) failed: %s\n",
314
 
                    unsigned(playbackHandle), unsigned(buffer), n, snd_strerror(r));
315
 
                  exit(1);
316
 
                  }
317
 
            result += r;
318
 
            buffer += r * framesize;
319
 
            n -= r;
320
 
            if (n)
321
 
                  snd_pcm_wait(playbackHandle, 1000);
322
 
            }
323
 
      return result;
324
 
      }
325
 
 
326
 
//---------------------------------------------------------
327
 
//   selectwfd
328
 
//---------------------------------------------------------
329
 
 
330
 
int AlsaAudioDevice::selectwfd() const
331
 
      {
332
 
      if (playbackHandle) {
333
 
            int n = snd_pcm_poll_descriptors_count(playbackHandle);
334
 
            if (n != 1) {
335
 
                  printf("AlsaAudioDevice:selectwfd: not supported\n");
336
 
                  abort();
337
 
                  }
338
 
            struct pollfd fd[n];
339
 
            snd_pcm_poll_descriptors(playbackHandle, fd, n);
340
 
            return fd[0].fd;
341
 
            }
342
 
      return -1;
343
 
      }
344
 
 
345
 
//---------------------------------------------------------
346
 
//   selectrfd
347
 
//---------------------------------------------------------
348
 
 
349
 
int AlsaAudioDevice::selectrfd() const
350
 
      {
351
 
      if (captureHandle) {
352
 
            int n = snd_pcm_poll_descriptors_count(captureHandle);
353
 
            if (n != 1) {
354
 
                  printf("AlsaAudioDevice:selectrfd: not supported\n");
355
 
                  abort();
356
 
                  }
357
 
            struct pollfd fd[n];
358
 
            snd_pcm_poll_descriptors(captureHandle, fd, n);
359
 
            return fd[0].fd;
360
 
            }
361
 
      return -1;
362
 
      }
363
 
 
364
 
//---------------------------------------------------------
365
 
//   close
366
 
//---------------------------------------------------------
367
 
 
368
 
void AlsaAudioDevice::close()
369
 
      {
370
 
      if (captureHandle) {
371
 
              int err = snd_pcm_close(captureHandle);
372
 
            if (err < 0)
373
 
                    printf("Alsa close capture: %s\n", snd_strerror(err));
374
 
            }
375
 
      if (playbackHandle) {
376
 
              int err = snd_pcm_close(playbackHandle);
377
 
            if (err < 0)
378
 
                    printf("Alsa close playback: %s\n", snd_strerror(err));
379
 
            }
380
 
      captureHandle  = 0;
381
 
      playbackHandle = 0;
382
 
      }
383
 
 
384
 
//---------------------------------------------------------
385
 
//   initAlsaAudio
386
 
//    collect infos about audio devices
387
 
//    return true if no soundcard found
388
 
//---------------------------------------------------------
389
 
 
390
 
bool initAlsaAudio()
391
 
      {
392
 
      int card = -1;
393
 
      int err;
394
 
      if (snd_card_next(&card) < 0 || card < 0) {
395
 
            fprintf(stderr, "ALSA: no soundcard found\n");
396
 
            return true;
397
 
            }
398
 
      snd_ctl_card_info_t* info;
399
 
      snd_ctl_card_info_alloca(&info);
400
 
      snd_pcm_info_t* pcminfo;
401
 
      snd_pcm_info_alloca(&pcminfo);
402
 
      while (card >= 0) {
403
 
            snd_ctl_t* handle;
404
 
            char name[32];
405
 
            sprintf(name, "hw:%d", card);
406
 
/*??*/      if ((err = snd_ctl_open(&handle, name, SND_CTL_NONBLOCK)) < 0) {
407
 
                  fprintf(stderr, "ALSA: control open (%d): %s\n",
408
 
                     card, snd_strerror(err));
409
 
                  continue;
410
 
                  }
411
 
 
412
 
            if ((err = snd_ctl_card_info(handle, info)) < 0) {
413
 
                  fprintf(stderr, "ALSA: control hardware info %d: %s\n",
414
 
                     card, snd_strerror(err));
415
 
                  snd_ctl_close(handle);
416
 
                  continue;
417
 
                  }
418
 
            int dev = -1;
419
 
            for (;;) {
420
 
                  if (snd_ctl_pcm_next_device(handle, &dev) < 0)
421
 
                        fprintf(stderr, "ALSA: pcm next device: %s\n",
422
 
                           snd_strerror(err));
423
 
                  if (dev < 0)
424
 
                        break;
425
 
                  int flags = 0;
426
 
                  snd_pcm_info_set_device(pcminfo, dev);
427
 
                  snd_pcm_info_set_subdevice(pcminfo, 0);
428
 
                  snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_PLAYBACK);
429
 
                  if (snd_ctl_pcm_info(handle, pcminfo) >= 0)
430
 
                        flags |= 1;
431
 
                  snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_CAPTURE);
432
 
                  if (snd_ctl_pcm_info(handle, pcminfo) >= 0)
433
 
                        flags |= 2;
434
 
                  if (flags) {
435
 
                        const char* name = snd_pcm_info_get_name(pcminfo);
436
 
                        AudioDevice* d = new AlsaAudioDevice (card, dev, flags, QString(name));
437
 
                        audioDevices.add(d);
438
 
                        }
439
 
                  }
440
 
            snd_ctl_close(handle);
441
 
            if (snd_card_next(&card) < 0) {
442
 
                  fprintf(stderr, "ALSA: snd_card_next: %s\n",
443
 
                     snd_strerror(err));
444
 
                  break;
445
 
                  }
446
 
            }
447
 
      return false;
448
 
      }
449
 
#endif
450
 
#endif