sound.c 39.5 KB
Newer Older
Gerd Moellmann's avatar
Gerd Moellmann committed
1
/* sound.c -- sound support.
2
   Copyright (C) 1998-1999, 2001-2011 Free Software Foundation, Inc.
Gerd Moellmann's avatar
Gerd Moellmann committed
3 4 5

This file is part of GNU Emacs.

6
GNU Emacs is free software: you can redistribute it and/or modify
Gerd Moellmann's avatar
Gerd Moellmann committed
7
it under the terms of the GNU General Public License as published by
8 9
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gerd Moellmann's avatar
Gerd Moellmann committed
10 11 12 13 14 15 16

GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
17
along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
Gerd Moellmann's avatar
Gerd Moellmann committed
18 19 20 21

/* Written by Gerd Moellmann <gerd@gnu.org>.  Tested with Luigi's
   driver on FreeBSD 2.2.7 with a SoundBlaster 16.  */

22 23 24 25 26 27 28 29 30 31 32 33
/*
  Modified by Ben Key <Bkey1@tampabay.rr.com> to add a partial
  implementation of the play-sound specification for Windows.

  Notes:
  In the Windows implementation of play-sound-internal only the
  :file and :volume keywords are supported.  The :device keyword,
  if present, is ignored.  The :data keyword, if present, will
  cause an error to be generated.

  The Windows implementation of play-sound is implemented via the
  Win32 API functions mciSendString, waveOutGetVolume, and
34
  waveOutSetVolume which are exported by Winmm.dll.
35 36
*/

Gerd Moellmann's avatar
Gerd Moellmann committed
37 38 39 40
#include <config.h>

#if defined HAVE_SOUND

41
/* BEGIN: Common Includes */
Gerd Moellmann's avatar
Gerd Moellmann committed
42 43 44 45
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
46
#include <setjmp.h>
47 48 49
#include "lisp.h"
#include "dispextern.h"
#include "atimer.h"
50 51
#include <signal.h>
#include "syssignal.h"
52 53 54 55 56
/* END: Common Includes */


/* BEGIN: Non Windows Includes */
#ifndef WINDOWSNT
Gerd Moellmann's avatar
Gerd Moellmann committed
57

58 59
#include <sys/ioctl.h>

Gerd Moellmann's avatar
Gerd Moellmann committed
60 61 62 63 64 65 66 67 68
/* FreeBSD has machine/soundcard.h.  Voxware sound driver docs mention
   sys/soundcard.h.  So, let's try whatever's there.  */

#ifdef HAVE_MACHINE_SOUNDCARD_H
#include <machine/soundcard.h>
#endif
#ifdef HAVE_SYS_SOUNDCARD_H
#include <sys/soundcard.h>
#endif
69 70 71
#ifdef HAVE_SOUNDCARD_H
#include <soundcard.h>
#endif
72
#ifdef HAVE_ALSA
73 74 75
#ifdef ALSA_SUBDIR_INCLUDE
#include <alsa/asoundlib.h>
#else
76
#include <asoundlib.h>
77 78
#endif /* ALSA_SUBDIR_INCLUDE */
#endif /* HAVE_ALSA */
79

80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
/* END: Non Windows Includes */

#else /* WINDOWSNT */

/* BEGIN: Windows Specific Includes */
#include <stdio.h>
#include <limits.h>
#include <windows.h>
#include <mmsystem.h>
/* END: Windows Specific Includes */

#endif /* WINDOWSNT */

/* BEGIN: Common Definitions */

/* Symbols.  */

97 98 99
static Lisp_Object QCvolume, QCdevice;
static Lisp_Object Qsound;
static Lisp_Object Qplay_sound_functions;
100 101 102 103 104 105 106 107 108 109 110 111

/* Indices of attributes in a sound attributes vector.  */

enum sound_attr
{
  SOUND_FILE,
  SOUND_DATA,
  SOUND_DEVICE,
  SOUND_VOLUME,
  SOUND_ATTR_SENTINEL
};

112
#ifdef HAVE_ALSA
113
static void alsa_sound_perror (const char *, int) NO_RETURN;
114
#endif
115 116
static void sound_perror (const char *) NO_RETURN;
static void sound_warning (const char *);
117
static int parse_sound (Lisp_Object, Lisp_Object *);
118 119 120 121 122

/* END: Common Definitions */

/* BEGIN: Non Windows Definitions */
#ifndef WINDOWSNT
123 124 125 126

#ifndef DEFAULT_SOUND_DEVICE
#define DEFAULT_SOUND_DEVICE "/dev/dsp"
#endif
127 128 129
#ifndef DEFAULT_ALSA_SOUND_DEVICE
#define DEFAULT_ALSA_SOUND_DEVICE "default"
#endif
Gerd Moellmann's avatar
Gerd Moellmann committed
130 131 132 133


/* Structure forward declarations.  */

134
struct sound;
Gerd Moellmann's avatar
Gerd Moellmann committed
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
struct sound_device;

/* The file header of RIFF-WAVE files (*.wav).  Files are always in
   little-endian byte-order.  */

struct wav_header
{
  u_int32_t magic;
  u_int32_t length;
  u_int32_t chunk_type;
  u_int32_t chunk_format;
  u_int32_t chunk_length;
  u_int16_t format;
  u_int16_t channels;
  u_int32_t sample_rate;
  u_int32_t bytes_per_second;
  u_int16_t sample_size;
  u_int16_t precision;
  u_int32_t chunk_data;
  u_int32_t data_length;
};

/* The file header of Sun adio files (*.au).  Files are always in
   big-endian byte-order.  */

struct au_header
{
  /* ASCII ".snd" */
  u_int32_t magic_number;
164

Gerd Moellmann's avatar
Gerd Moellmann committed
165 166
  /* Offset of data part from start of file. Minimum value is 24.  */
  u_int32_t data_offset;
167

Gerd Moellmann's avatar
Gerd Moellmann committed
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
  /* Size of data part, 0xffffffff if unknown.  */
  u_int32_t data_size;

  /* Data encoding format.
     1	8-bit ISDN u-law
     2  8-bit linear PCM (REF-PCM)
     3  16-bit linear PCM
     4	24-bit linear PCM
     5	32-bit linear PCM
     6	32-bit IEEE floating-point
     7	64-bit IEEE floating-point
     23 8-bit u-law compressed using CCITT 0.721 ADPCM voice data
     encoding scheme.  */
  u_int32_t encoding;

  /* Number of samples per second.  */
  u_int32_t sample_rate;

  /* Number of interleaved channels.  */
  u_int32_t channels;
};

/* Maximum of all sound file headers sizes.  */

#define MAX_SOUND_HEADER_BYTES \
     max (sizeof (struct wav_header), sizeof (struct au_header))

/* Interface structure for sound devices.  */

struct sound_device
{
  /* The name of the device or null meaning use a default device name.  */
  char *file;

  /* File descriptor of the device.  */
  int fd;

  /* Device-dependent format.  */
  int format;

  /* Volume (0..100).  Zero means unspecified.  */
  int volume;

  /* Sample size.  */
  int sample_size;

  /* Sample rate.  */
  int sample_rate;

  /* Bytes per second.  */
  int bps;

  /* 1 = mono, 2 = stereo, 0 = don't set.  */
  int channels;
222

Gerd Moellmann's avatar
Gerd Moellmann committed
223
  /* Open device SD.  */
224
  void (* open) (struct sound_device *sd);
Gerd Moellmann's avatar
Gerd Moellmann committed
225 226

  /* Close device SD.  */
227
  void (* close) (struct sound_device *sd);
Gerd Moellmann's avatar
Gerd Moellmann committed
228 229

  /* Configure SD accoring to device-dependent parameters.  */
230
  void (* configure) (struct sound_device *device);
231

232
  /* Choose a device-dependent format for outputting sound S.  */
233 234
  void (* choose_format) (struct sound_device *sd,
                          struct sound *s);
Gerd Moellmann's avatar
Gerd Moellmann committed
235

236 237
  /* Return a preferred data size in bytes to be sent to write (below)
     each time.  2048 is used if this is NULL.  */
238
  EMACS_INT (* period_size) (struct sound_device *sd);
239

Gerd Moellmann's avatar
Gerd Moellmann committed
240
  /* Write NYBTES bytes from BUFFER to device SD.  */
241
  void (* write) (struct sound_device *sd, const char *buffer,
242
                  EMACS_INT nbytes);
Gerd Moellmann's avatar
Gerd Moellmann committed
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257

  /* A place for devices to store additional data.  */
  void *data;
};

/* An enumerator for each supported sound file type.  */

enum sound_type
{
  RIFF,
  SUN_AUDIO
};

/* Interface structure for sound files.  */

258
struct sound
Gerd Moellmann's avatar
Gerd Moellmann committed
259 260 261 262
{
  /* The type of the file.  */
  enum sound_type type;

263
  /* File descriptor of a sound file.  */
Gerd Moellmann's avatar
Gerd Moellmann committed
264 265
  int fd;

266 267
  /* Pointer to sound file header.  This contains header_size bytes
     read from the start of a sound file.  */
Gerd Moellmann's avatar
Gerd Moellmann committed
268 269
  char *header;

270 271 272 273 274 275 276 277
  /* Number of bytes raed from sound file.  This is always <=
     MAX_SOUND_HEADER_BYTES.  */
  int header_size;

  /* Sound data, if a string.  */
  Lisp_Object data;

  /* Play sound file S on device SD.  */
278
  void (* play) (struct sound *s, struct sound_device *sd);
Gerd Moellmann's avatar
Gerd Moellmann committed
279 280
};

281
/* These are set during `play-sound-internal' so that sound_cleanup has
Gerd Moellmann's avatar
Gerd Moellmann committed
282 283
   access to them.  */

284 285
static struct sound_device *current_sound_device;
static struct sound *current_sound;
Gerd Moellmann's avatar
Gerd Moellmann committed
286 287 288

/* Function prototypes.  */

289 290 291 292 293
static void vox_open (struct sound_device *);
static void vox_configure (struct sound_device *);
static void vox_close (struct sound_device *sd);
static void vox_choose_format (struct sound_device *, struct sound *);
static int vox_init (struct sound_device *);
294
static void vox_write (struct sound_device *, const char *, EMACS_INT);
295 296 297 298 299 300 301 302
static void find_sound_type (struct sound *);
static u_int32_t le2hl (u_int32_t);
static u_int16_t le2hs (u_int16_t);
static u_int32_t be2hl (u_int32_t);
static int wav_init (struct sound *);
static void wav_play (struct sound *, struct sound_device *);
static int au_init (struct sound *);
static void au_play (struct sound *, struct sound_device *);
Gerd Moellmann's avatar
Gerd Moellmann committed
303

304
#if 0 /* Currently not used.  */
305
static u_int16_t be2hs (u_int16_t);
306 307
#endif

308 309 310 311
/* END: Non Windows Definitions */
#else /* WINDOWSNT */

/* BEGIN: Windows Specific Definitions */
312
static int do_play_sound (const char *, unsigned long);
313 314 315
/*
  END: Windows Specific Definitions */
#endif /* WINDOWSNT */
Gerd Moellmann's avatar
Gerd Moellmann committed
316 317 318 319 320 321


/***********************************************************************
			       General
 ***********************************************************************/

322 323
/* BEGIN: Common functions */

Gerd Moellmann's avatar
Gerd Moellmann committed
324 325 326
/* Like perror, but signals an error.  */

static void
327
sound_perror (const char *msg)
Gerd Moellmann's avatar
Gerd Moellmann committed
328
{
329 330
  int saved_errno = errno;

331 332 333 334
  turn_on_atimers (1);
#ifdef SIGIO
  sigunblock (sigmask (SIGIO));
#endif
335 336
  if (saved_errno != 0)
    error ("%s: %s", msg, strerror (saved_errno));
337 338 339 340 341 342 343 344
  else
    error ("%s", msg);
}


/* Display a warning message.  */

static void
345
sound_warning (const char *msg)
346
{
347
  message ("%s", msg);
Gerd Moellmann's avatar
Gerd Moellmann committed
348 349 350 351 352 353 354 355 356 357 358 359 360 361
}


/* Parse sound specification SOUND, and fill ATTRS with what is
   found.  Value is non-zero if SOUND Is a valid sound specification.
   A valid sound specification is a list starting with the symbol
   `sound'.  The rest of the list is a property list which may
   contain the following key/value pairs:

   - `:file FILE'

   FILE is the sound file to play.  If it isn't an absolute name,
   it's searched under `data-directory'.

362 363 364 365 366
   - `:data DATA'

   DATA is a string containing sound data.  Either :file or :data
   may be present, but not both.

Gerd Moellmann's avatar
Gerd Moellmann committed
367 368 369 370 371 372 373
   - `:device DEVICE'

   DEVICE is the name of the device to play on, e.g. "/dev/dsp2".
   If not specified, a default device is used.

   - `:volume VOL'

374 375
   VOL must be an integer in the range [0, 100], or a float in the
   range [0, 1].  */
Gerd Moellmann's avatar
Gerd Moellmann committed
376 377

static int
378
parse_sound (Lisp_Object sound, Lisp_Object *attrs)
Gerd Moellmann's avatar
Gerd Moellmann committed
379 380 381 382 383 384 385
{
  /* SOUND must be a list starting with the symbol `sound'.  */
  if (!CONSP (sound) || !EQ (XCAR (sound), Qsound))
    return 0;

  sound = XCDR (sound);
  attrs[SOUND_FILE] = Fplist_get (sound, QCfile);
386
  attrs[SOUND_DATA] = Fplist_get (sound, QCdata);
Gerd Moellmann's avatar
Gerd Moellmann committed
387 388 389
  attrs[SOUND_DEVICE] = Fplist_get (sound, QCdevice);
  attrs[SOUND_VOLUME] = Fplist_get (sound, QCvolume);

390
#ifndef WINDOWSNT
391 392 393
  /* File name or data must be specified.  */
  if (!STRINGP (attrs[SOUND_FILE])
      && !STRINGP (attrs[SOUND_DATA]))
Gerd Moellmann's avatar
Gerd Moellmann committed
394
    return 0;
395 396 397 398 399 400 401 402 403 404
#else /* WINDOWSNT */
  /*
    Data is not supported in Windows.  Therefore a
    File name MUST be supplied.
  */
  if (!STRINGP (attrs[SOUND_FILE]))
    {
      return 0;
    }
#endif /* WINDOWSNT */
Gerd Moellmann's avatar
Gerd Moellmann committed
405 406 407 408

  /* Volume must be in the range 0..100 or unspecified.  */
  if (!NILP (attrs[SOUND_VOLUME]))
    {
409 410 411 412 413 414 415 416 417 418 419 420 421
      if (INTEGERP (attrs[SOUND_VOLUME]))
	{
	  if (XINT (attrs[SOUND_VOLUME]) < 0
	      || XINT (attrs[SOUND_VOLUME]) > 100)
	    return 0;
	}
      else if (FLOATP (attrs[SOUND_VOLUME]))
	{
	  if (XFLOAT_DATA (attrs[SOUND_VOLUME]) < 0
	      || XFLOAT_DATA (attrs[SOUND_VOLUME]) > 1)
	    return 0;
	}
      else
Gerd Moellmann's avatar
Gerd Moellmann committed
422 423 424
	return 0;
    }

425
#ifndef WINDOWSNT
Gerd Moellmann's avatar
Gerd Moellmann committed
426 427 428 429
  /* Device must be a string or unspecified.  */
  if (!NILP (attrs[SOUND_DEVICE])
      && !STRINGP (attrs[SOUND_DEVICE]))
    return 0;
430 431 432 433 434
#endif  /* WINDOWSNT */
  /*
    Since device is ignored in Windows, it does not matter
    what it is.
   */
Gerd Moellmann's avatar
Gerd Moellmann committed
435 436 437
  return 1;
}

438 439 440 441
/* END: Common functions */

/* BEGIN: Non Windows functions */
#ifndef WINDOWSNT
Gerd Moellmann's avatar
Gerd Moellmann committed
442 443

/* Find out the type of the sound file whose file descriptor is FD.
444
   S is the sound file structure to fill in.  */
Gerd Moellmann's avatar
Gerd Moellmann committed
445 446

static void
447
find_sound_type (struct sound *s)
Gerd Moellmann's avatar
Gerd Moellmann committed
448
{
449 450
  if (!wav_init (s) && !au_init (s))
    error ("Unknown sound format");
Gerd Moellmann's avatar
Gerd Moellmann committed
451 452 453
}


454
/* Function installed by play-sound-internal with record_unwind_protect.  */
Gerd Moellmann's avatar
Gerd Moellmann committed
455 456

static Lisp_Object
457
sound_cleanup (Lisp_Object arg)
Gerd Moellmann's avatar
Gerd Moellmann committed
458
{
459 460 461 462
  if (current_sound_device->close)
    current_sound_device->close (current_sound_device);
  if (current_sound->fd > 0)
    emacs_close (current_sound->fd);
463 464
  xfree (current_sound_device);
  xfree (current_sound);
465 466

  return Qnil;
Gerd Moellmann's avatar
Gerd Moellmann committed
467 468 469 470 471 472 473 474 475 476
}

/***********************************************************************
			Byte-order Conversion
 ***********************************************************************/

/* Convert 32-bit value VALUE which is in little-endian byte-order
   to host byte-order.  */

static u_int32_t
477
le2hl (u_int32_t value)
Gerd Moellmann's avatar
Gerd Moellmann committed
478
{
479
#ifdef WORDS_BIGENDIAN
Gerd Moellmann's avatar
Gerd Moellmann committed
480 481 482 483 484 485 486 487 488 489 490
  unsigned char *p = (unsigned char *) &value;
  value = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
#endif
  return value;
}


/* Convert 16-bit value VALUE which is in little-endian byte-order
   to host byte-order.  */

static u_int16_t
491
le2hs (u_int16_t value)
Gerd Moellmann's avatar
Gerd Moellmann committed
492
{
493
#ifdef WORDS_BIGENDIAN
Gerd Moellmann's avatar
Gerd Moellmann committed
494 495 496 497 498 499 500 501 502 503 504
  unsigned char *p = (unsigned char *) &value;
  value = p[0] + (p[1] << 8);
#endif
  return value;
}


/* Convert 32-bit value VALUE which is in big-endian byte-order
   to host byte-order.  */

static u_int32_t
505
be2hl (u_int32_t value)
Gerd Moellmann's avatar
Gerd Moellmann committed
506
{
507
#ifndef WORDS_BIGENDIAN
Gerd Moellmann's avatar
Gerd Moellmann committed
508 509 510 511 512 513 514
  unsigned char *p = (unsigned char *) &value;
  value = p[3] + (p[2] << 8) + (p[1] << 16) + (p[0] << 24);
#endif
  return value;
}


515 516
#if 0 /* Currently not used.  */

Gerd Moellmann's avatar
Gerd Moellmann committed
517 518 519 520
/* Convert 16-bit value VALUE which is in big-endian byte-order
   to host byte-order.  */

static u_int16_t
521
be2hs (u_int16_t value)
Gerd Moellmann's avatar
Gerd Moellmann committed
522
{
523
#ifndef WORDS_BIGENDIAN
Gerd Moellmann's avatar
Gerd Moellmann committed
524 525 526 527 528 529
  unsigned char *p = (unsigned char *) &value;
  value = p[1] + (p[0] << 8);
#endif
  return value;
}

530
#endif /* 0 */
Gerd Moellmann's avatar
Gerd Moellmann committed
531 532 533 534 535

/***********************************************************************
			  RIFF-WAVE (*.wav)
 ***********************************************************************/

536
/* Try to initialize sound file S from S->header.  S->header
Gerd Moellmann's avatar
Gerd Moellmann committed
537 538
   contains the first MAX_SOUND_HEADER_BYTES number of bytes from the
   sound file.  If the file is a WAV-format file, set up interface
539
   functions in S and convert header fields to host byte-order.
Gerd Moellmann's avatar
Gerd Moellmann committed
540 541 542
   Value is non-zero if the file is a WAV file.  */

static int
543
wav_init (struct sound *s)
Gerd Moellmann's avatar
Gerd Moellmann committed
544
{
545 546 547
  struct wav_header *header = (struct wav_header *) s->header;

  if (s->header_size < sizeof *header
548
      || memcmp (s->header, "RIFF", 4) != 0)
Gerd Moellmann's avatar
Gerd Moellmann committed
549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567
    return 0;

  /* WAV files are in little-endian order.  Convert the header
     if on a big-endian machine.  */
  header->magic = le2hl (header->magic);
  header->length = le2hl (header->length);
  header->chunk_type = le2hl (header->chunk_type);
  header->chunk_format = le2hl (header->chunk_format);
  header->chunk_length = le2hl (header->chunk_length);
  header->format = le2hs (header->format);
  header->channels = le2hs (header->channels);
  header->sample_rate = le2hl (header->sample_rate);
  header->bytes_per_second = le2hl (header->bytes_per_second);
  header->sample_size = le2hs (header->sample_size);
  header->precision = le2hs (header->precision);
  header->chunk_data = le2hl (header->chunk_data);
  header->data_length = le2hl (header->data_length);

  /* Set up the interface functions for WAV.  */
568 569
  s->type = RIFF;
  s->play = wav_play;
Gerd Moellmann's avatar
Gerd Moellmann committed
570 571

  return 1;
572
}
Gerd Moellmann's avatar
Gerd Moellmann committed
573 574


575
/* Play RIFF-WAVE audio file S on sound device SD.  */
Gerd Moellmann's avatar
Gerd Moellmann committed
576 577

static void
578
wav_play (struct sound *s, struct sound_device *sd)
Gerd Moellmann's avatar
Gerd Moellmann committed
579
{
580
  struct wav_header *header = (struct wav_header *) s->header;
Gerd Moellmann's avatar
Gerd Moellmann committed
581 582 583

  /* Let the device choose a suitable device-dependent format
     for the file.  */
584
  sd->choose_format (sd, s);
585

Gerd Moellmann's avatar
Gerd Moellmann committed
586 587 588 589 590 591 592 593 594 595 596
  /* Configure the device.  */
  sd->sample_size = header->sample_size;
  sd->sample_rate = header->sample_rate;
  sd->bps = header->bytes_per_second;
  sd->channels = header->channels;
  sd->configure (sd);

  /* Copy sound data to the device.  The WAV file specification is
     actually more complex.  This simple scheme worked with all WAV
     files I found so far.  If someone feels inclined to implement the
     whole RIFF-WAVE spec, please do.  */
597
  if (STRINGP (s->data))
598
    sd->write (sd, SSDATA (s->data) + sizeof *header,
599
	       SBYTES (s->data) - sizeof *header);
600 601 602
  else
    {
      char *buffer;
603 604 605
      EMACS_INT nbytes = 0;
      EMACS_INT blksize = sd->period_size ? sd->period_size (sd) : 2048;
      EMACS_INT data_left = header->data_length;
606

607 608
      buffer = (char *) alloca (blksize);
      lseek (s->fd, sizeof *header, SEEK_SET);
609 610 611 612 613 614 615 616
      while (data_left > 0
             && (nbytes = emacs_read (s->fd, buffer, blksize)) > 0)
        {
          /* Don't play possible garbage at the end of file */
          if (data_left < nbytes) nbytes = data_left;
          data_left -= nbytes;
          sd->write (sd, buffer, nbytes);
        }
Gerd Moellmann's avatar
Gerd Moellmann committed
617

618
      if (nbytes < 0)
619
	sound_perror ("Error reading sound file");
620
    }
Gerd Moellmann's avatar
Gerd Moellmann committed
621 622 623 624 625 626 627
}


/***********************************************************************
			   Sun Audio (*.au)
 ***********************************************************************/

628
/* Sun audio file encodings.  */
Gerd Moellmann's avatar
Gerd Moellmann committed
629 630 631 632 633 634 635 636 637 638

enum au_encoding
{
  AU_ENCODING_ULAW_8 = 1,
  AU_ENCODING_8,
  AU_ENCODING_16,
  AU_ENCODING_24,
  AU_ENCODING_32,
  AU_ENCODING_IEEE32,
  AU_ENCODING_IEEE64,
639 640
  AU_COMPRESSED = 23,
  AU_ENCODING_ALAW_8 = 27
Gerd Moellmann's avatar
Gerd Moellmann committed
641 642 643
};


644
/* Try to initialize sound file S from S->header.  S->header
Gerd Moellmann's avatar
Gerd Moellmann committed
645 646
   contains the first MAX_SOUND_HEADER_BYTES number of bytes from the
   sound file.  If the file is a AU-format file, set up interface
647
   functions in S and convert header fields to host byte-order.
Gerd Moellmann's avatar
Gerd Moellmann committed
648 649 650
   Value is non-zero if the file is an AU file.  */

static int
651
au_init (struct sound *s)
Gerd Moellmann's avatar
Gerd Moellmann committed
652
{
653
  struct au_header *header = (struct au_header *) s->header;
654

655
  if (s->header_size < sizeof *header
656
      || memcmp (s->header, ".snd", 4) != 0)
Gerd Moellmann's avatar
Gerd Moellmann committed
657
    return 0;
658

Gerd Moellmann's avatar
Gerd Moellmann committed
659 660 661 662 663 664
  header->magic_number = be2hl (header->magic_number);
  header->data_offset = be2hl (header->data_offset);
  header->data_size = be2hl (header->data_size);
  header->encoding = be2hl (header->encoding);
  header->sample_rate = be2hl (header->sample_rate);
  header->channels = be2hl (header->channels);
665

Gerd Moellmann's avatar
Gerd Moellmann committed
666
  /* Set up the interface functions for AU.  */
667 668
  s->type = SUN_AUDIO;
  s->play = au_play;
Gerd Moellmann's avatar
Gerd Moellmann committed
669 670 671 672 673

  return 1;
}


674
/* Play Sun audio file S on sound device SD.  */
Gerd Moellmann's avatar
Gerd Moellmann committed
675 676

static void
677
au_play (struct sound *s, struct sound_device *sd)
Gerd Moellmann's avatar
Gerd Moellmann committed
678
{
679
  struct au_header *header = (struct au_header *) s->header;
Gerd Moellmann's avatar
Gerd Moellmann committed
680 681 682 683 684

  sd->sample_size = 0;
  sd->sample_rate = header->sample_rate;
  sd->bps = 0;
  sd->channels = header->channels;
685
  sd->choose_format (sd, s);
Gerd Moellmann's avatar
Gerd Moellmann committed
686
  sd->configure (sd);
687 688

  if (STRINGP (s->data))
689
    sd->write (sd, SSDATA (s->data) + header->data_offset,
690
	       SBYTES (s->data) - header->data_offset);
691 692
  else
    {
693
      EMACS_INT blksize = sd->period_size ? sd->period_size (sd) : 2048;
694
      char *buffer;
695
      EMACS_INT nbytes;
696

697 698
      /* Seek */
      lseek (s->fd, header->data_offset, SEEK_SET);
699

700 701 702 703
      /* Copy sound data to the device.  */
      buffer = (char *) alloca (blksize);
      while ((nbytes = emacs_read (s->fd, buffer, blksize)) > 0)
	sd->write (sd, buffer, nbytes);
704

705
      if (nbytes < 0)
706
	sound_perror ("Error reading sound file");
707
    }
Gerd Moellmann's avatar
Gerd Moellmann committed
708 709 710 711 712 713 714 715 716 717 718 719 720 721 722
}


/***********************************************************************
		       Voxware Driver Interface
 ***********************************************************************/

/* This driver is available on GNU/Linux, and the free BSDs.  FreeBSD
   has a compatible own driver aka Luigi's driver.  */


/* Open device SD.  If SD->file is non-null, open that device,
   otherwise use a default device name.  */

static void
723
vox_open (struct sound_device *sd)
Gerd Moellmann's avatar
Gerd Moellmann committed
724
{
725
  const char *file;
726

Gerd Moellmann's avatar
Gerd Moellmann committed
727 728 729 730
  /* Open the sound device.  Default is /dev/dsp.  */
  if (sd->file)
    file = sd->file;
  else
731
    file = DEFAULT_SOUND_DEVICE;
732

733
  sd->fd = emacs_open (file, O_WRONLY, 0);
Gerd Moellmann's avatar
Gerd Moellmann committed
734 735 736 737 738 739 740 741
  if (sd->fd < 0)
    sound_perror (file);
}


/* Configure device SD from parameters in it.  */

static void
742
vox_configure (struct sound_device *sd)
Gerd Moellmann's avatar
Gerd Moellmann committed
743
{
744
  int val;
745

Gerd Moellmann's avatar
Gerd Moellmann committed
746 747
  xassert (sd->fd >= 0);

748 749 750
  /* On GNU/Linux, it seems that the device driver doesn't like to be
     interrupted by a signal.  Block the ones we know to cause
     troubles.  */
751
  turn_on_atimers (0);
752 753 754
#ifdef SIGIO
  sigblock (sigmask (SIGIO));
#endif
755

756 757 758
  val = sd->format;
  if (ioctl (sd->fd, SNDCTL_DSP_SETFMT, &sd->format) < 0
      || val != sd->format)
759
    sound_perror ("Could not set sound format");
Gerd Moellmann's avatar
Gerd Moellmann committed
760

761 762 763
  val = sd->channels != 1;
  if (ioctl (sd->fd, SNDCTL_DSP_STEREO, &val) < 0
      || val != (sd->channels != 1))
764
    sound_perror ("Could not set stereo/mono");
Gerd Moellmann's avatar
Gerd Moellmann committed
765

766 767 768 769 770
  /* I think bps and sampling_rate are the same, but who knows.
     Check this. and use SND_DSP_SPEED for both.  */
  if (sd->sample_rate > 0)
    {
      val = sd->sample_rate;
771 772 773 774
      if (ioctl (sd->fd, SNDCTL_DSP_SPEED, &sd->sample_rate) < 0)
	sound_perror ("Could not set sound speed");
      else if (val != sd->sample_rate)
	sound_warning ("Could not set sample rate");
775
    }
Gerd Moellmann's avatar
Gerd Moellmann committed
776

777 778 779 780
  if (sd->volume > 0)
    {
      int volume = sd->volume & 0xff;
      volume |= volume << 8;
781 782
      /* This may fail if there is no mixer.  Ignore the failure.  */
      ioctl (sd->fd, SOUND_MIXER_WRITE_PCM, &volume);
783
    }
784

785
  turn_on_atimers (1);
786 787 788
#ifdef SIGIO
  sigunblock (sigmask (SIGIO));
#endif
Gerd Moellmann's avatar
Gerd Moellmann committed
789 790 791 792 793 794
}


/* Close device SD if it is open.  */

static void
795
vox_close (struct sound_device *sd)
Gerd Moellmann's avatar
Gerd Moellmann committed
796 797 798
{
  if (sd->fd >= 0)
    {
799 800 801 802 803 804
      /* On GNU/Linux, it seems that the device driver doesn't like to
	 be interrupted by a signal.  Block the ones we know to cause
	 troubles.  */
#ifdef SIGIO
      sigblock (sigmask (SIGIO));
#endif
805
      turn_on_atimers (0);
806

807
      /* Flush sound data, and reset the device.  */
Gerd Moellmann's avatar
Gerd Moellmann committed
808
      ioctl (sd->fd, SNDCTL_DSP_SYNC, NULL);
809

810
      turn_on_atimers (1);
811 812 813
#ifdef SIGIO
      sigunblock (sigmask (SIGIO));
#endif
Gerd Moellmann's avatar
Gerd Moellmann committed
814 815

      /* Close the device.  */
816
      emacs_close (sd->fd);
Gerd Moellmann's avatar
Gerd Moellmann committed
817 818 819 820 821
      sd->fd = -1;
    }
}


822
/* Choose device-dependent format for device SD from sound file S.  */
Gerd Moellmann's avatar
Gerd Moellmann committed
823 824

static void
825
vox_choose_format (struct sound_device *sd, struct sound *s)
Gerd Moellmann's avatar
Gerd Moellmann committed
826
{
827
  if (s->type == RIFF)
Gerd Moellmann's avatar
Gerd Moellmann committed
828
    {
829
      struct wav_header *h = (struct wav_header *) s->header;
Gerd Moellmann's avatar
Gerd Moellmann committed
830 831 832 833 834 835 836
      if (h->precision == 8)
	sd->format = AFMT_U8;
      else if (h->precision == 16)
	sd->format = AFMT_S16_LE;
      else
	error ("Unsupported WAV file format");
    }
837
  else if (s->type == SUN_AUDIO)
Gerd Moellmann's avatar
Gerd Moellmann committed
838
    {
839
      struct au_header *header = (struct au_header *) s->header;
Gerd Moellmann's avatar
Gerd Moellmann committed
840 841 842 843 844 845 846
      switch (header->encoding)
	{
	case AU_ENCODING_ULAW_8:
	case AU_ENCODING_IEEE32:
	case AU_ENCODING_IEEE64:
	  sd->format = AFMT_MU_LAW;
	  break;
847

Gerd Moellmann's avatar
Gerd Moellmann committed
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866
	case AU_ENCODING_8:
	case AU_ENCODING_16:
	case AU_ENCODING_24:
	case AU_ENCODING_32:
	  sd->format = AFMT_S16_LE;
	  break;

	default:
	  error ("Unsupported AU file format");
	}
    }
  else
    abort ();
}


/* Initialize device SD.  Set up the interface functions in the device
   structure.  */

867
static int
868
vox_init (struct sound_device *sd)
Gerd Moellmann's avatar
Gerd Moellmann committed
869
{
870
  const char *file;
871 872 873 874 875 876 877 878 879 880 881 882 883
  int fd;

  /* Open the sound device.  Default is /dev/dsp.  */
  if (sd->file)
    file = sd->file;
  else
    file = DEFAULT_SOUND_DEVICE;
  fd = emacs_open (file, O_WRONLY, 0);
  if (fd >= 0)
    emacs_close (fd);
  else
    return 0;

Gerd Moellmann's avatar
Gerd Moellmann committed
884 885 886 887 888 889
  sd->fd = -1;
  sd->open = vox_open;
  sd->close = vox_close;
  sd->configure = vox_configure;
  sd->choose_format = vox_choose_format;
  sd->write = vox_write;
890 891 892
  sd->period_size = NULL;

  return 1;
Gerd Moellmann's avatar
Gerd Moellmann committed
893 894 895 896 897
}

/* Write NBYTES bytes from BUFFER to device SD.  */

static void
898
vox_write (struct sound_device *sd, const char *buffer, EMACS_INT nbytes)
Gerd Moellmann's avatar
Gerd Moellmann committed
899
{
900
  if (emacs_write (sd->fd, buffer, nbytes) != nbytes)
901
    sound_perror ("Error writing to sound device");
Gerd Moellmann's avatar
Gerd Moellmann committed
902 903
}

904 905 906 907 908 909 910 911
#ifdef HAVE_ALSA
/***********************************************************************
		       ALSA Driver Interface
 ***********************************************************************/

/* This driver is available on GNU/Linux. */

static void
912
alsa_sound_perror (const char *msg, int err)
913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928
{
  error ("%s: %s", msg, snd_strerror (err));
}

struct alsa_params
{
  snd_pcm_t *handle;
  snd_pcm_hw_params_t *hwparams;
  snd_pcm_sw_params_t *swparams;
  snd_pcm_uframes_t period_size;
};

/* Open device SD.  If SD->file is non-null, open that device,
   otherwise use a default device name.  */

static void
929
alsa_open (struct sound_device *sd)
930
{
931
  const char *file;
932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949
  struct alsa_params *p;
  int err;

  /* Open the sound device.  Default is "default".  */
  if (sd->file)
    file = sd->file;
  else
    file = DEFAULT_ALSA_SOUND_DEVICE;

  p = xmalloc (sizeof (*p));
  p->handle = NULL;
  p->hwparams = NULL;
  p->swparams = NULL;

  sd->fd = -1;
  sd->data = p;


950 951
  err = snd_pcm_open (&p->handle, file, SND_PCM_STREAM_PLAYBACK, 0);
  if (err < 0)
952 953 954
    alsa_sound_perror (file, err);
}

955
static EMACS_INT
956
alsa_period_size (struct sound_device *sd)
957 958
{
  struct alsa_params *p = (struct alsa_params *) sd->data;
959 960
  int fact = snd_pcm_format_size (sd->format, 1) * sd->channels;
  return p->period_size * (fact > 0 ? fact : 1);
961 962 963
}

static void
964
alsa_configure (struct sound_device *sd)
965 966
{
  int val, err, dir;
967
  unsigned uval;
968 969 970 971 972
  struct alsa_params *p = (struct alsa_params *) sd->data;
  snd_pcm_uframes_t buffer_size;

  xassert (p->handle != 0);

973 974
  err = snd_pcm_hw_params_malloc (&p->hwparams);
  if (err < 0)
975 976
    alsa_sound_perror ("Could not allocate hardware parameter structure", err);

977 978
  err = snd_pcm_sw_params_malloc (&p->swparams);
  if (err < 0)
979 980
    alsa_sound_perror ("Could not allocate software parameter structure", err);

981 982
  err = snd_pcm_hw_params_any (p->handle, p->hwparams);
  if (err < 0)
983 984
    alsa_sound_perror ("Could not initialize hardware parameter structure", err);

985 986 987
  err = snd_pcm_hw_params_set_access (p->handle, p->hwparams,
                                      SND_PCM_ACCESS_RW_INTERLEAVED);
  if (err < 0)
988 989 990
    alsa_sound_perror ("Could not set access type", err);

  val = sd->format;
991
  err = snd_pcm_hw_params_set_format (p->handle, p->hwparams, val);
992
  if (err < 0)
993 994
    alsa_sound_perror ("Could not set sound format", err);

995 996
  uval = sd->sample_rate;
  err = snd_pcm_hw_params_set_rate_near (p->handle, p->hwparams, &uval, 0);
997
  if (err < 0)
998
    alsa_sound_perror ("Could not set sample rate", err);
999

1000
  val = sd->channels;
1001 1002
  err = snd_pcm_hw_params_set_channels (p->handle, p->hwparams, val);
  if (err < 0)
1003 1004
    alsa_sound_perror ("Could not set channel count", err);

1005 1006
  err = snd_pcm_hw_params (p->handle, p->hwparams);
  if (err < 0)
1007 1008
    alsa_sound_perror ("Could not set parameters", err);

1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042

  err = snd_pcm_hw_params_get_period_size (p->hwparams, &p->period_size, &dir);
  if (err < 0)
    alsa_sound_perror ("Unable to get period size for playback", err);

  err = snd_pcm_hw_params_get_buffer_size (p->hwparams, &buffer_size);
  if (err < 0)
    alsa_sound_perror("Unable to get buffer size for playback", err);

  err = snd_pcm_sw_params_current (p->handle, p->swparams);
  if (err < 0)
    alsa_sound_perror ("Unable to determine current swparams for playback",
                       err);

  /* Start the transfer when the buffer is almost full */
  err = snd_pcm_sw_params_set_start_threshold (p->handle, p->swparams,
                                               (buffer_size / p->period_size)
                                               * p->period_size);
  if (err < 0)
    alsa_sound_perror ("Unable to set start threshold mode for playback", err);

  /* Allow the transfer when at least period_size samples can be processed */
  err = snd_pcm_sw_params_set_avail_min (p->handle, p->swparams, p->period_size);
  if (err < 0)
    alsa_sound_perror ("Unable to set avail min for playback", err);

  err = snd_pcm_sw_params (p->handle, p->swparams);
  if (err < 0)
    alsa_sound_perror ("Unable to set sw params for playback\n", err);

  snd_pcm_hw_params_free (p->hwparams);
  p->hwparams = NULL;
  snd_pcm_sw_params_free (p->swparams);
  p->swparams = NULL;
1043

1044 1045
  err = snd_pcm_prepare (p->handle);
  if (err < 0)
1046
    alsa_sound_perror ("Could not prepare audio interface for use", err);
1047

1048 1049 1050 1051 1052
  if (sd->volume > 0)
    {
      int chn;
      snd_mixer_t *handle;
      snd_mixer_elem_t *e;
1053
      const char *file = sd->file ? sd->file : DEFAULT_ALSA_SOUND_DEVICE;
1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065

      if (snd_mixer_open (&handle, 0) >= 0)
        {
          if (snd_mixer_attach (handle, file) >= 0
              && snd_mixer_load (handle) >= 0
              && snd_mixer_selem_register (handle, NULL, NULL) >= 0)
            for (e = snd_mixer_first_elem (handle);
                 e;
                 e = snd_mixer_elem_next (e))
              {
                if (snd_mixer_selem_has_playback_volume (e))
                  {