home *** CD-ROM | disk | FTP | other *** search
- /*
- * @(#) cAudioWrap.cpp 0.1, last edit: 04/04/97
- * @(#) Copyright (C) 1997 Pierre Brua (brua@dess-info.u-strasbg.fr)
- *
- *
-
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
- // -------------------------------------------------------------------
- // File Name : cAudioWrap.cpp
- // Created : 1997/03/30
- // Version : 0.1
- // Author : Pierre Brua
- // Distrib :
- // -------------------------------------------------------------------
- // Purpose : Allow an incoming buffered data flow to be
- // transmitted to the audio stream.
- // -------------------------------------------------------------------
- // Todo : (o : todo; / : begin; x : done)
- //
- // -------------------------------------------------------------------
- // History :
- // 1997/03/30 : File created
- // 1997/04/02 : End first goal : it runs !
- //
- // -------------------------------------------------------------------
- // symbol FIXME mark problems to fix.
- // -------------------------------------------------------------------
- // Includes
-
- #include "beos_audiowrap.h"
-
-
- //
- // -------------------------------------------------------------------
- // Class cAudioWrap
-
-
- // Standard services - public
-
- cAudioWrap::~cAudioWrap (void)
- {
- delete_sem(buffer_empty);
- delete_sem(buffer_full);
- delete_sem(memory_access);
- delete(fSubscriber);
- kill_thread(thread_no);
- }
-
- long cAudioWrap::AddData(char *buffer, long size)
- {
- long position; // where we add data in audio_buffer
- // FIXME : this could be avoided in released code
- if(size>BUFFER_SIZE)
- {
- ERRORMSG(true,"buffer size error. Increase BUFFER_SIZE in cAudioWrap.h\n");
- return false;
- }
- acquire_sem(memory_access); // begin critical section
- // we test wether we can add data to the buffer or not
-
- if(acquire_sem_etc(buffer_full, size, B_TIMEOUT, 0.0) != B_WOULD_BLOCK)
- {
- get_sem_count(buffer_empty, &position);
- if((position<BUFFER_SIZE/4)&&activate_warning)
- {
- fprintf(stderr,"buffer is low, music could stop !\n");
- activate_warning = false;
- }
- else
- if(!activate_warning&&(position > BUFFER_SIZE/2))
- activate_warning = true;
- position += buffer_begin;
- position %= BUFFER_SIZE;
- release_sem_etc(buffer_empty, size, B_DO_NOT_RESCHEDULE);
- AddBuffer(buffer, position, size);
- release_sem(memory_access);
- return true;
- }
- // the buffer is full, we wait for 1/2s max until there is room for our data
- else
- {
- release_sem(memory_access);
- if(acquire_sem_etc(buffer_full, size, B_TIMEOUT, FULL_WAITING) == B_TIMED_OUT)
- {// there is a real problem, the buffer is not read... dropping the buffer
- ERRORMSG(true,"lost a buffer in cAudioWrap::AddData : buffer full\n");
- return false;
- }
- else
- {// we can add data now
- // WARNING : if all the buffer is read before we can acquire memory_access,
- // there could be an invalid buffer in the output.
- acquire_sem(memory_access);
- get_sem_count(buffer_empty, &position);
- position += buffer_begin;
- position %= BUFFER_SIZE;
- release_sem_etc(buffer_empty, size, B_DO_NOT_RESCHEDULE);
- AddBuffer(buffer, position, size);
- release_sem(memory_access);
- return true;
- }
- }
- }
-
- // Debug - public
-
- /*inline void cAudioWrap::SelfDisplay (cOStream& thatStream) const
- {
- thatStream << "< class cAudioWrap >" << EndL;
- }
-
- inline bool cAudioWrap::OK (void) const
- {
- return true;
- }*/
-
-
- // Interface - public
-
-
- // Standard services - private
-
- cAudioWrap::cAudioWrap(long nb_channels)
- {
- long *nb2 = (long *)malloc(sizeof(long));
-
- // Creates needed semaphores, to control the size of the buffer
- // semaphores are needed there because the audio buffer size
- // is not customizable yet(crashes the audio_server)
- if((buffer_empty = create_sem(0,"buffer_empty"))<B_NO_ERROR)
- {
- ERRORMSG(true,"Unable to create the buffer_empty semaphore\n");
- exit(-1);
- }
- if((buffer_full = create_sem(BUFFER_SIZE,"buffer_full"))<B_NO_ERROR)
- {
- ERRORMSG(true,"Unable to create the buffer_full semaphore\n");
- exit(-1);
- }
- if((memory_access = create_sem(1,"memory_access"))<B_NO_ERROR)
- {
- ERRORMSG(true,"Unable to create the memory_access semaphore\n");
- exit(-1);
- }
- fSubscriber = new BAudioSubscriber("audiodevice");
-
- nbvoices = nb_channels;
- // audio stream need to have an high priority
- thread_no=spawn_thread(AudioWrap2,"audio filling thread",
- B_REAL_TIME_PRIORITY,(void *)this);
- resume_thread(thread_no);
- }
-
- long AudioWrap2 (void *data2)
- {
- cAudioWrap *data=(cAudioWrap *)data2;
- sleep(BEGINNING_DELAY);//let my father calculate some input data before proceeding
-
- // I try to connect to the B_DAC_STREAM
- if((data->fSubscriberID =
- data->fSubscriber->Subscribe(B_DAC_STREAM,B_SHARED_SUBSCRIBER_ID, TRUE))<B_NO_ERROR)
- {
- ERRORMSG(true,"subscription to audio stream canceled\n");
- exit(-1);
- }
-
- // there was some problems reported when the sampling rate is not set to 44100 in DR8
- data->fSubscriber->SetSamplingRate(44100);
- // FIXME : BIG_ENDIAN ?
- data->fSubscriber->SetDACSampleInfo(BYTES_PER_SAMPLE,data->nbvoices,
- B_BIG_ENDIAN,B_LINEAR_SAMPLES);
-
- // Allow me to receive sound data
- data->fSubscriber->EnterStream(NULL,TRUE,data,
- (enter_stream_hook)FillPlaybackBuffer,
- (exit_stream_hook)EndPlayBack,false);
- data->buffer_begin = 0;
- data->activate_warning = true;
- return 0;
- }
-
- inline cAudioWrap::cAudioWrap (cAudioWrap&)
- {
- }
-
- void cAudioWrap::AddBuffer(char *buffer, long position, long size)
- {
- long buffer_end,// end of the audio_buffer after adding buffer, if it was infinite
- size2; // size of the 2nd part of the buffer when it is cutted
-
- if(position>=BUFFER_SIZE) position = position % BUFFER_SIZE;
- buffer_end=position+size;
- if(buffer_end<=BUFFER_SIZE)
- {
- // the buffer is not cutted...
- memcpy(audio_buffer + position, buffer, size);
- }
- else
- {// the buffer IS cutted
- size2 = buffer_end-BUFFER_SIZE;
- // place the second part at the beginning
- memcpy(audio_buffer, buffer+size-size2, size2);
- // place the first part at the end of the audio_buffer
- memcpy(audio_buffer + position, buffer, size-size2);
- }
- }
-
- //
- // -------------------------------------------------------------------
- // static members
-
-
- // called after the last sound buffer has been processed
- long EndPlayBack(void *UserData, long error)
- {
- // FIXME : to be filled
- if(error != B_NO_ERROR)
- ERRORMSG(true,"error code returned by the BAudioSubscriber\n");
- printf("endplayback\n");
- return 0; // FIXME : ask Be what the return code should be...
- }
-
- bool FillPlaybackBuffer(void *userData, char *bebuffer, long count)
- {
- cAudioWrap *audio = (cAudioWrap *)userData;
- long i, posbuf;
-
- // printf("FillPlaybackBuffer - Received Buffer of size: %d\n",count);
-
- acquire_sem(audio->memory_access);
- if(acquire_sem_etc(audio->buffer_empty, count, B_TIMEOUT, 17000.0) == B_TIMED_OUT)
- {// the buffer is empty ?!?
- printf("buffer empty\n");
- release_sem(audio->memory_access);
- return true;
- }
- else
- {
- release_sem_etc(audio->buffer_full, count, B_DO_NOT_RESCHEDULE);
- // FIXME : this could be made more optimal(i.e. without the %)
- for(i=0,posbuf=audio->buffer_begin; i<count; i++,posbuf++)
- bebuffer[i] += audio->audio_buffer[posbuf%BUFFER_SIZE];
- audio->buffer_begin += count;
- audio->buffer_begin %= BUFFER_SIZE;
- release_sem(audio->memory_access);
- }
- return true;
- }
-
-
- //
- // -------------------------------------------------------------------
-