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

  1. /*
  2.  *  audio_beos.cpp - Audio support, BeOS implementation
  3.  *
  4.  *  Basilisk II (C) 1997-1999 Christian Bauer
  5.  *  Portions (C) 1997-1999 Marc Hellwig
  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  20.  */
  21.  
  22. #include "sysdeps.h"
  23.  
  24. #include <KernelKit.h>
  25. #include <MediaKit.h>
  26.  
  27. #include "cpu_emulation.h"
  28. #include "main.h"
  29. #include "prefs.h"
  30. #include "user_strings.h"
  31. #include "audio.h"
  32. #include "audio_defs.h"
  33.  
  34. #define DEBUG 0
  35. #include "debug.h"
  36.  
  37.  
  38. // Supported sample rates, sizes and channels
  39. int audio_num_sample_rates = 1;
  40. uint32 audio_sample_rates[] = {44100 << 16};
  41. int audio_num_sample_sizes = 1;
  42. uint16 audio_sample_sizes[] = {16};
  43. int audio_num_channel_counts = 1;
  44. uint16 audio_channel_counts[] = {2};
  45.  
  46. // Global variables
  47. static int audio_irq_done_sem = -1;    // Signal from interrupt to streaming thread: data block read
  48. static BSoundPlayer *the_player;
  49.  
  50. // Prototypes
  51. static void playbuffer_func(void *arg, void *buf, size_t size, const media_raw_audio_format &format);
  52.  
  53.  
  54. /*
  55.  *  Audio manager thread (for calling media kit functions;
  56.  *  this is not safe under R4 when running on the MacOS stack in kernel space)
  57.  */
  58.  
  59. // Message constants
  60. const uint32 MSG_QUIT_AUDIO_MANAGER = 'quit';
  61. const uint32 MSG_ENTER_STREAM = 'entr';
  62. const uint32 MSG_EXIT_STREAM = 'exit';
  63. const uint32 MSG_GET_VOLUME = 'getv';
  64. const uint32 MSG_SET_VOLUME = 'setv';
  65.  
  66. static thread_id am_thread = -1;
  67. static sem_id am_done_sem = -1;
  68.  
  69. static volatile float am_volume;
  70.  
  71. static status_t audio_manager(void *arg)
  72. {
  73.     for (;;) {
  74.  
  75.         // Receive message
  76.         thread_id sender;
  77.         uint32 code = receive_data(&sender, NULL, 0);
  78.         D(bug("Audio manager received %08lx\n", code));
  79.         switch (code) {
  80.             case MSG_QUIT_AUDIO_MANAGER:
  81.                 return 0;
  82.  
  83.             case MSG_ENTER_STREAM:
  84.                 the_player->Start();
  85.                 break;
  86.  
  87.             case MSG_EXIT_STREAM:
  88.                 the_player->Stop();
  89.                 break;
  90.  
  91.             case MSG_GET_VOLUME:
  92.                 am_volume = the_player->Volume();
  93.                 break;
  94.  
  95.             case MSG_SET_VOLUME:
  96.                 the_player->SetVolume(am_volume);
  97.                 break;
  98.         }
  99.  
  100.         // Acknowledge
  101.         release_sem(am_done_sem);
  102.     }
  103. }
  104.  
  105.  
  106. /*
  107.  *  Initialization
  108.  */
  109.  
  110. void AudioInit(void)
  111. {
  112.     // Init audio status and feature flags
  113.     AudioStatus.sample_rate = audio_sample_rates[0];
  114.     AudioStatus.sample_size = audio_sample_sizes[0];
  115.     AudioStatus.channels = audio_channel_counts[0];
  116.     AudioStatus.mixer = 0;
  117.     AudioStatus.num_sources = 0;
  118.     audio_component_flags = cmpWantsRegisterMessage | kStereoOut | k16BitOut;
  119.  
  120.     // Sound disabled in prefs? Then do nothing
  121.     if (PrefsFindBool("nosound"))
  122.         return;
  123.  
  124.     // Init semaphores
  125.     audio_irq_done_sem = create_sem(0, "Audio IRQ Done");
  126.     am_done_sem = create_sem(0, "Audio Manager Done");
  127.  
  128.     // Start audio manager thread
  129.     am_thread = spawn_thread(audio_manager, "Audio Manager", B_NORMAL_PRIORITY, NULL);
  130.     resume_thread(am_thread);
  131.  
  132.     // Start stream
  133.     media_raw_audio_format format;
  134.     format.frame_rate = AudioStatus.sample_rate >> 16;
  135.     format.channel_count = AudioStatus.channels;
  136.     format.format = media_raw_audio_format::B_AUDIO_SHORT;
  137.     format.byte_order = B_MEDIA_BIG_ENDIAN;
  138.     audio_frames_per_block = 4096;
  139.     size_t block_size = (AudioStatus.sample_size >> 3) * AudioStatus.channels * audio_frames_per_block;
  140.     D(bug("AudioInit: block size %d\n", block_size));
  141.     format.buffer_size = block_size;
  142.     the_player = new BSoundPlayer(&format, "MacOS Audio", playbuffer_func, NULL, NULL);
  143.     if (the_player->InitCheck() != B_NO_ERROR) {
  144.         printf("FATAL: Cannot initialize BSoundPlayer\n");
  145.         delete the_player;
  146.         the_player = NULL;
  147.         return;
  148.     } else
  149.         the_player->SetHasData(true);
  150.  
  151.     // Everything OK
  152.     audio_open = true;
  153. }
  154.  
  155.  
  156. /*
  157.  *  Deinitialization
  158.  */
  159.  
  160. void AudioExit(void)
  161. {
  162.     // Stop stream
  163.     if (the_player) {
  164.         the_player->Stop();
  165.         delete the_player;
  166.         the_player = NULL;
  167.     }
  168.  
  169.     // Stop audio manager
  170.     if (am_thread > 0) {
  171.         status_t l;
  172.         send_data(am_thread, MSG_QUIT_AUDIO_MANAGER, NULL, 0);
  173.         wait_for_thread(am_thread, &l);
  174.     }
  175.  
  176.     // Delete semaphores
  177.     delete_sem(am_done_sem);
  178.     delete_sem(audio_irq_done_sem);
  179. }
  180.  
  181.  
  182. /*
  183.  *  First source added, start audio stream
  184.  */
  185.  
  186. void audio_enter_stream()
  187. {
  188.     while (send_data(am_thread, MSG_ENTER_STREAM, NULL, 0) == B_INTERRUPTED) ;
  189.     while (acquire_sem(am_done_sem) == B_INTERRUPTED) ;
  190. }
  191.  
  192.  
  193. /*
  194.  *  Last source removed, stop audio stream
  195.  */
  196.  
  197. void audio_exit_stream()
  198. {
  199.     while (send_data(am_thread, MSG_EXIT_STREAM, NULL, 0) == B_INTERRUPTED) ;
  200.     while (acquire_sem(am_done_sem) == B_INTERRUPTED) ;
  201. }
  202.  
  203.  
  204. /*
  205.  *  Streaming function
  206.  */
  207.  
  208. static uint32 apple_stream_info;    // Mac address of SoundComponentData struct describing next buffer
  209.  
  210. static void playbuffer_func(void *arg, void *buf, size_t size, const media_raw_audio_format &format)
  211. {
  212.     // Check if new buffer is available
  213.     if (acquire_sem_etc(audio_irq_done_sem, 1, B_TIMEOUT, 0) == B_NO_ERROR) {
  214.  
  215.         // Get size of audio data
  216.         D(bug("stream: new buffer present\n"));
  217.         uint32 apple_stream_info = ReadMacInt32(audio_data + adatStreamInfo);
  218.         if (apple_stream_info) {
  219.             size_t work_size = ReadMacInt32(apple_stream_info + scd_sampleCount) * (AudioStatus.sample_size >> 3) * AudioStatus.channels;
  220.             D(bug("stream: size %d, work_size %d\n", size, work_size));
  221.             if (work_size > size)
  222.                 work_size = size;
  223.  
  224.             if (format.format != media_raw_audio_format::B_AUDIO_SHORT) {
  225.                 D(bug("Wrong audio format %04x\n", format.format));
  226.                 return;
  227.             }
  228.  
  229.             // Place data into Media Kit buffer
  230.             Mac2Host_memcpy(buf, ReadMacInt32(apple_stream_info + scd_buffer), work_size);
  231.             if (work_size != size)
  232.                 memset((uint8 *)buf + work_size, 0, size - work_size);
  233.         }
  234.  
  235.     } else
  236.         memset(buf, 0, size);
  237.  
  238.     // Trigger audio interrupt to get new buffer
  239.     if (AudioStatus.num_sources) {
  240.         D(bug("stream: triggering irq\n"));
  241.         SetInterruptFlag(INTFLAG_AUDIO);
  242.         TriggerInterrupt();
  243.     }
  244. }
  245.  
  246.  
  247. /*
  248.  *  MacOS audio interrupt, read next data block
  249.  */
  250.  
  251. void AudioInterrupt(void)
  252. {
  253.     D(bug("AudioInterrupt\n"));
  254.  
  255.     // Get data from apple mixer
  256.     if (AudioStatus.mixer) {
  257.         M68kRegisters r;
  258.         r.a[0] = audio_data + adatStreamInfo;
  259.         r.a[1] = AudioStatus.mixer;
  260.         Execute68k(audio_data + adatGetSourceData, &r);
  261.         D(bug(" GetSourceData() returns %08lx\n", r.d[0]));
  262.     } else
  263.         WriteMacInt32(audio_data + adatStreamInfo, 0);
  264.  
  265.     // Signal stream function
  266.     release_sem(audio_irq_done_sem);
  267.     D(bug("AudioInterrupt done\n"));
  268. }
  269.  
  270.  
  271. /*
  272.  *  Set sampling parameters
  273.  *  "index" is an index into the audio_sample_rates[] etc. arrays
  274.  *  It is guaranteed that AudioStatus.num_sources == 0
  275.  */
  276.  
  277. void audio_set_sample_rate(int index)
  278. {
  279. }
  280.  
  281. void audio_set_sample_size(int index)
  282. {
  283. }
  284.  
  285. void audio_set_channels(int index)
  286. {
  287. }
  288.  
  289.  
  290. /*
  291.  *  Get/set audio info
  292.  */
  293.  
  294. bool audio_get_main_mute(void)
  295. {
  296.     return false;
  297. }
  298.  
  299. uint32 audio_get_main_volume(void)
  300. {
  301.     if (audio_open) {
  302.         while (send_data(am_thread, MSG_GET_VOLUME, NULL, 0) == B_INTERRUPTED) ;
  303.         while (acquire_sem(am_done_sem) == B_INTERRUPTED) ;
  304.         return int(am_volume * 256.0) * 0x00010001;
  305.     } else
  306.         return 0x01000100;
  307. }
  308.  
  309. bool audio_get_speaker_mute(void)
  310. {
  311.     return false;
  312. }
  313.  
  314. uint32 audio_get_speaker_volume(void)
  315. {
  316.     return 0x01000100;
  317. }
  318.  
  319. void audio_set_main_mute(bool mute)
  320. {
  321. }
  322.  
  323. void audio_set_main_volume(uint32 vol)
  324. {
  325.     if (audio_open) {
  326.         am_volume = float((vol >> 16) + (vol & 0xffff)) / 512.0;
  327.         while (send_data(am_thread, MSG_SET_VOLUME, NULL, 0) == B_INTERRUPTED) ;
  328.         while (acquire_sem(am_done_sem) == B_INTERRUPTED) ;
  329.     }
  330. }
  331.  
  332. void audio_set_speaker_mute(bool mute)
  333. {
  334. }
  335.  
  336. void audio_set_speaker_volume(uint32 vol)
  337. {
  338. }
  339.