home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Emulation / BasiliskII / src / Unix / Solaris / audio_solaris.cpp next >
C/C++ Source or Header  |  1999-11-03  |  8KB  |  324 lines

  1. /*
  2.  *  audio_solaris.cpp - Audio support, Solaris implementation
  3.  *
  4.  *  Adapted from Frodo's Solaris sound routines by Marc Chabanas
  5.  *
  6.  *  Basilisk II (C) 1997-1999 Christian Bauer
  7.  *
  8.  *  This program is free software; you can redistribute it and/or modify
  9.  *  it under the terms of the GNU General Public License as published by
  10.  *  the Free Software Foundation; either version 2 of the License, or
  11.  *  (at your option) any later version.
  12.  *
  13.  *  This program is distributed in the hope that it will be useful,
  14.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  *  GNU General Public License for more details.
  17.  *
  18.  *  You should have received a copy of the GNU General Public License
  19.  *  along with this program; if not, write to the Free Software
  20.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  21.  */
  22.  
  23. #include "sysdeps.h"
  24.  
  25. #include <sys/ioctl.h>
  26. #include <sys/audioio.h>
  27. #include <unistd.h>
  28. #include <errno.h>
  29. #include <pthread.h>
  30. #include <semaphore.h>
  31.  
  32. #include "cpu_emulation.h"
  33. #include "main.h"
  34. #include "prefs.h"
  35. #include "user_strings.h"
  36. #include "audio.h"
  37. #include "audio_defs.h"
  38.  
  39. #define DEBUG 0
  40. #include "debug.h"
  41.  
  42.  
  43. // Supported sample rates, sizes and channels
  44. int audio_num_sample_rates = 1;
  45. uint32 audio_sample_rates[] = {44100 << 16};
  46. int audio_num_sample_sizes = 1;
  47. uint16 audio_sample_sizes[] = {16};
  48. int audio_num_channel_counts = 1;
  49. uint16 audio_channel_counts[] = {2};
  50.  
  51. // Global variables
  52. static int fd = -1;                            // fd of /dev/audio
  53. static sem_t audio_irq_done_sem;            // Signal from interrupt to streaming thread: data block read
  54. static pthread_t stream_thread;                // Audio streaming thread
  55. static pthread_attr_t stream_thread_attr;    // Streaming thread attributes
  56. static bool stream_thread_active = false;
  57. static int sound_buffer_size;                // Size of sound buffer in bytes
  58.  
  59. // Prototypes
  60. static void *stream_func(void *arg);
  61.  
  62.  
  63. /*
  64.  *  Initialization
  65.  */
  66.  
  67. void AudioInit(void)
  68. {
  69.     char str[256];
  70.  
  71.     // Init audio status and feature flags
  72.     AudioStatus.sample_rate = audio_sample_rates[0];
  73.     AudioStatus.sample_size = audio_sample_sizes[0];
  74.     AudioStatus.channels = audio_channel_counts[0];
  75.     AudioStatus.mixer = 0;
  76.     AudioStatus.num_sources = 0;
  77.     audio_component_flags = cmpWantsRegisterMessage | kStereoOut | k16BitOut;
  78.  
  79.     // Sound disabled in prefs? Then do nothing
  80.     if (PrefsFindBool("nosound"))
  81.         return;
  82.  
  83.     // Init semaphore
  84.     if (sem_init(&audio_irq_done_sem, 0, 0) < 0)
  85.         return;
  86.  
  87.     // Open /dev/audio
  88.     fd = open("/dev/audio", O_WRONLY | O_NDELAY);
  89.     if (fd < 0) {
  90.         sprintf(str, GetString(STR_NO_AUDIO_DEV_WARN), "/dev/audio", strerror(errno));
  91.         WarningAlert(str);
  92.         sem_destroy(&audio_irq_done_sem);
  93.         return;
  94.     }
  95.  
  96.     // Set audio parameters
  97.     struct audio_info info;
  98.     AUDIO_INITINFO(&info);
  99.     info.play.sample_rate = AudioStatus.sample_rate >> 16;
  100.     info.play.channels = AudioStatus.channels;
  101.     info.play.precision = AudioStatus.sample_size;
  102.     info.play.encoding = AUDIO_ENCODING_LINEAR;
  103.     info.play.port = AUDIO_SPEAKER;
  104.     if (ioctl(fd, AUDIO_SETINFO, &info)) {
  105.         WarningAlert(GetString(STR_AUDIO_FORMAT_WARN));
  106.         close(fd);
  107.         fd = -1;
  108.         sem_destroy(&audio_irq_done_sem);
  109.         return;
  110.     }
  111.  
  112.     // 2048 frames per buffer
  113.     audio_frames_per_block = 2048;
  114.     sound_buffer_size = (AudioStatus.sample_size>>3) * AudioStatus.channels * audio_frames_per_block;
  115.  
  116.     // Start audio thread
  117.     pthread_attr_init(&stream_thread_attr);
  118. #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
  119.     pthread_attr_setinheritsched(&stream_thread_attr, PTHREAD_EXPLICIT_SCHED);
  120.     pthread_attr_setschedpolicy(&stream_thread_attr, SCHED_FIFO);
  121.     struct sched_param fifo_param;
  122.     fifo_param.sched_priority = (sched_get_priority_min(SCHED_FIFO) + sched_get_priority_max(SCHED_FIFO)) / 2;
  123.     pthread_attr_setschedparam(&stream_thread_attr, &fifo_param);
  124. #endif
  125.     stream_thread_active = (pthread_create(&stream_thread, &stream_thread_attr, stream_func, NULL) == 0);
  126.  
  127.     // Everything OK
  128.     audio_open = true;
  129. }
  130.  
  131.  
  132. /*
  133.  *  Deinitialization
  134.  */
  135.  
  136. void AudioExit(void)
  137. {
  138.     // Stop audio thread
  139.     if (stream_thread_active) {
  140.         pthread_cancel(stream_thread);
  141.         pthread_join(stream_thread, NULL);
  142.         sem_destroy(&audio_irq_done_sem);
  143.         stream_thread_active = false;
  144.     }
  145.  
  146.     // Close /dev/audio
  147.     if (fd > 0) {
  148.         ioctl(fd, AUDIO_DRAIN);
  149.         close(fd);
  150.     }
  151. }
  152.  
  153.  
  154. /*
  155.  *  First source added, start audio stream
  156.  */
  157.  
  158. void audio_enter_stream()
  159. {
  160. }
  161.  
  162.  
  163. /*
  164.  *  Last source removed, stop audio stream
  165.  */
  166.  
  167. void audio_exit_stream()
  168. {
  169. }
  170.  
  171.  
  172. /*
  173.  *  Streaming function
  174.  */
  175.  
  176. static uint32 apple_stream_info;    // Mac address of SoundComponentData struct describing next buffer
  177.  
  178. static void *stream_func(void *arg)
  179. {
  180.     int16 *silent_buffer = new int16[sound_buffer_size / 2];
  181.     int16 *last_buffer = new int16[sound_buffer_size / 2];
  182.     memset(silent_buffer, 0, sound_buffer_size);
  183.  
  184.     uint_t sent = 0, delta;
  185.     struct audio_info status;
  186.  
  187.     for (;;) {
  188.         if (AudioStatus.num_sources) {
  189.  
  190.             // Trigger audio interrupt to get new buffer
  191.             D(bug("stream: triggering irq\n"));
  192.             SetInterruptFlag(INTFLAG_AUDIO);
  193.             TriggerInterrupt();
  194.             D(bug("stream: waiting for ack\n"));
  195.             sem_wait(&audio_irq_done_sem);
  196.             D(bug("stream: ack received\n"));
  197.  
  198.             // Get size of audio data
  199.             uint32 apple_stream_info = ReadMacInt32(audio_data + adatStreamInfo);
  200.             if (apple_stream_info) {
  201.                 int work_size = ReadMacInt32(apple_stream_info + scd_sampleCount) * (AudioStatus.sample_size >> 3) * AudioStatus.channels;
  202.                 D(bug("stream: work_size %d\n", work_size));
  203.                 if (work_size > sound_buffer_size)
  204.                     work_size = sound_buffer_size;
  205.                 if (work_size == 0)
  206.                     goto silence;
  207.  
  208.                 // Send data to audio port
  209.                 if (work_size == sound_buffer_size)
  210.                     write(fd, Mac2HostAddr(ReadMacInt32(apple_stream_info + scd_buffer)), sound_buffer_size);
  211.                 else {
  212.                     // Last buffer
  213.                     Mac2Host_memcpy(last_buffer, ReadMacInt32(apple_stream_info + scd_buffer), work_size);
  214.                     memset((uint8 *)last_buffer + work_size, 0, sound_buffer_size - work_size);
  215.                     write(fd, last_buffer, sound_buffer_size);
  216.                 }
  217.                 D(bug("stream: data written\n"));
  218.             } else
  219.                 goto silence;
  220.  
  221.         } else {
  222.  
  223.             // Audio not active, play silence
  224. silence:    write(fd, silent_buffer, sound_buffer_size);
  225.         }
  226.  
  227.         // We allow a maximum of three buffers to be sent
  228.         sent += audio_frames_per_block;
  229.         ioctl(fd, AUDIO_GETINFO, &status);
  230.         while ((delta = sent - status.play.samples) > (audio_frames_per_block * 3)) {
  231.             unsigned int sl = 1000000 * (delta - audio_frames_per_block * 3) / (AudioStatus.sample_rate >> 16);
  232.             usleep(sl);
  233.             ioctl(fd, AUDIO_GETINFO, &status);
  234.         }
  235.     }
  236.     return NULL;
  237. }
  238.  
  239.  
  240. /*
  241.  *  MacOS audio interrupt, read next data block
  242.  */
  243.  
  244. void AudioInterrupt(void)
  245. {
  246.     D(bug("AudioInterrupt\n"));
  247.  
  248.     // Get data from apple mixer
  249.     if (AudioStatus.mixer) {
  250.         M68kRegisters r;
  251.         r.a[0] = audio_data + adatStreamInfo;
  252.         r.a[1] = AudioStatus.mixer;
  253.         Execute68k(audio_data + adatGetSourceData, &r);
  254.         D(bug(" GetSourceData() returns %08lx\n", r.d[0]));
  255.     } else
  256.         WriteMacInt32(audio_data + adatStreamInfo, 0);
  257.  
  258.     // Signal stream function
  259.     sem_post(&audio_irq_done_sem);
  260.     D(bug("AudioInterrupt done\n"));
  261. }
  262.  
  263.  
  264. /*
  265.  *  Set sampling parameters
  266.  *  "index" is an index into the audio_sample_rates[] etc. arrays
  267.  *  It is guaranteed that AudioStatus.num_sources == 0
  268.  */
  269.  
  270. void audio_set_sample_rate(int index)
  271. {
  272. }
  273.  
  274. void audio_set_sample_size(int index)
  275. {
  276. }
  277.  
  278. void audio_set_channels(int index)
  279. {
  280. }
  281.  
  282.  
  283. /*
  284.  *  Get/set volume controls (volume values received/returned have the left channel
  285.  *  volume in the upper 16 bits and the right channel volume in the lower 16 bits;
  286.  *  both volumes are 8.8 fixed point values with 0x0100 meaning "maximum volume"))
  287.  */
  288.  
  289. bool audio_get_main_mute(void)
  290. {
  291.     return false;
  292. }
  293.  
  294. uint32 audio_get_main_volume(void)
  295. {
  296.     return 0x01000100;
  297. }
  298.  
  299. bool audio_get_speaker_mute(void)
  300. {
  301.     return false;
  302. }
  303.  
  304. uint32 audio_get_speaker_volume(void)
  305. {
  306.     return 0x01000100;
  307. }
  308.  
  309. void audio_set_main_mute(bool mute)
  310. {
  311. }
  312.  
  313. void audio_set_main_volume(uint32 vol)
  314. {
  315. }
  316.  
  317. void audio_set_speaker_mute(bool mute)
  318. {
  319. }
  320.  
  321. void audio_set_speaker_volume(uint32 vol)
  322. {
  323. }
  324.