home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Emulation / BasiliskII / src / Unix / audio_oss_esd.cpp < prev    next >
C/C++ Source or Header  |  1999-11-03  |  12KB  |  461 lines

  1. /*
  2.  *  audio_oss_esd.cpp - Audio support, implementation for OSS and ESD (Linux and FreeBSD)
  3.  *
  4.  *  Basilisk II (C) 1997-1999 Christian Bauer
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  */
  20.  
  21. #include "sysdeps.h"
  22.  
  23. #include <sys/ioctl.h>
  24. #include <unistd.h>
  25. #include <errno.h>
  26. #include <pthread.h>
  27. #include <semaphore.h>
  28.  
  29. #ifdef __linux__
  30. #include <linux/soundcard.h>
  31. #endif
  32.  
  33. #ifdef __FreeBSD__
  34. #include <machine/soundcard.h>
  35. #endif
  36.  
  37. #include "cpu_emulation.h"
  38. #include "main.h"
  39. #include "prefs.h"
  40. #include "user_strings.h"
  41. #include "audio.h"
  42. #include "audio_defs.h"
  43.  
  44. #if ENABLE_ESD
  45. #include <esd.h>
  46. #endif
  47.  
  48. #define DEBUG 0
  49. #include "debug.h"
  50.  
  51.  
  52. // Supported sample rates, sizes and channels (defaults)
  53. int audio_num_sample_rates = 1;
  54. uint32 audio_sample_rates[] = {44100 << 16};
  55. int audio_num_sample_sizes = 1;
  56. uint16 audio_sample_sizes[] = {16};
  57. int audio_num_channel_counts = 1;
  58. uint16 audio_channel_counts[] = {2};
  59.  
  60. // Constants
  61. #define DSP_NAME "/dev/dsp"
  62.  
  63. // Global variables
  64. static int audio_fd = -1;                            // fd of /dev/dsp or ESD
  65. static int mixer_fd = -1;                            // fd of /dev/mixer
  66. static sem_t audio_irq_done_sem;                    // Signal from interrupt to streaming thread: data block read
  67. static bool sem_inited = false;                        // Flag: audio_irq_done_sem initialized
  68. static int sound_buffer_size;                        // Size of sound buffer in bytes
  69. static bool little_endian = false;                    // Flag: DSP accepts only little-endian 16-bit sound data
  70. static uint8 silence_byte;                            // Byte value to use to fill sound buffers with silence
  71. static pthread_t stream_thread;                        // Audio streaming thread
  72. static pthread_attr_t stream_thread_attr;            // Streaming thread attributes
  73. static bool stream_thread_active = false;            // Flag: streaming thread installed
  74. static volatile bool stream_thread_cancel = false;    // Flag: cancel streaming thread
  75.  
  76. // Prototypes
  77. static void *stream_func(void *arg);
  78.  
  79.  
  80. /*
  81.  *  Initialization
  82.  */
  83.  
  84. // Set AudioStatus to reflect current audio stream format
  85. static void set_audio_status_format(void)
  86. {
  87.     AudioStatus.sample_rate = audio_sample_rates[0];
  88.     AudioStatus.sample_size = audio_sample_sizes[0];
  89.     AudioStatus.channels = audio_channel_counts[0];
  90. }
  91.  
  92. // Init using /dev/dsp, returns false on error
  93. bool audio_init_dsp(void)
  94. {
  95.     printf("Using " DSP_NAME " audio output\n");
  96.  
  97.     // Get supported sample formats
  98.     unsigned long format;
  99.     ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &format);
  100.     if ((format & (AFMT_U8 | AFMT_S16_BE | AFMT_S16_LE)) == 0) {
  101.         WarningAlert(GetString(STR_AUDIO_FORMAT_WARN));
  102.         close(audio_fd);
  103.         audio_fd = -1;
  104.         return false;
  105.     }
  106.     if (format & (AFMT_S16_BE | AFMT_S16_LE)) {
  107.         audio_sample_sizes[0] = 16;
  108.         silence_byte = 0;
  109.     } else {
  110.         audio_sample_sizes[0] = 8;
  111.         silence_byte = 0x80;
  112.     }
  113.     if (!(format & AFMT_S16_BE))
  114.         little_endian = true;
  115.  
  116.     // Set DSP parameters
  117.     format = audio_sample_sizes[0] == 8 ? AFMT_U8 : (little_endian ? AFMT_S16_LE : AFMT_S16_BE);
  118.     ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format);
  119.     int frag = 0x0004000c;        // Block size: 4096 frames
  120.     ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag);
  121.     int stereo = (audio_channel_counts[0] == 2);
  122.     ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo);
  123.     int rate = audio_sample_rates[0] >> 16;
  124.     ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate);
  125.     audio_sample_rates[0] = rate << 16;
  126.  
  127.     // Set AudioStatus again because we now know more about the sound
  128.     // system's capabilities
  129.     set_audio_status_format();
  130.  
  131.     // Get sound buffer size
  132.     ioctl(audio_fd, SNDCTL_DSP_GETBLKSIZE, &audio_frames_per_block);
  133.     D(bug("DSP_GETBLKSIZE %d\n", audio_frames_per_block));
  134.     sound_buffer_size = (AudioStatus.sample_size >> 3) * AudioStatus.channels * audio_frames_per_block;
  135.     return true;
  136. }
  137.  
  138. // Init using ESD, returns false on error
  139. bool audio_init_esd(void)
  140. {
  141. #if ENABLE_ESD
  142.     printf("Using ESD audio output\n");
  143.  
  144.     // ESD audio format
  145.     esd_format_t format = ESD_STREAM | ESD_PLAY;
  146.     if (AudioStatus.sample_size == 8)
  147.         format |= ESD_BITS8;
  148.     else
  149.         format |= ESD_BITS16;
  150.     if (AudioStatus.channels == 1)
  151.         format |= ESD_MONO;
  152.     else
  153.         format |= ESD_STEREO;
  154.  
  155. #if WORDS_BIGENDIAN
  156.     little_endian = false;
  157. #else
  158.     little_endian = true;
  159. #endif
  160.     silence_byte = 0;    // Is this correct for 8-bit mode?
  161.  
  162.     // Open connection to ESD server
  163.     audio_fd = esd_play_stream(format, AudioStatus.sample_rate >> 16, NULL, NULL);
  164.     if (audio_fd < 0) {
  165.         char str[256];
  166.         sprintf(str, GetString(STR_NO_ESD_WARN), strerror(errno));
  167.         WarningAlert(str);
  168.         return false;
  169.     }
  170.  
  171.     // Sound buffer size = 4096 frames
  172.     audio_frames_per_block = 4096;
  173.     sound_buffer_size = (AudioStatus.sample_size >> 3) * AudioStatus.channels * audio_frames_per_block;
  174.     return true;
  175. #else
  176.     ErrorAlert("Basilisk II has been compiled with ESD support disabled.");
  177.     return false;
  178. #endif
  179. }
  180.  
  181. void AudioInit(void)
  182. {
  183.     char str[256];
  184.  
  185.     // Init audio status (defaults) and feature flags
  186.     set_audio_status_format();
  187.     AudioStatus.mixer = 0;
  188.     AudioStatus.num_sources = 0;
  189.     audio_component_flags = cmpWantsRegisterMessage | kStereoOut | k16BitOut;
  190.  
  191.     // Sound disabled in prefs? Then do nothing
  192.     if (PrefsFindBool("nosound"))
  193.         return;
  194.  
  195.     // Try to open /dev/dsp
  196.     audio_fd = open(DSP_NAME, O_WRONLY);
  197.     if (audio_fd < 0) {
  198. #if ENABLE_ESD
  199.         if (!audio_init_esd())
  200.             return;
  201. #else
  202.         sprintf(str, GetString(STR_NO_AUDIO_DEV_WARN), DSP_NAME, strerror(errno));
  203.         WarningAlert(str);
  204.         return;
  205. #endif
  206.     } else
  207.         if (!audio_init_dsp())
  208.             return;
  209.  
  210.     // Try to open /dev/mixer
  211.     mixer_fd = open("/dev/mixer", O_RDWR);
  212.     if (mixer_fd < 0)
  213.         printf("WARNING: Cannot open /dev/mixer (%s)", strerror(errno));
  214.  
  215.     // Init semaphore
  216.     if (sem_init(&audio_irq_done_sem, 0, 0) < 0)
  217.         return;
  218.     sem_inited = true;
  219.  
  220.     // Start streaming thread
  221.     pthread_attr_init(&stream_thread_attr);
  222. #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
  223.     if (geteuid() == 0) {
  224.         pthread_attr_setinheritsched(&stream_thread_attr, PTHREAD_EXPLICIT_SCHED);
  225.         pthread_attr_setschedpolicy(&stream_thread_attr, SCHED_FIFO);
  226.         struct sched_param fifo_param;
  227.         fifo_param.sched_priority = (sched_get_priority_min(SCHED_FIFO) + sched_get_priority_max(SCHED_FIFO)) / 2;
  228.         pthread_attr_setschedparam(&stream_thread_attr, &fifo_param);
  229.     }
  230. #endif
  231.     stream_thread_active = (pthread_create(&stream_thread, &stream_thread_attr, stream_func, NULL) == 0);
  232.  
  233.     // Everything OK
  234.     audio_open = true;
  235. }
  236.  
  237.  
  238. /*
  239.  *  Deinitialization
  240.  */
  241.  
  242. void AudioExit(void)
  243. {
  244.     // Stop stream and delete semaphore
  245.     if (stream_thread_active) {
  246.         stream_thread_cancel = true;
  247. #ifdef HAVE_PTHREAD_CANCEL
  248.         pthread_cancel(stream_thread);
  249. #endif
  250.         pthread_join(stream_thread, NULL);
  251.         stream_thread_active = false;
  252.     }
  253.     if (sem_inited)
  254.         sem_destroy(&audio_irq_done_sem);
  255.  
  256.     // Close /dev/dsp
  257.     if (audio_fd > 0)
  258.         close(audio_fd);
  259.  
  260.     // Close /dev/mixer
  261.     if (mixer_fd > 0)
  262.         close(mixer_fd);
  263. }
  264.  
  265.  
  266. /*
  267.  *  First source added, start audio stream
  268.  */
  269.  
  270. void audio_enter_stream()
  271. {
  272.     // Streaming thread is always running to avoid clicking noises
  273. }
  274.  
  275.  
  276. /*
  277.  *  Last source removed, stop audio stream
  278.  */
  279.  
  280. void audio_exit_stream()
  281. {
  282.     // Streaming thread is always running to avoid clicking noises
  283. }
  284.  
  285.  
  286. /*
  287.  *  Streaming function
  288.  */
  289.  
  290. static uint32 apple_stream_info;    // Mac address of SoundComponentData struct describing next buffer
  291.  
  292. static void *stream_func(void *arg)
  293. {
  294.     int16 *silent_buffer = new int16[sound_buffer_size / 2];
  295.     int16 *last_buffer = new int16[sound_buffer_size / 2];
  296.     memset(silent_buffer, silence_byte, sound_buffer_size);
  297.  
  298.     while (!stream_thread_cancel) {
  299.         if (AudioStatus.num_sources) {
  300.  
  301.             // Trigger audio interrupt to get new buffer
  302.             D(bug("stream: triggering irq\n"));
  303.             SetInterruptFlag(INTFLAG_AUDIO);
  304.             TriggerInterrupt();
  305.             D(bug("stream: waiting for ack\n"));
  306.             sem_wait(&audio_irq_done_sem);
  307.             D(bug("stream: ack received\n"));
  308.  
  309.             // Get size of audio data
  310.             uint32 apple_stream_info = ReadMacInt32(audio_data + adatStreamInfo);
  311.             if (apple_stream_info) {
  312.                 int work_size = ReadMacInt32(apple_stream_info + scd_sampleCount) * (AudioStatus.sample_size >> 3) * AudioStatus.channels;
  313.                 D(bug("stream: work_size %d\n", work_size));
  314.                 if (work_size > sound_buffer_size)
  315.                     work_size = sound_buffer_size;
  316.                 if (work_size == 0)
  317.                     goto silence;
  318.  
  319.                 // Send data to DSP
  320.                 if (work_size == sound_buffer_size && !little_endian)
  321.                     write(audio_fd, Mac2HostAddr(ReadMacInt32(apple_stream_info + scd_buffer)), sound_buffer_size);
  322.                 else {
  323.                     // Last buffer or little-endian DSP
  324.                     if (little_endian) {
  325.                         int16 *p = (int16 *)Mac2HostAddr(ReadMacInt32(apple_stream_info + scd_buffer));
  326.                         for (int i=0; i<work_size/2; i++)
  327.                             last_buffer[i] = ntohs(p[i]);
  328.                     } else
  329.                         Mac2Host_memcpy(last_buffer, ReadMacInt32(apple_stream_info + scd_buffer), work_size);
  330.                     memset((uint8 *)last_buffer + work_size, silence_byte, sound_buffer_size - work_size);
  331.                     write(audio_fd, last_buffer, sound_buffer_size);
  332.                 }
  333.                 D(bug("stream: data written\n"));
  334.             } else
  335.                 goto silence;
  336.  
  337.         } else {
  338.  
  339.             // Audio not active, play silence
  340. silence:    write(audio_fd, silent_buffer, sound_buffer_size);
  341.         }
  342.     }
  343.     delete[] silent_buffer;
  344.     delete[] last_buffer;
  345.     return NULL;
  346. }
  347.  
  348.  
  349. /*
  350.  *  MacOS audio interrupt, read next data block
  351.  */
  352.  
  353. void AudioInterrupt(void)
  354. {
  355.     D(bug("AudioInterrupt\n"));
  356.  
  357.     // Get data from apple mixer
  358.     if (AudioStatus.mixer) {
  359.         M68kRegisters r;
  360.         r.a[0] = audio_data + adatStreamInfo;
  361.         r.a[1] = AudioStatus.mixer;
  362.         Execute68k(audio_data + adatGetSourceData, &r);
  363.         D(bug(" GetSourceData() returns %08lx\n", r.d[0]));
  364.     } else
  365.         WriteMacInt32(audio_data + adatStreamInfo, 0);
  366.  
  367.     // Signal stream function
  368.     sem_post(&audio_irq_done_sem);
  369.     D(bug("AudioInterrupt done\n"));
  370. }
  371.  
  372.  
  373. /*
  374.  *  Set sampling parameters
  375.  *  "index" is an index into the audio_sample_rates[] etc. arrays
  376.  *  It is guaranteed that AudioStatus.num_sources == 0
  377.  */
  378.  
  379. void audio_set_sample_rate(int index)
  380. {
  381. }
  382.  
  383. void audio_set_sample_size(int index)
  384. {
  385. }
  386.  
  387. void audio_set_channels(int index)
  388. {
  389. }
  390.  
  391.  
  392. /*
  393.  *  Get/set volume controls (volume values received/returned have the left channel
  394.  *  volume in the upper 16 bits and the right channel volume in the lower 16 bits;
  395.  *  both volumes are 8.8 fixed point values with 0x0100 meaning "maximum volume"))
  396.  */
  397.  
  398. bool audio_get_main_mute(void)
  399. {
  400.     return false;
  401. }
  402.  
  403. uint32 audio_get_main_volume(void)
  404. {
  405.     if (mixer_fd >= 0) {
  406.         int vol;
  407.         if (ioctl(mixer_fd, SOUND_MIXER_READ_PCM, &vol) == 0) {
  408.             int left = vol >> 8;
  409.             int right = vol & 0xff;
  410.             return ((left * 256 / 100) << 16) | (right * 256 / 100);
  411.         }
  412.     }
  413.     return 0x01000100;
  414. }
  415.  
  416. bool audio_get_speaker_mute(void)
  417. {
  418.     return false;
  419. }
  420.  
  421. uint32 audio_get_speaker_volume(void)
  422. {
  423.     if (mixer_fd >= 0) {
  424.         int vol;
  425.         if (ioctl(mixer_fd, SOUND_MIXER_READ_VOLUME, &vol) == 0) {
  426.             int left = vol >> 8;
  427.             int right = vol & 0xff;
  428.             return ((left * 256 / 100) << 16) | (right * 256 / 100);
  429.         }
  430.     }
  431.     return 0x01000100;
  432. }
  433.  
  434. void audio_set_main_mute(bool mute)
  435. {
  436. }
  437.  
  438. void audio_set_main_volume(uint32 vol)
  439. {
  440.     if (mixer_fd >= 0) {
  441.         int left = vol >> 16;
  442.         int right = vol & 0xffff;
  443.         int p = ((left * 100 / 256) << 8) | (right * 100 / 256);
  444.         ioctl(mixer_fd, SOUND_MIXER_WRITE_PCM, &p);
  445.     }
  446. }
  447.  
  448. void audio_set_speaker_mute(bool mute)
  449. {
  450. }
  451.  
  452. void audio_set_speaker_volume(uint32 vol)
  453. {
  454.     if (mixer_fd >= 0) {
  455.         int left = vol >> 16;
  456.         int right = vol & 0xffff;
  457.         int p = ((left * 100 / 256) << 8) | (right * 100 / 256);
  458.         ioctl(mixer_fd, SOUND_MIXER_WRITE_VOLUME, &p);
  459.     }
  460. }
  461.