home *** CD-ROM | disk | FTP | other *** search
/ Windows 95 Secrets / Secrets2.iso / Audio / WAV / MaplayP / _SETUP.1 / beos_audiowrap.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-08  |  7.8 KB  |  265 lines

  1. /*
  2.  *  @(#) cAudioWrap.cpp 0.1, last edit: 04/04/97
  3.  *  @(#) Copyright (C) 1997 Pierre Brua (brua@dess-info.u-strasbg.fr)
  4.  * 
  5.  *
  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. // -------------------------------------------------------------------
  22. // File Name : cAudioWrap.cpp
  23. // Created   : 1997/03/30
  24. // Version   : 0.1
  25. // Author    : Pierre Brua
  26. // Distrib   :
  27. // -------------------------------------------------------------------
  28. // Purpose   : Allow an incoming buffered data flow to be
  29. //             transmitted to the audio stream.
  30. // -------------------------------------------------------------------
  31. // Todo : (o : todo; / : begin; x : done)
  32. //
  33. // -------------------------------------------------------------------
  34. // History :
  35. //     1997/03/30 : File created
  36. //     1997/04/02 : End first goal : it runs !
  37. //
  38. // -------------------------------------------------------------------
  39. // symbol FIXME mark problems to fix. 
  40. // -------------------------------------------------------------------
  41. // Includes
  42.  
  43. #include "beos_audiowrap.h"
  44.  
  45.  
  46. //
  47. // -------------------------------------------------------------------
  48. // Class cAudioWrap
  49.  
  50.  
  51. // Standard services - public
  52.  
  53. cAudioWrap::~cAudioWrap (void)
  54. {
  55.     delete_sem(buffer_empty);
  56.     delete_sem(buffer_full);
  57.     delete_sem(memory_access);
  58.     delete(fSubscriber);
  59.     kill_thread(thread_no);
  60. }
  61.  
  62. long cAudioWrap::AddData(char *buffer, long size)
  63. {
  64.     long position; // where we add data in audio_buffer
  65. // FIXME : this could be avoided in released code
  66.     if(size>BUFFER_SIZE)
  67.     {
  68.         ERRORMSG(true,"buffer size error. Increase BUFFER_SIZE in cAudioWrap.h\n");
  69.         return false;
  70.     }
  71.     acquire_sem(memory_access); // begin critical section
  72.     // we test wether we can add data to the buffer or not
  73.     
  74.     if(acquire_sem_etc(buffer_full, size, B_TIMEOUT, 0.0) != B_WOULD_BLOCK)
  75.     {
  76.         get_sem_count(buffer_empty, &position);
  77.         if((position<BUFFER_SIZE/4)&&activate_warning) 
  78.         {
  79.             fprintf(stderr,"buffer is low, music could stop !\n");
  80.             activate_warning = false;
  81.         }
  82.         else 
  83.             if(!activate_warning&&(position > BUFFER_SIZE/2)) 
  84.                 activate_warning = true;
  85.         position += buffer_begin;
  86.         position %= BUFFER_SIZE;
  87.         release_sem_etc(buffer_empty, size, B_DO_NOT_RESCHEDULE);
  88.         AddBuffer(buffer, position, size);
  89.         release_sem(memory_access);
  90.         return true;
  91.     }
  92.     // the buffer is full, we wait for 1/2s max until there is room for our data
  93.     else
  94.     {
  95.         release_sem(memory_access);
  96.         if(acquire_sem_etc(buffer_full, size, B_TIMEOUT, FULL_WAITING) == B_TIMED_OUT)
  97.         {// there is a real problem, the buffer is not read... dropping the buffer
  98.             ERRORMSG(true,"lost a buffer in cAudioWrap::AddData : buffer full\n");
  99.             return false;
  100.         }
  101.         else
  102.         {// we can add data now
  103.             // WARNING : if all the buffer is read before we can acquire memory_access,
  104.             //           there could be an invalid buffer in the output.
  105.             acquire_sem(memory_access);
  106.             get_sem_count(buffer_empty, &position);
  107.             position += buffer_begin;
  108.             position %= BUFFER_SIZE;
  109.             release_sem_etc(buffer_empty, size, B_DO_NOT_RESCHEDULE);
  110.             AddBuffer(buffer, position, size);
  111.             release_sem(memory_access);
  112.             return true;
  113.         }
  114.     }
  115. }
  116.  
  117. // Debug - public
  118.  
  119. /*inline void cAudioWrap::SelfDisplay (cOStream& thatStream) const
  120. {
  121.     thatStream << "< class cAudioWrap >" << EndL;
  122. }
  123.  
  124. inline bool cAudioWrap::OK (void) const
  125. {
  126.     return true;
  127. }*/
  128.  
  129.  
  130. // Interface - public
  131.  
  132.  
  133. // Standard services - private
  134.  
  135. cAudioWrap::cAudioWrap(long nb_channels)
  136. {
  137.     long *nb2 = (long *)malloc(sizeof(long));
  138.  
  139.     // Creates needed semaphores, to control the size of the buffer
  140.     // semaphores are needed there because the audio buffer size
  141.     // is not customizable yet(crashes the audio_server)
  142.     if((buffer_empty = create_sem(0,"buffer_empty"))<B_NO_ERROR)
  143.     {
  144.         ERRORMSG(true,"Unable to create the buffer_empty semaphore\n");
  145.         exit(-1);
  146.     }
  147.     if((buffer_full = create_sem(BUFFER_SIZE,"buffer_full"))<B_NO_ERROR)
  148.     {
  149.         ERRORMSG(true,"Unable to create the buffer_full semaphore\n");
  150.         exit(-1);
  151.     }
  152.     if((memory_access = create_sem(1,"memory_access"))<B_NO_ERROR)
  153.     {
  154.         ERRORMSG(true,"Unable to create the memory_access semaphore\n");
  155.         exit(-1);
  156.     }
  157.     fSubscriber = new BAudioSubscriber("audiodevice");
  158.  
  159.     nbvoices = nb_channels;
  160.     // audio stream need to have an high priority
  161.     thread_no=spawn_thread(AudioWrap2,"audio filling thread",
  162.         B_REAL_TIME_PRIORITY,(void *)this);    
  163.     resume_thread(thread_no);
  164. }
  165.  
  166. long AudioWrap2 (void *data2)
  167. {
  168.     cAudioWrap *data=(cAudioWrap *)data2;        
  169.     sleep(BEGINNING_DELAY);//let my father calculate some input data before proceeding
  170.  
  171.     // I try to connect to the B_DAC_STREAM
  172.     if((data->fSubscriberID = 
  173.         data->fSubscriber->Subscribe(B_DAC_STREAM,B_SHARED_SUBSCRIBER_ID, TRUE))<B_NO_ERROR)
  174.     {
  175.         ERRORMSG(true,"subscription to audio stream canceled\n");
  176.         exit(-1);
  177.     }
  178.   
  179.     // there was some problems reported when the sampling rate is not set to 44100 in DR8
  180.     data->fSubscriber->SetSamplingRate(44100);
  181.     // FIXME : BIG_ENDIAN ?
  182.     data->fSubscriber->SetDACSampleInfo(BYTES_PER_SAMPLE,data->nbvoices,
  183.         B_BIG_ENDIAN,B_LINEAR_SAMPLES);
  184.  
  185.     // Allow me to receive sound data
  186.     data->fSubscriber->EnterStream(NULL,TRUE,data,
  187.         (enter_stream_hook)FillPlaybackBuffer,
  188.         (exit_stream_hook)EndPlayBack,false);
  189.     data->buffer_begin = 0;
  190.     data->activate_warning = true;
  191.     return 0;
  192. }
  193.  
  194. inline cAudioWrap::cAudioWrap (cAudioWrap&)
  195. {
  196. }
  197.  
  198. void cAudioWrap::AddBuffer(char *buffer, long position, long size)
  199. {
  200.     long buffer_end,// end of the audio_buffer after adding buffer, if it was infinite
  201.         size2;        // size of the 2nd part of the buffer when it is cutted
  202.     
  203.     if(position>=BUFFER_SIZE) position = position % BUFFER_SIZE;
  204.     buffer_end=position+size;
  205.     if(buffer_end<=BUFFER_SIZE)
  206.     {
  207.         // the buffer is not cutted...
  208.         memcpy(audio_buffer + position, buffer, size);
  209.     }
  210.     else
  211.     {// the buffer IS cutted
  212.         size2 = buffer_end-BUFFER_SIZE;
  213.         // place the second part at the beginning
  214.         memcpy(audio_buffer, buffer+size-size2, size2);
  215.         // place the first part at the end of the audio_buffer
  216.         memcpy(audio_buffer + position, buffer, size-size2);
  217.     }
  218. }
  219.  
  220. //
  221. // -------------------------------------------------------------------
  222. // static members
  223.  
  224.  
  225. // called after the last sound buffer has been processed
  226. long EndPlayBack(void *UserData, long error)
  227. {
  228.     // FIXME : to be filled
  229.     if(error != B_NO_ERROR)
  230.         ERRORMSG(true,"error code returned by the BAudioSubscriber\n");
  231.     printf("endplayback\n");
  232.     return 0; // FIXME : ask Be what the return code should be...
  233. }
  234.  
  235. bool FillPlaybackBuffer(void *userData, char *bebuffer, long count)
  236. {
  237.     cAudioWrap *audio = (cAudioWrap *)userData;
  238.     long i, posbuf;
  239.     
  240. //    printf("FillPlaybackBuffer - Received Buffer of size: %d\n",count);
  241.         
  242.     acquire_sem(audio->memory_access);
  243.     if(acquire_sem_etc(audio->buffer_empty, count, B_TIMEOUT, 17000.0) == B_TIMED_OUT)
  244.     {// the buffer is empty ?!?
  245.         printf("buffer empty\n");
  246.         release_sem(audio->memory_access);
  247.         return true;
  248.     }
  249.     else
  250.     {
  251.         release_sem_etc(audio->buffer_full, count, B_DO_NOT_RESCHEDULE);
  252.         // FIXME : this could be made more optimal(i.e. without the %)
  253.         for(i=0,posbuf=audio->buffer_begin; i<count; i++,posbuf++)
  254.             bebuffer[i] += audio->audio_buffer[posbuf%BUFFER_SIZE];
  255.         audio->buffer_begin += count;
  256.         audio->buffer_begin %= BUFFER_SIZE;
  257.         release_sem(audio->memory_access);
  258.     }
  259.     return true;
  260. }
  261.  
  262.  
  263. //
  264. // -------------------------------------------------------------------
  265.