~ubuntu-branches/ubuntu/hoary/kdemultimedia/hoary

« back to all changes in this revision

Viewing changes to kmidi/alsa_a.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Martin Schulze
  • Date: 2003-01-22 15:00:51 UTC
  • Revision ID: james.westby@ubuntu.com-20030122150051-uihwkdoxf15mi1tn
Tags: upstream-2.2.2
ImportĀ upstreamĀ versionĀ 2.2.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 
 
3
    TiMidity++ -- MIDI to WAVE converter and player
 
4
    Copyright (C) 1999 Masanao Izumo <mo@goice.co.jp>
 
5
    Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
 
6
 
 
7
    This program is free software; you can redistribute it and/or modify
 
8
    it under the terms of the GNU General Public License as published by
 
9
    the Free Software Foundation; either version 2 of the License, or
 
10
    (at your option) any later version.
 
11
 
 
12
    This program is distributed in the hope that it will be useful,
 
13
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
    GNU General Public License for more details.
 
16
 
 
17
    You should have received a copy of the GNU General Public License
 
18
    along with this program; if not, write to the Free Software
 
19
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
20
 
 
21
    linux_audio.c
 
22
 
 
23
    Functions to play sound on the VoxWare audio driver (Linux or FreeBSD)
 
24
 
 
25
*/
 
26
 
 
27
#ifdef AU_ALSA
 
28
 
 
29
#ifdef ORIG_TIMPP
 
30
#ifdef HAVE_CONFIG_H
 
31
#include "config.h"
 
32
#endif /* HAVE_CONFIG_H */
 
33
#define _GNU_SOURCE
 
34
#endif
 
35
 
 
36
#include <stdio.h>
 
37
#include <stdlib.h>
 
38
#include <unistd.h>
 
39
#include <fcntl.h>
 
40
 
 
41
#ifndef NO_STRING_H
 
42
#include <string.h>
 
43
#else
 
44
#include <strings.h>
 
45
#endif
 
46
 
 
47
/*ALSA header file*/
 
48
#ifdef __cplusplus
 
49
#undef __cplusplus
 
50
extern "C" {
 
51
#include <sys/asoundlib.h>
 
52
}
 
53
#define __cplusplus
 
54
#else
 
55
#include <sys/asoundlib.h>
 
56
#endif
 
57
 
 
58
#ifdef ORIG_TIMPP
 
59
#include "timidity.h"
 
60
#else
 
61
#include "config.h"
 
62
#endif
 
63
 
 
64
#include "common.h"
 
65
#include "output.h"
 
66
#include "controls.h"
 
67
/* #include "timer.h" */
 
68
#include "instrum.h"
 
69
#include "playmidi.h"
 
70
/* #include "miditrace.h" */
 
71
 
 
72
static int open_output(void); /* 0=success, 1=warning, -1=fatal error */
 
73
static void close_output(void);
 
74
#ifdef ORIG_TIMPP
 
75
static int output_data(char *buf, int32 nbytes);
 
76
static int acntl(int request, void *arg);
 
77
#else
 
78
static void output_data(int32 *buf, uint32 count);
 
79
static int driver_output_data(unsigned char *buf, uint32 count);
 
80
static void flush_output(void);
 
81
static void purge_output(void);
 
82
static int output_count(uint32 ct);
 
83
#endif
 
84
static int total_bytes, output_counter;
 
85
 
 
86
/* export the playback mode */
 
87
 
 
88
#define dpm alsa_play_mode
 
89
 
 
90
#ifdef ORIG_TIMPP
 
91
PlayMode dpm = {
 
92
  DEFAULT_RATE, PE_16BIT|PE_SIGNED, PF_PCM_STREAM|PF_CAN_TRACE,
 
93
  -1,
 
94
  {0}, /* default: get all the buffer fragments you can */
 
95
  "ALSA pcm device", 's',
 
96
  "/dev/snd/pcm00",
 
97
  open_output,
 
98
  close_output,
 
99
  output_data,
 
100
  acntl
 
101
};
 
102
#else
 
103
#define PE_ALAW       0x20
 
104
PlayMode dpm = {
 
105
  DEFAULT_RATE, PE_16BIT|PE_SIGNED,
 
106
  -1,
 
107
  {0}, /* default: get all the buffer fragments you can */
 
108
  "ALSA pcm device", 's',
 
109
  "/dev/snd/pcm00",
 
110
  open_output,
 
111
  close_output,
 
112
  output_data,
 
113
  driver_output_data,
 
114
  flush_output,
 
115
  purge_output,
 
116
  output_count
 
117
};
 
118
#endif
 
119
 
 
120
/*************************************************************************/
 
121
/* We currently only honor the PE_MONO bit, the sample rate, and the
 
122
   number of buffer fragments. We try 16-bit signed data first, and
 
123
   then 8-bit unsigned if it fails. If you have a sound device that
 
124
   can't handle either, let me know. */
 
125
 
 
126
 
 
127
/*ALSA PCM handler*/
 
128
static snd_pcm_t* handle = NULL;
 
129
static int card = 0;
 
130
static int device = 0;
 
131
static int setup_frags = 0;
 
132
static int setup_frag_size = 0;
 
133
 
 
134
void alsa_tell(int *fragsize, int *fragstotal)
 
135
{
 
136
  *fragsize = setup_frag_size;
 
137
  *fragstotal = setup_frags;
 
138
}
 
139
 
 
140
static void error_report (int snd_error)
 
141
{
 
142
  ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s",
 
143
            dpm.name, snd_strerror (snd_error));
 
144
}
 
145
 
 
146
/*return value == 0 sucess
 
147
               == -1 fails
 
148
 */
 
149
static int check_sound_cards (int* card__, int* device__,
 
150
                              const int32 extra_param[5])
 
151
{
 
152
  /*Search sound cards*/
 
153
  struct snd_ctl_hw_info ctl_hw_info;
 
154
  snd_pcm_info_t pcm_info;
 
155
  snd_ctl_t* ctl_handle;
 
156
  const char* env_sound_card = getenv ("TIMIDITY_SOUND_CARD");
 
157
  const char* env_pcm_device = getenv ("TIMIDITY_PCM_DEVICE");
 
158
  int tmp;
 
159
 
 
160
  /*specify card*/
 
161
  *card__ = 0;
 
162
  if (env_sound_card != NULL)
 
163
    *card__ = atoi (env_sound_card);
 
164
  /*specify device*/
 
165
  *device__ = 0;
 
166
  if (env_pcm_device != NULL)
 
167
    *device__ = atoi (env_pcm_device);
 
168
  
 
169
  tmp = snd_cards ();
 
170
  if (tmp == 0)
 
171
    {
 
172
      ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "No sound card found.");
 
173
      return -1;
 
174
    }
 
175
  if (tmp < 0)
 
176
    {
 
177
      error_report (tmp);
 
178
      return -1;
 
179
    }
 
180
  
 
181
  if (*card__ < 0 || *card__ >= tmp)
 
182
    {
 
183
      ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "There is %d sound cards."
 
184
                " %d is invalid sound card. assuming 0.",
 
185
                tmp, *card__);
 
186
      *card__ = 0;
 
187
    }
 
188
 
 
189
  tmp = snd_ctl_open (&ctl_handle, *card__);
 
190
  if (tmp != 0)
 
191
    {
 
192
      error_report (tmp);
 
193
      return -1;
 
194
    }
 
195
 
 
196
  /*check whether sound card has pcm device(s)*/
 
197
  tmp = snd_ctl_hw_info (ctl_handle, & ctl_hw_info);
 
198
  if (ctl_hw_info.pcmdevs == 0)
 
199
    {
 
200
      ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
 
201
                "%d-th sound card(%s) has no pcm device",
 
202
                ctl_hw_info.longname, *card__);
 
203
      snd_ctl_close (ctl_handle);
 
204
      return -1;
 
205
    }
 
206
  
 
207
  if (*device__ < 0 || *device__ >= ctl_hw_info.pcmdevs)
 
208
    {
 
209
      ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
 
210
                "%d-th sound cards(%s) has %d pcm device(s)."
 
211
                " %d is invalid pcm device. assuming 0.",
 
212
                *card__, ctl_hw_info.longname, ctl_hw_info.pcmdevs, *device__);
 
213
      *device__ = 0;
 
214
      
 
215
      if (ctl_hw_info.pcmdevs == 0)
 
216
        {/*sound card has no pcm devices*/
 
217
          snd_ctl_close (ctl_handle);
 
218
          return -1;
 
219
        }
 
220
    }
 
221
 
 
222
  /*check whether pcm device is able to playback*/
 
223
  tmp = snd_ctl_pcm_info(ctl_handle, *device__, &pcm_info);
 
224
  if (tmp != 0)
 
225
    {
 
226
      error_report (tmp);
 
227
      snd_ctl_close (ctl_handle);
 
228
      return -1;
 
229
    }
 
230
  
 
231
  if ((pcm_info.flags & SND_PCM_INFO_PLAYBACK) == 0)
 
232
    {
 
233
      ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
 
234
                "%d-th sound cards(%s), device=%d, "
 
235
                "type=%d, flags=%d, id=%s, name=%s,"
 
236
                " does not support playback",
 
237
                *card__, ctl_hw_info.longname, ctl_hw_info.pcmdevs,
 
238
                pcm_info.type, pcm_info.flags, pcm_info.id, pcm_info.name);
 
239
      snd_ctl_close (ctl_handle);
 
240
      return -1;
 
241
    }
 
242
  
 
243
  tmp = snd_ctl_close (ctl_handle);
 
244
  if (tmp != 0)
 
245
    {
 
246
      error_report (tmp);
 
247
      return -1;
 
248
    }
 
249
 
 
250
  return 0;
 
251
}
 
252
 
 
253
/*return value == 0 sucess
 
254
               == 1 warning
 
255
               == -1 fails
 
256
 */
 
257
static int set_playback_info (void* handle__,
 
258
                              uint32* encoding__, uint32* rate__,
 
259
                              const int32 extra_param[5])
 
260
{
 
261
  int ret_val = 0;
 
262
  const uint32 orig_encoding = *encoding__;
 
263
  const uint32 orig_rate = *rate__;
 
264
  /* snd_pcm_playback_info_t playback_info; */
 
265
  snd_pcm_channel_info_t playback_info;
 
266
  snd_pcm_format_t pcm_format;
 
267
  /*
 
268
  struct snd_pcm_playback_params playback_params;
 
269
  struct snd_pcm_playback_status playback_status;
 
270
  */
 
271
  struct snd_pcm_channel_params playback_params;
 
272
  struct snd_pcm_channel_status playback_status;
 
273
  struct snd_pcm_channel_setup setup;
 
274
  int tmp;
 
275
 
 
276
//fprintf(stderr,"setting playback info\n");
 
277
  memset (&pcm_format, 0, sizeof (pcm_format));
 
278
  pcm_format.interleave = 1;
 
279
 
 
280
  memset (&playback_params, 0, sizeof (playback_params));
 
281
  playback_params.channel = SND_PCM_CHANNEL_PLAYBACK;
 
282
  playback_params.mode = SND_PCM_MODE_BLOCK;
 
283
 
 
284
  memset(&playback_info, 0, sizeof(playback_info));
 
285
  playback_info.channel = SND_PCM_CHANNEL_PLAYBACK;
 
286
 
 
287
  tmp = snd_pcm_plugin_info (handle__, &playback_info);
 
288
//fprintf(stderr,"tmp = %d from snd_pcm_channel_info\n",tmp);
 
289
  if (tmp != 0)
 
290
    {
 
291
      error_report (tmp);
 
292
      return -1;
 
293
    }
 
294
 
 
295
  /*check sample bit*/
 
296
#if 0
 
297
  if ((playback_info.flags & SND_PCM_PINFO_8BITONLY) != 0)
 
298
    *encoding__ &= ~PE_16BIT;/*force 8bit samles*/
 
299
  if ((playback_info.flags & SND_PCM_PINFO_16BITONLY) != 0)
 
300
    *encoding__ |= PE_16BIT;/*force 16bit samples*/
 
301
#endif
 
302
 
 
303
  /*check rate*/
 
304
  if (playback_info.min_rate > *rate__)
 
305
    *rate__ = playback_info.min_rate;
 
306
  if (playback_info.max_rate < *rate__)
 
307
    *rate__ = playback_info.max_rate;
 
308
  pcm_format.rate = *rate__;
 
309
 
 
310
  /*check channels*/
 
311
  if ((*encoding__ & PE_MONO) != 0 && playback_info.min_voices > 1)
 
312
    *encoding__ &= ~PE_MONO;
 
313
  if ((*encoding__ & PE_MONO) == 0 && playback_info.max_voices < 2)
 
314
    *encoding__ |= PE_MONO;
 
315
 
 
316
  if ((*encoding__ & PE_MONO) != 0)
 
317
    pcm_format.voices = 1;/*mono*/
 
318
  else
 
319
    pcm_format.voices = 2;/*stereo*/
 
320
 
 
321
 
 
322
  /*check format*/
 
323
  if ((*encoding__ & PE_16BIT) != 0)
 
324
    {/*16bit*/
 
325
      if ((playback_info.formats & SND_PCM_FMT_S16_LE) != 0)
 
326
        {
 
327
          pcm_format.format = SND_PCM_SFMT_S16_LE;
 
328
          *encoding__ |= PE_SIGNED;
 
329
        }
 
330
      else if ((playback_info.formats & SND_PCM_FMT_U16_LE) != 0)
 
331
        {
 
332
          pcm_format.format = SND_PCM_SFMT_U16_LE;
 
333
          *encoding__ &= ~PE_SIGNED;
 
334
        }
 
335
      else if ((playback_info.formats & SND_PCM_FMT_S16_BE) != 0)
 
336
        {
 
337
          pcm_format.format = SND_PCM_SFMT_S16_BE;
 
338
          *encoding__ |= PE_SIGNED;
 
339
        }
 
340
      else if ((playback_info.formats & SND_PCM_FMT_U16_BE) != 0)
 
341
        {
 
342
          pcm_format.format = SND_PCM_SFMT_U16_LE;
 
343
          *encoding__ &= ~PE_SIGNED;
 
344
        }
 
345
      else
 
346
        {
 
347
          ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
 
348
                    "%s doesn't support 16 bit sample width",
 
349
                    dpm.name);
 
350
          return -1;
 
351
        }
 
352
    }
 
353
  else
 
354
    {/*8bit*/
 
355
      if ((playback_info.formats & SND_PCM_FMT_U8) != 0)
 
356
        {
 
357
          pcm_format.format = SND_PCM_SFMT_U8;
 
358
          *encoding__ &= ~PE_SIGNED;
 
359
        }
 
360
      else if ((playback_info.formats & SND_PCM_FMT_S8) != 0)
 
361
        {
 
362
          pcm_format.format = SND_PCM_SFMT_U16_LE;
 
363
          *encoding__ |= PE_SIGNED;
 
364
        }
 
365
      else
 
366
        {
 
367
          ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
 
368
                    "%s doesn't support 8 bit sample width",
 
369
                    dpm.name);
 
370
          return -1;
 
371
        }
 
372
    }
 
373
  memcpy(&playback_params.format, &pcm_format, sizeof(pcm_format));
 
374
 
 
375
#if 0
 
376
  tmp = snd_pcm_channel_format (handle__, &pcm_format);
 
377
  if (tmp != 0)
 
378
    {
 
379
      error_report (tmp);
 
380
      return -1;
 
381
    }
 
382
#endif
 
383
 
 
384
  /*check result of snd_pcm_channel_format*/
 
385
  if ((*encoding__ & PE_16BIT) != (orig_encoding & PE_16BIT ))
 
386
    {
 
387
      ctl->cmsg (CMSG_WARNING, VERB_VERBOSE,
 
388
                 "Sample width adjusted to %d bits",
 
389
                 ((*encoding__ & PE_16BIT) != 0)? 16:8);
 
390
      ret_val = 1;
 
391
    }
 
392
  if (((pcm_format.voices == 1)? PE_MONO:0) != (orig_encoding & PE_MONO))
 
393
    {
 
394
      ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, "Sound adjusted to %sphonic",
 
395
                ((*encoding__ & PE_MONO) != 0)? "mono" : "stereo");
 
396
      ret_val = 1;
 
397
    }
 
398
  
 
399
  /* Set buffer fragments (in extra_param[0]) */
 
400
#if 0
 
401
  tmp = AUDIO_BUFFER_BITS;
 
402
  if (!(*encoding__ & PE_MONO))
 
403
    tmp++;
 
404
  if (*encoding__ & PE_16BIT)
 
405
    tmp++;
 
406
  tmp++;
 
407
  playback_params.buf.block.frag_size = (1 << tmp);
 
408
#endif
 
409
  tmp = AUDIO_BUFFER_SIZE;
 
410
  if (!(*encoding__ & PE_MONO))
 
411
    tmp *=2;
 
412
  if (*encoding__ & PE_16BIT)
 
413
    tmp *=2;
 
414
  playback_params.buf.block.frag_size = tmp;
 
415
//fprintf(stderr,"frag_size %d\n", playback_params.buf.block.frag_size);
 
416
 
 
417
  if (extra_param[0] == 0)
 
418
    playback_params.buf.block.frags_max = 7;/*default value. What's value is apporpriate?*/
 
419
  else
 
420
    playback_params.buf.block.frags_max = extra_param[0];
 
421
 
 
422
#if 0
 
423
  if (extra_param[0] == 0)
 
424
    playback_params.fragments_max = 15;/*default value. What's value is apporpriate?*/
 
425
  else
 
426
    playback_params.fragments_max = extra_param[0];
 
427
#endif
 
428
  playback_params.buf.block.frags_min = 1;
 
429
  snd_pcm_plugin_flush(handle__, SND_PCM_CHANNEL_PLAYBACK);
 
430
 
 
431
  playback_params.start_mode = SND_PCM_START_FULL;
 
432
  playback_params.stop_mode = SND_PCM_STOP_STOP;
 
433
  //playback_params.stop_mode = SND_PCM_STOP_ROLLOVER;
 
434
 
 
435
  tmp = snd_pcm_channel_params (handle__, &playback_params);
 
436
 
 
437
//fprintf(stderr,"tmp = %d from snd_pcm_channel_params\n",tmp);
 
438
  if (tmp != 0)
 
439
    {
 
440
      ctl->cmsg(CMSG_WARNING, VERB_NORMAL,
 
441
                "%s doesn't support buffer fragments"
 
442
                ":request size=%d, max=%d, room=%d\n",
 
443
                dpm.name,
 
444
                playback_params.buf.block.frag_size,
 
445
                playback_params.buf.block.frags_max,
 
446
                playback_params.buf.block.frags_min);
 
447
      ret_val =1;
 
448
    }
 
449
 
 
450
 
 
451
  if (snd_pcm_plugin_prepare(handle__, SND_PCM_CHANNEL_PLAYBACK) < 0) {
 
452
      fprintf(stderr, "unable to prepare channel\n");
 
453
      return -1;
 
454
  } 
 
455
 
 
456
  memset(&setup, 0, sizeof(setup));
 
457
  setup.channel = SND_PCM_CHANNEL_PLAYBACK;
 
458
  setup.mode = SND_PCM_MODE_BLOCK;
 
459
  if (snd_pcm_plugin_setup(handle__, &setup) < 0) {
 
460
      fprintf(stderr, "unable to obtain setup\n");
 
461
      return -1;
 
462
  }
 
463
  setup_frags = setup.buf.block.frags;
 
464
  setup_frag_size = setup.buf.block.frag_size;
 
465
 
 
466
//fprintf(stderr, "setup frags = %d\n", setup.buf.block.frags);
 
467
//fprintf(stderr, "setup frag_size = %d\n", setup.buf.block.frag_size);
 
468
 
 
469
  if(snd_pcm_plugin_status(handle__, &playback_status) == 0)
 
470
    {
 
471
      if (setup.format.rate != orig_rate)
 
472
        {
 
473
          ctl->cmsg(CMSG_WARNING, VERB_VERBOSE,
 
474
                    "Output rate adjusted to %d Hz (requested %d Hz)",
 
475
                    setup.format.rate, orig_rate);
 
476
          dpm.rate = setup.format.rate;
 
477
          ret_val = 1;
 
478
        }
 
479
      total_bytes = playback_status.count;
 
480
    }
 
481
  else
 
482
    total_bytes = -1; /* snd_pcm_channel_status fails */
 
483
 
 
484
  return ret_val;
 
485
}
 
486
 
 
487
static int open_output(void)
 
488
{
 
489
  int tmp, warnings=0;
 
490
  int ret;
 
491
 
 
492
  tmp = check_sound_cards (&card, &device, dpm.extra_param);
 
493
  if (tmp != 0)
 
494
    return -1;
 
495
 
 
496
//fprintf(stderr,"using card %d, device %d\n", card, device);
 
497
  /* Open the audio device */
 
498
  ret = snd_pcm_open (&handle, card, device,
 
499
        SND_PCM_OPEN_PLAYBACK|SND_PCM_OPEN_NONBLOCK);
 
500
//  ret = snd_pcm_open (&handle, card, device, SND_PCM_OPEN_PLAYBACK);
 
501
//fprintf(stderr,"ret was %d\n", ret);
 
502
 
 
503
  if (ret != 0)
 
504
    {
 
505
      ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s",
 
506
                dpm.name, snd_strerror (ret));
 
507
      return -1;
 
508
    }
 
509
 
 
510
  /* They can't mean these */
 
511
  dpm.encoding &= ~(PE_ULAW|PE_ALAW|PE_BYTESWAP);
 
512
  warnings = set_playback_info (handle, &dpm.encoding, &dpm.rate,
 
513
                                dpm.extra_param);
 
514
  if (warnings == -1)
 
515
    {
 
516
      close_output ();
 
517
      return -1;
 
518
    }
 
519
 
 
520
  dpm.fd = snd_pcm_file_descriptor (handle, SND_PCM_CHANNEL_PLAYBACK);
 
521
  output_counter = 0;
 
522
  return warnings;
 
523
}
 
524
 
 
525
static void close_output(void)
 
526
{
 
527
  int ret;
 
528
  
 
529
  if (handle == NULL)
 
530
    return;
 
531
  
 
532
  ret = snd_pcm_close (handle);
 
533
  if (ret != 0)
 
534
    error_report (ret);
 
535
  handle = NULL;
 
536
  
 
537
  dpm.fd = -1;
 
538
}
 
539
 
 
540
#ifdef ORIG_TIMPP
 
541
static int output_data(char *buf, int32 nbytes)
 
542
{
 
543
    int n;
 
544
 
 
545
    while(nbytes > 0)
 
546
    {
 
547
        n = snd_pcm_plugin_write(handle, buf, nbytes);
 
548
        if(n == -1)
 
549
        {
 
550
            ctl->cmsg(CMSG_WARNING, VERB_DEBUG,
 
551
                      "%s: %s", dpm.name, strerror(errno));
 
552
            if(errno == EWOULDBLOCK)
 
553
                continue;
 
554
            return -1;
 
555
        }
 
556
        buf += n;
 
557
        nbytes -= n;
 
558
        output_counter += n;
 
559
    }
 
560
 
 
561
    return 0;
 
562
}
 
563
#else
 
564
 
 
565
void playback_write_error(void)
 
566
{
 
567
        snd_pcm_channel_status_t status;
 
568
        
 
569
        memset(&status, 0, sizeof(status));
 
570
        status.channel = SND_PCM_CHANNEL_PLAYBACK;
 
571
        if (snd_pcm_plugin_status(handle, &status)<0) {
 
572
                fprintf(stderr, "playback channel status error\n");
 
573
                exit(1);
 
574
        }
 
575
        if (status.status == SND_PCM_STATUS_UNDERRUN) {
 
576
                //printf("underrun at position %u!!!\n", status.scount);
 
577
                if (snd_pcm_plugin_prepare(handle, SND_PCM_CHANNEL_PLAYBACK)<0) {
 
578
                        fprintf(stderr, "underrun: playback channel prepare error\n");
 
579
                        exit(1);
 
580
                }
 
581
                return;         /* ok, data should be accepted again */
 
582
        }
 
583
        if (status.status == SND_PCM_STATUS_READY) {
 
584
                if (snd_pcm_plugin_prepare(handle, SND_PCM_CHANNEL_PLAYBACK)<0) {
 
585
                        fprintf(stderr, "ready: playback channel prepare error\n");
 
586
                        exit(1);
 
587
                }
 
588
                return;         /* ok, data should be accepted again */
 
589
        }
 
590
        if (status.status == SND_PCM_STATUS_RUNNING) return;
 
591
        fprintf(stderr, "write error: status %d\n", status.status);
 
592
        exit(1);
 
593
}
 
594
 
 
595
 
 
596
 
 
597
static int driver_output_data(unsigned char *buf, uint32 count) {
 
598
        int ret_value;
 
599
//fprintf(stderr,"write %d bytes with buffer size %d\n",
 
600
//              count, AUDIO_BUFFER_SIZE);
 
601
  if (count < (uint32)setup_frag_size ) return 0;
 
602
  ret_value = snd_pcm_plugin_write(handle, buf, setup_frag_size);
 
603
  if (ret_value < 0) {
 
604
//fprintf(stderr,"ret_value = %d\n", ret_value);
 
605
    playback_write_error();       
 
606
    ret_value = 0;
 
607
  }
 
608
  return ret_value;
 
609
}
 
610
 
 
611
 
 
612
static int output_count(uint32 ct)
 
613
{
 
614
  struct snd_pcm_channel_status playback_status;
 
615
  int samples = -1;
 
616
  int samples_queued, samples_sent = (int)ct;
 
617
 
 
618
  samples = samples_sent = b_out_count();
 
619
 
 
620
  if (samples_sent) {
 
621
        if(snd_pcm_plugin_status(handle, &playback_status) != 0)
 
622
          return -1;
 
623
/* samples_queued is PM_REQ_GETFILLED */
 
624
      /* if (snd_pcm_channel_status(handle, &playback_status) == 0) */
 
625
        samples_queued = playback_status.count;
 
626
      samples -= samples_queued;
 
627
  }
 
628
  if (!(dpm.encoding & PE_MONO)) samples >>= 1;
 
629
  if (dpm.encoding & PE_16BIT) samples >>= 1;
 
630
  return samples;
 
631
}
 
632
 
 
633
 
 
634
static void output_data(int32 *buf, uint32 count)
 
635
{
 
636
  int ocount;
 
637
 
 
638
  if (!(dpm.encoding & PE_MONO)) count*=2; /* Stereo samples */
 
639
  ocount = (int)count;
 
640
 
 
641
  if (ocount) {
 
642
    if (dpm.encoding & PE_16BIT)
 
643
      {
 
644
        /* Convert data to signed 16-bit PCM */
 
645
        s32tos16(buf, count);
 
646
        ocount *= 2;
 
647
      }
 
648
    else
 
649
      {
 
650
        /* Convert to 8-bit unsigned and write out. */
 
651
        s32tou8(buf, count);
 
652
      }
 
653
  }
 
654
 
 
655
  b_out(dpm.id_character, dpm.fd, (int *)buf, ocount);
 
656
}
 
657
 
 
658
 
 
659
static void flush_output(void)
 
660
{
 
661
  output_data(0, 0);
 
662
  snd_pcm_plugin_flush(handle, SND_PCM_CHANNEL_PLAYBACK);
 
663
}
 
664
 
 
665
static void purge_output(void)
 
666
{
 
667
  b_out(dpm.id_character, dpm.fd, 0, -1);
 
668
  snd_pcm_plugin_playback_drain(handle);
 
669
 
 
670
  if (snd_pcm_plugin_prepare(handle, SND_PCM_CHANNEL_PLAYBACK) < 0) {
 
671
      fprintf(stderr, "unable to prepare channel\n");
 
672
      exit (1);
 
673
  } 
 
674
 
 
675
//fprintf(stderr, "setup frags = %d\n", setup.buf.block.frags);
 
676
}
 
677
 
 
678
#endif
 
679
 
 
680
#ifdef ORIG_TIMPP
 
681
static int acntl(int request, void *arg)
 
682
{
 
683
    struct snd_pcm_playback_status playback_status;
 
684
    int i;
 
685
 
 
686
    switch(request)
 
687
    {
 
688
      case PM_REQ_GETQSIZ:
 
689
        if(total_bytes == -1)
 
690
          return -1;
 
691
        *((int *)arg) = total_bytes;
 
692
        return 0;
 
693
 
 
694
      case PM_REQ_GETFILLABLE:
 
695
        if(total_bytes == -1)
 
696
          return -1;
 
697
        if(snd_pcm_playback_status(handle, &playback_status) != 0)
 
698
          return -1;
 
699
        *((int *)arg) = playback_status.count;
 
700
        return 0;
 
701
 
 
702
      case PM_REQ_GETFILLED:
 
703
        if(total_bytes == -1)
 
704
          return -1;
 
705
        if(snd_pcm_playback_status(handle, &playback_status) != 0)
 
706
          return -1;
 
707
        *((int *)arg) = playback_status.queue;
 
708
        return 0;
 
709
 
 
710
      case PM_REQ_GETSAMPLES:
 
711
        if(total_bytes == -1)
 
712
          return -1;
 
713
        if(snd_pcm_playback_status(handle, &playback_status) != 0)
 
714
          return -1;
 
715
        i = output_counter - playback_status.queue;
 
716
        if(!(dpm.encoding & PE_MONO)) i >>= 1;
 
717
        if(dpm.encoding & PE_16BIT) i >>= 1;
 
718
        *((int *)arg) = i;
 
719
        return 0;
 
720
 
 
721
      case PM_REQ_DISCARD:
 
722
        if(snd_pcm_drain_playback (handle) != 0)
 
723
            return -1; /* error */
 
724
        output_counter = 0;
 
725
        return 0;
 
726
 
 
727
      case PM_REQ_FLUSH:
 
728
        if(snd_pcm_flush_playback(handle) != 0)
 
729
          return -1; /* error */
 
730
        output_counter = 0;
 
731
        return 0;
 
732
    }
 
733
    return -1;
 
734
}
 
735
#endif
 
736
#endif