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:
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.
|
||||
Reference in New Issue
Block a user