David Shipman started implementing the BeOS system audio mixer.

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@681 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
beveloper
2002-08-09 23:55:28 +00:00
parent bbab11ba30
commit 00cffa1ce7
7 changed files with 1619 additions and 0 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,208 @@
// AudioMixer.h
/*
By David Shipman, 2002
*/
#ifndef _AUDIOMIXER_H
#define _AUDIOMIXER_H
// forward declarations
class input_channel;
// includes
#include <media/BufferGroup.h>
#include <media/MediaNode.h>
#include <media/BufferConsumer.h>
#include <media/BufferProducer.h>
#include <media/Controllable.h>
#include <media/MediaEventLooper.h>
// ----------------
// AudioMixer class
class AudioMixer :
public BBufferConsumer,
public BBufferProducer,
public BControllable,
public BMediaEventLooper
{
public:
AudioMixer(BMediaAddOn *addOn);
~AudioMixer();
// Our own (AudioMixer) methods
bool IsValidDest( media_destination dest);
bool IsValidSource( media_source source);
status_t ResolveDest(int32 dest, input_channel *outchannel);
status_t ResolveDest(media_destination dest, input_channel *outchannel);
void AllocateBuffers();
// BMediaNode methods
BMediaAddOn * AddOn(int32*) const;
// void SetRunMode(run_mode);
// void Preroll();
// void SetTimeSource(BTimeSource* time_source);
// status_t RequestCompleted(const media_request_info & info);
protected:
// BControllable methods
status_t GetParameterValue( int32 id, bigtime_t* last_change,
void* value,
size_t* ioSize);
void SetParameterValue( int32 id, bigtime_t when,
const void* value,
size_t size);
// BBufferConsumer methods
status_t HandleMessage( int32 message,
const void* data,
size_t size);
status_t AcceptFormat( const media_destination &dest, media_format *format);
status_t GetNextInput( int32 *cookie,
media_input *out_input);
void DisposeInputCookie( int32 cookie);
void BufferReceived( BBuffer *buffer);
void ProducerDataStatus( const media_destination &for_whom,
int32 status,
bigtime_t at_performance_time);
status_t GetLatencyFor( const media_destination &for_whom,
bigtime_t *out_latency,
media_node_id *out_timesource);
status_t Connected( const media_source &producer,
const media_destination &where,
const media_format &with_format,
media_input *out_input);
void Disconnected( const media_source &producer,
const media_destination &where);
status_t FormatChanged( const media_source &producer,
const media_destination &consumer,
int32 change_tag,
const media_format &format);
//
// BBufferProducer methods
//
status_t FormatSuggestionRequested( media_type type,
int32 quality,
media_format *format);
status_t FormatProposal(
const media_source& output,
media_format* format);
//
// /* If the format isn't good, put a good format into *io_format and return error */
// /* If format has wildcard, specialize to what you can do (and change). */
// /* If you can change the format, return OK. */
// /* The request comes from your destination sychronously, so you cannot ask it */
// /* whether it likes it -- you should assume it will since it asked. */
status_t FormatChangeRequested(
const media_source& source,
const media_destination& destination,
media_format* io_format,
int32* _deprecated_);
status_t GetNextOutput( /* cookie starts as 0 */
int32* cookie,
media_output* out_output);
status_t DisposeOutputCookie(
int32 cookie);
status_t SetBufferGroup(
const media_source& for_source,
BBufferGroup* group);
status_t GetLatency(
bigtime_t* out_latency);
status_t PrepareToConnect(
const media_source& what,
const media_destination& where,
media_format* format,
media_source* out_source,
char* out_name);
void Connect(
status_t error,
const media_source& source,
const media_destination& destination,
const media_format& format,
char* io_name);
void Disconnect(
const media_source& what,
const media_destination& where);
void LateNoticeReceived(
const media_source& what,
bigtime_t how_much,
bigtime_t performance_time);
void EnableOutput(
const media_source & what,
bool enabled,
int32* _deprecated_);
// BMediaEventLooper methods
virtual void NodeRegistered();
void HandleEvent( const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent = false);
// handle mixing in separate thread
// not implemented (yet)
static int32 _mix_thread_(void *data);
int32 MixThread();
private:
thread_id fThread; // for launching mixthread
media_input fInput; // descriptor of single input (temp)
media_output fOutput; // single output (temp)
BMediaAddOn * fAddOn;
BParameterWeb * fWeb; // local pointer to parameterweb
bigtime_t fLatency, fInternalLatency; // latency (total and internal)
bigtime_t fStartTime, fNextEventTime; // time node started, time of next (output) event
uint64 fFramesSent; // audio frames sent
bool fOutputEnabled;
media_format fPrefInputFormat, fPrefOutputFormat;
BBufferGroup * fBufferGroup;
BList fInputChannels;
};
#endif
@@ -0,0 +1,27 @@
// IOStructures.h
/*
Structures to represent IO channels in the AudioMixer node
By David Shipman, 2002
*/
#ifndef _IO_STRUCT_H
#define _IO_STRUCT_H
struct input_channel
{
public:
media_input fInput;
int32 fProducerDataStatus; // status of upstream data
bool DataAvailable; // there is a buffer ready for mixing
char * fData;
size_t fEventOffset; // offset (in bytes)
size_t fDataSize; // size of ringbuffer
};
#endif;
@@ -0,0 +1,84 @@
// MixerAddOn.cpp
//
// David Shipman, 2002
// allows AudioMixer to be used as an addon
//
#include "AudioMixer.h"
#include "MixerAddOn.h"
#include <cstring>
#include <cstdlib>
// instantiation function
extern "C" _EXPORT BMediaAddOn* make_media_addon(image_id image) {
return new AudioMixerAddon(image);
}
// -------------------------------------------------------- //
// ctor/dtor
// -------------------------------------------------------- //
AudioMixerAddon::~AudioMixerAddon() {}
AudioMixerAddon::AudioMixerAddon(image_id image) :
BMediaAddOn(image) {}
// -------------------------------------------------------- //
// BMediaAddOn impl
// -------------------------------------------------------- //
status_t AudioMixerAddon::InitCheck(
const char** out_failure_text) {
return B_OK;
}
int32 AudioMixerAddon::CountFlavors() {
return 1;
}
status_t AudioMixerAddon::GetFlavorAt(
int32 n,
const flavor_info** out_info) {
if(n)
return B_ERROR;
flavor_info* pInfo = new flavor_info;
pInfo->internal_id = n;
pInfo->name = "AudioMixer";
pInfo->info =
"AudioMixer media addon\n";
"By David Shipman, 2002";
pInfo->kinds = B_BUFFER_PRODUCER | B_BUFFER_CONSUMER | B_SYSTEM_MIXER | B_CONTROLLABLE;
pInfo->flavor_flags = 0;
pInfo->possible_count = 0;
media_format* pFormat = new media_format;
pFormat->type = B_MEDIA_RAW_AUDIO;
pFormat->u.raw_audio = media_raw_audio_format::wildcard;
pInfo->in_format_count = 1;
pInfo->in_formats = pFormat;
pInfo->out_format_count = 1;
pInfo->out_formats = pFormat;
*out_info = pInfo;
return B_OK;
}
BMediaNode* AudioMixerAddon::InstantiateNodeFor(
const flavor_info* info,
BMessage* config,
status_t* out_error) {
return new AudioMixer(this);
}
status_t AudioMixerAddon::GetConfigurationFor(
BMediaNode* your_node,
BMessage* into_message) {
// no config yet
return B_OK;
}
// end
@@ -0,0 +1,45 @@
// MixerAddon.h
// David Shipman, 2002
//
// Quick addon header for the Audio Mixer
//
#ifndef __AudioMixerAddOn_H_
#define __AudioMixerAddOn_H_
#include <MediaAddOn.h>
// -------------------------------------------------------- //
class AudioMixerAddon :
public BMediaAddOn {
typedef BMediaAddOn _inherited;
public: // ctor/dtor
virtual ~AudioMixerAddon();
explicit AudioMixerAddon(image_id image);
public: // BMediaAddOn impl
virtual status_t InitCheck(
const char** out_failure_text);
virtual int32 CountFlavors();
virtual status_t GetFlavorAt(
int32 n,
const flavor_info ** out_info);
virtual BMediaNode * InstantiateNodeFor(
const flavor_info * info,
BMessage * config,
status_t * out_error);
virtual status_t GetConfigurationFor(
BMediaNode * your_node,
BMessage * into_message);
virtual bool WantsAutoStart() { return false; }
virtual status_t AutoStart(
int in_count,
BMediaNode ** out_node,
int32 * out_internal_id,
bool * out_has_more) { return B_OK; }
};
#endif /*__AudioMixerAddOn_H_*/
@@ -0,0 +1,31 @@
----------------------
Be Sample Code License
----------------------
Copyright 1991-1999, Be Incorporated.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions, and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,41 @@
OpenBeOS Audio Mixer
David Shipman, 2002
Overview
The node is based on a mediaeventlooper, using the HandleEvent loop to compile
the mixed buffer output.
Each input creates a ringbuffer (fixed size "looped" buffer) for its input - this way
buffer contents can be placed in the ringbuffer and recycled immediately.
Inputs are maintained using a list of input_channel structs - inputs are created/
destroyed dynamically when producers connect/disconnect.
Done
- node functions as a replacement for the BeOS R5 mixer.media-addon
- IO/conversion between stereo B_AUDIO_FLOAT and B_AUDIO_SHORT streams
Tested
- Output to emu10k1 (SBLive)
- Input from CL-Amp and emu10k1-in
Bugs
- Soundplay, extractor nodes, and a variety of others connect, but sound really bad!
- When input stops, the current ringbuffer contents continue to be played
To Do (lots) (vaguely in order of importance)
- fix bugs
- support for remaining formats
- samplerate conversion
- Interface (BControllable)
- multithreading (separate mix thread)
- tidy up code
Notes :
Parts of this program are based on code under the Be Sample Code License.
This is included in the archive, in accordance with the license.