aboutsummaryrefslogtreecommitdiff
path: root/pd/portaudio/pa_beos/pa_beos_mk.cc
diff options
context:
space:
mode:
authorGuenter Geiger <ggeiger@users.sourceforge.net>2003-05-09 16:04:00 +0000
committerGuenter Geiger <ggeiger@users.sourceforge.net>2003-05-09 16:04:00 +0000
commit9c0e19a3be2288db79e2502e5fa450c3e20a668d (patch)
treeca97ce615e037a533304fc4660dcf372ca3b9cd6 /pd/portaudio/pa_beos/pa_beos_mk.cc
parentef50dd62804d54af7da18d8bd8413c0dccd729b8 (diff)
This commit was generated by cvs2svn to compensate for changes in r610,
which included commits to RCS files with non-trunk default branches. svn path=/trunk/; revision=611
Diffstat (limited to 'pd/portaudio/pa_beos/pa_beos_mk.cc')
-rw-r--r--pd/portaudio/pa_beos/pa_beos_mk.cc441
1 files changed, 441 insertions, 0 deletions
diff --git a/pd/portaudio/pa_beos/pa_beos_mk.cc b/pd/portaudio/pa_beos/pa_beos_mk.cc
new file mode 100644
index 00000000..3307a2ff
--- /dev/null
+++ b/pd/portaudio/pa_beos/pa_beos_mk.cc
@@ -0,0 +1,441 @@
+/*
+ * $Id: pa_beos_mk.cc,v 1.1.1.1 2003-05-09 16:03:53 ggeiger Exp $
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.portaudio.com
+ * BeOS Media Kit Implementation by Joshua Haberman
+ *
+ * Copyright (c) 2001 Joshua Haberman <joshua@haberman.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <be/app/Application.h>
+#include <be/kernel/OS.h>
+#include <be/media/RealtimeAlloc.h>
+#include <be/media/MediaRoster.h>
+#include <be/media/TimeSource.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "portaudio.h"
+#include "pa_host.h"
+
+#include "PlaybackNode.h"
+
+#define PRINT(x) { printf x; fflush(stdout); }
+
+#ifdef DEBUG
+#define DBUG(x) PRINT(x)
+#else
+#define DBUG(x)
+#endif
+
+typedef struct PaHostSoundControl
+{
+ /* These members are common to all modes of operation */
+ media_node pahsc_TimeSource; /* the sound card's DAC. */
+ media_format pahsc_Format;
+
+ /* These methods are specific to playing mode */
+ media_node pahsc_OutputNode; /* output to the mixer */
+ media_node pahsc_InputNode; /* reads data from user callback -- PA specific */
+
+ media_input pahsc_MixerInput; /* input jack on the soundcard's mixer. */
+ media_output pahsc_PaOutput; /* output jack from the PA node */
+
+ PaPlaybackNode *pahsc_InputNodeInstance;
+
+}
+PaHostSoundControl;
+
+/*************************************************************************/
+PaDeviceID Pa_GetDefaultOutputDeviceID( void )
+{
+ /* stub */
+ return 0;
+}
+
+/*************************************************************************/
+PaDeviceID Pa_GetDefaultInputDeviceID( void )
+{
+ /* stub */
+ return 0;
+}
+
+/*************************************************************************/
+const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id )
+{
+ /* stub */
+ return NULL;
+}
+
+/*************************************************************************/
+int Pa_CountDevices()
+{
+ /* stub */
+ return 1;
+}
+
+/*************************************************************************/
+PaError PaHost_Init( void )
+{
+ /* we have to create this in order to use BMediaRoster. I hope it doesn't
+ * cause problems */
+ be_app = new BApplication("application/x-vnd.portaudio-app");
+
+ return paNoError;
+}
+
+PaError PaHost_Term( void )
+{
+ delete be_app;
+ return paNoError;
+}
+
+/*************************************************************************/
+PaError PaHost_StreamActive( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData;
+ DBUG(("IsRunning returning: %s\n",
+ pahsc->pahsc_InputNodeInstance->IsRunning() ? "true" : "false"));
+
+ return (PaError)pahsc->pahsc_InputNodeInstance->IsRunning();
+}
+
+PaError PaHost_StartOutput( internalPortAudioStream *past )
+{
+ return paNoError;
+}
+
+/*************************************************************************/
+PaError PaHost_StartInput( internalPortAudioStream *past )
+{
+ return paNoError;
+}
+
+/*************************************************************************/
+PaError PaHost_StopInput( internalPortAudioStream *past, int abort )
+{
+ return paNoError;
+}
+
+/*************************************************************************/
+PaError PaHost_StopOutput( internalPortAudioStream *past, int abort )
+{
+ return paNoError;
+}
+
+
+/*************************************************************************/
+PaError PaHost_StartEngine( internalPortAudioStream *past )
+{
+ bigtime_t very_soon, start_latency;
+ status_t err;
+ BMediaRoster *roster = BMediaRoster::Roster(&err);
+ PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData;
+
+ /* for some reason, err indicates an error (though nothing it wrong)
+ * when the DBUG macro in pa_lib.c is enabled. It's reproducably
+ * linked. Weird. */
+ if( !roster /* || err != B_OK */ )
+ {
+ DBUG(("No media server! err=%d, roster=%x\n", err, roster));
+ return paHostError;
+ }
+
+ /* tell the node when to start -- since there aren't any other nodes
+ * starting that we have to wait for, just tell it to start now
+ */
+
+ BTimeSource *timeSource = roster->MakeTimeSourceFor(pahsc->pahsc_TimeSource);
+ very_soon = timeSource->PerformanceTimeFor( BTimeSource::RealTime() );
+ timeSource->Release();
+
+ /* Add the latency of starting the network of nodes */
+ err = roster->GetStartLatencyFor( pahsc->pahsc_TimeSource, &start_latency );
+ very_soon += start_latency;
+
+ err = roster->StartNode( pahsc->pahsc_InputNode, very_soon );
+ /* No need to start the mixer -- it's always running */
+
+ return paNoError;
+}
+
+
+/*************************************************************************/
+PaError PaHost_StopEngine( internalPortAudioStream *past, int abort )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData;
+ BMediaRoster *roster = BMediaRoster::Roster();
+
+ if( !roster )
+ {
+ DBUG(("No media roster!\n"));
+ return paHostError;
+ }
+
+ if( !pahsc )
+ return paHostError;
+
+ /* this crashes, and I don't know why yet */
+ // if( abort )
+ // pahsc->pahsc_InputNodeInstance->mAborted = true;
+
+ roster->StopNode(pahsc->pahsc_InputNode, 0, /* immediate = */ true);
+
+ return paNoError;
+}
+
+
+/*************************************************************************/
+PaError PaHost_OpenStream( internalPortAudioStream *past )
+{
+ status_t err;
+ BMediaRoster *roster = BMediaRoster::Roster(&err);
+ PaHostSoundControl *pahsc;
+
+ /* Allocate and initialize host data. */
+ pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl));
+ if( pahsc == NULL )
+ {
+ goto error;
+ }
+ memset( pahsc, 0, sizeof(PaHostSoundControl) );
+ past->past_DeviceData = (void *) pahsc;
+
+ if( !roster /* || err != B_OK */ )
+ {
+ /* no media server! */
+ DBUG(("No media server.\n"));
+ goto error;
+ }
+
+ if ( past->past_NumInputChannels > 0 && past->past_NumOutputChannels > 0 )
+ {
+ /* filter -- not implemented yet */
+ goto error;
+ }
+ else if ( past->past_NumInputChannels > 0 )
+ {
+ /* recorder -- not implemented yet */
+ goto error;
+ }
+ else
+ {
+ /* player ****************************************************************/
+
+ status_t err;
+ int32 num;
+
+ /* First we need to create the three components (like components in a stereo
+ * system). The mixer component is our interface to the sound card, data
+ * we write there will get played. The BePA_InputNode component is the node
+ * which represents communication with the PA client (it is what calls the
+ * client's callbacks). The time source component is the sound card's DAC,
+ * which allows us to slave the other components to it instead of the system
+ * clock. */
+ err = roster->GetAudioMixer( &pahsc->pahsc_OutputNode );
+ if( err != B_OK )
+ {
+ DBUG(("Couldn't get default mixer.\n"));
+ goto error;
+ }
+
+ err = roster->GetTimeSource( &pahsc->pahsc_TimeSource );
+ if( err != B_OK )
+ {
+ DBUG(("Couldn't get time source.\n"));
+ goto error;
+ }
+
+ pahsc->pahsc_InputNodeInstance = new PaPlaybackNode(2, 44100,
+ past->past_FramesPerUserBuffer, past->past_Callback, past->past_UserData );
+ pahsc->pahsc_InputNodeInstance->SetSampleFormat(0,
+ past->past_OutputSampleFormat);
+ err = roster->RegisterNode( pahsc->pahsc_InputNodeInstance );
+ if( err != B_OK )
+ {
+ DBUG(("Unable to register node.\n"));
+ goto error;
+ }
+
+ roster->GetNodeFor( pahsc->pahsc_InputNodeInstance->Node().node,
+ &pahsc->pahsc_InputNode );
+ if( err != B_OK )
+ {
+ DBUG(("Unable to get input node.\n"));
+ goto error;
+ }
+
+ /* Now we have three components (nodes) sitting next to each other. The
+ * next step is to look at them and find their inputs and outputs so we can
+ * wire them together. */
+ err = roster->GetFreeInputsFor( pahsc->pahsc_OutputNode,
+ &pahsc->pahsc_MixerInput, 1, &num, B_MEDIA_RAW_AUDIO );
+ if( err != B_OK || num < 1 )
+ {
+ DBUG(("Couldn't get the mixer input.\n"));
+ goto error;
+ }
+
+ err = roster->GetFreeOutputsFor( pahsc->pahsc_InputNode,
+ &pahsc->pahsc_PaOutput, 1, &num, B_MEDIA_RAW_AUDIO );
+ if( err != B_OK || num < 1 )
+ {
+ DBUG(("Couldn't get PortAudio output.\n"));
+ goto error;
+ }
+
+
+ /* We've found the input and output -- the final step is to run a wire
+ * between them so they are connected. */
+
+ /* try to make the mixer input adapt to what PA sends it */
+ pahsc->pahsc_Format = pahsc->pahsc_PaOutput.format;
+ roster->Connect( pahsc->pahsc_PaOutput.source,
+ pahsc->pahsc_MixerInput.destination, &pahsc->pahsc_Format,
+ &pahsc->pahsc_PaOutput, &pahsc->pahsc_MixerInput );
+
+
+ /* Actually, there's one final step -- tell them all to sync to the
+ * sound card's DAC */
+ roster->SetTimeSourceFor( pahsc->pahsc_InputNode.node,
+ pahsc->pahsc_TimeSource.node );
+ roster->SetTimeSourceFor( pahsc->pahsc_OutputNode.node,
+ pahsc->pahsc_TimeSource.node );
+
+ }
+
+ return paNoError;
+
+error:
+ PaHost_CloseStream( past );
+ return paHostError;
+}
+
+/*************************************************************************/
+PaError PaHost_CloseStream( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData;
+ status_t err;
+ BMediaRoster *roster = BMediaRoster::Roster(&err);
+
+ if( !roster )
+ {
+ DBUG(("Couldn't get media roster\n"));
+ return paHostError;
+ }
+
+ if( !pahsc )
+ return paHostError;
+
+ /* Disconnect all the connections we made when opening the stream */
+
+ roster->Disconnect(pahsc->pahsc_InputNode.node, pahsc->pahsc_PaOutput.source,
+ pahsc->pahsc_OutputNode.node, pahsc->pahsc_MixerInput.destination);
+
+ DBUG(("Calling ReleaseNode()"));
+ roster->ReleaseNode(pahsc->pahsc_InputNode);
+
+ /* deleting the node shouldn't be necessary -- it is reference counted, and will
+ * delete itself when its references drop to zero. the call to ReleaseNode()
+ * above should decrease its reference count */
+ pahsc->pahsc_InputNodeInstance = NULL;
+
+ return paNoError;
+}
+
+/*************************************************************************/
+PaTimestamp Pa_StreamTime( PortAudioStream *stream )
+{
+ internalPortAudioStream *past = (internalPortAudioStream *) stream;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData;
+
+ return pahsc->pahsc_InputNodeInstance->GetStreamTime();
+}
+
+/*************************************************************************/
+void Pa_Sleep( long msec )
+{
+ /* snooze() takes microseconds */
+ snooze( msec * 1000 );
+}
+
+/*************************************************************************
+ * Allocate memory that can be accessed in real-time.
+ * This may need to be held in physical memory so that it is not
+ * paged to virtual memory.
+ * This call MUST be balanced with a call to PaHost_FreeFastMemory().
+ * Memory will be set to zero.
+ */
+void *PaHost_AllocateFastMemory( long numBytes )
+{
+ /* BeOS supports non-pagable memory through pools -- a pool is an area
+ * of physical memory that is locked. It would be best to pre-allocate
+ * that pool and then hand out memory from it, but we don't know in
+ * advance how much we'll need. So for now, we'll allocate a pool
+ * for every request we get, storing a pointer to the pool at the
+ * beginning of the allocated memory */
+ rtm_pool *pool;
+ void *addr;
+ long size = numBytes + sizeof(rtm_pool *);
+ static int counter = 0;
+ char pool_name[100];
+
+ /* Every pool needs a unique name. */
+ sprintf(pool_name, "PaPoolNumber%d", counter++);
+
+ if( rtm_create_pool( &pool, size, pool_name ) != B_OK )
+ return 0;
+
+ addr = rtm_alloc( pool, size );
+ if( addr == NULL )
+ return 0;
+
+ memset( addr, 0, numBytes );
+ *((rtm_pool **)addr) = pool; // store the pointer to the pool
+ addr = (rtm_pool **)addr + 1; // and return the next location in memory
+
+ return addr;
+}
+
+/*************************************************************************
+ * Free memory that could be accessed in real-time.
+ * This call MUST be balanced with a call to PaHost_AllocateFastMemory().
+ */
+void PaHost_FreeFastMemory( void *addr, long numBytes )
+{
+ rtm_pool *pool;
+
+ if( addr == NULL )
+ return;
+
+ addr = (rtm_pool **)addr - 1;
+ pool = *((rtm_pool **)addr);
+
+ rtm_free( addr );
+ rtm_delete_pool( pool );
+}