* Cleanup, no functional change.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34437 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2009-12-02 09:21:28 +00:00
parent 1fd264a18e
commit a9cf57cff5
18 changed files with 970 additions and 696 deletions

View File

@ -6,23 +6,27 @@
* Distributed under the terms of the MIT License.
*/
#include "AudioMixer.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Buffer.h>
#include <FindDirectory.h>
#include <MediaRoster.h>
#include <ParameterWeb.h>
#include <Path.h>
#include <RealtimeAlloc.h>
#include <TimeSource.h>
#include "MixerCore.h"
#include "MixerInput.h"
#include "MixerOutput.h"
#include "MixerUtils.h"
#include <Buffer.h>
#include <FindDirectory.h>
#include <math.h>
#include <MediaRoster.h>
#include <ParameterWeb.h>
#include <Path.h>
#include <RealtimeAlloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <TimeSource.h>
// the range of the gain sliders (in dB)
#define DB_MAX 18.0
@ -84,7 +88,8 @@ multi_audio_format_specialize(media_multi_audio_format *format,
AudioMixer::AudioMixer(BMediaAddOn *addOn, bool isSystemMixer)
: BMediaNode("Audio Mixer"),
:
BMediaNode("Audio Mixer"),
BBufferConsumer(B_MEDIA_RAW_AUDIO),
BBufferProducer(B_MEDIA_RAW_AUDIO),
BControllable(),

View File

@ -7,6 +7,7 @@
#ifndef _AUDIOMIXER_H
#define _AUDIOMIXER_H
#include <BufferConsumer.h>
#include <BufferGroup.h>
#include <BufferProducer.h>
@ -14,20 +15,18 @@
#include <MediaEventLooper.h>
#include <MediaNode.h>
class MixerCore;
class AudioMixer :
public BBufferConsumer,
public BBufferProducer,
public BControllable,
public BMediaEventLooper
{
public:
class AudioMixer : public BBufferConsumer, public BBufferProducer,
public BControllable, public BMediaEventLooper {
public:
AudioMixer(BMediaAddOn *addOn, bool isSystemMixer);
~AudioMixer();
void DisableNodeStop();
// AudioMixer support
void ApplySettings();
@ -48,9 +47,9 @@ class AudioMixer :
void SetTimeSource(BTimeSource * time_source);
using BBufferProducer::SendBuffer;
protected:
protected:
// BControllable methods
status_t GetParameterValue(int32 id,
status_t GetParameterValue(int32 id,
bigtime_t *last_change,
void *value,
size_t *ioSize);
@ -69,10 +68,10 @@ class AudioMixer :
void DisposeInputCookie(int32 cookie);
void BufferReceived(BBuffer *buffer);
void ProducerDataStatus(const media_destination &for_whom,
int32 status,
int32 status,
bigtime_t at_performance_time);
status_t GetLatencyFor(const media_destination &for_whom,
bigtime_t *out_latency,
bigtime_t *out_latency,
media_node_id *out_timesource);
status_t Connected(const media_source &producer,
const media_destination &where,
@ -128,7 +127,7 @@ class AudioMixer :
bigtime_t lateness,
bool realTimeEvent = false);
private:
private:
BMediaAddOn *fAddOn;
MixerCore *fCore;
BParameterWeb *fWeb; // local pointer to parameterweb
@ -138,4 +137,5 @@ class AudioMixer :
bool fDisableStop;
media_format fDefaultFormat;
};
#endif
#endif // _AUDIOMIXER_H

View File

@ -3,17 +3,22 @@
* Copyright 2007 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "ByteSwap.h"
#include "MixerDebug.h"
#include <ByteOrder.h>
#include <MediaDefs.h>
#include "MixerDebug.h"
static void swap_float(void *buffer, size_t bytecount);
static void swap_int32(void *buffer, size_t bytecount);
static void swap_int16(void *buffer, size_t bytecount);
static void do_nothing(void *buffer, size_t bytecount);
ByteSwap::ByteSwap(uint32 format)
{
switch (format) {
@ -32,18 +37,21 @@ ByteSwap::ByteSwap(uint32 format)
}
}
ByteSwap::~ByteSwap()
{
}
void
do_nothing(void *buffer, size_t bytecount)
{
}
#if __INTEL__
// optimized for IA32 platform
#if __INTEL__
// #pragma mark - optimized for IA32 platform
void
swap_float(void *buffer, size_t bytecount)
@ -52,6 +60,7 @@ swap_float(void *buffer, size_t bytecount)
swap_data(B_FLOAT_TYPE, buffer, bytecount, B_SWAP_ALWAYS);
}
void
swap_int32(void *buffer, size_t bytecount)
{
@ -59,6 +68,7 @@ swap_int32(void *buffer, size_t bytecount)
swap_data(B_INT32_TYPE, buffer, bytecount, B_SWAP_ALWAYS);
}
void
swap_int16(void *buffer, size_t bytecount)
{
@ -111,9 +121,10 @@ swap_int16(void *buffer, size_t bytecount)
: "cc", "memory");
}
#else
// non optimized default versions, do not remove
#else // !__INTEL__
// #pragma mark - generic versions
void
swap_float(void *buffer, size_t bytecount)
@ -121,15 +132,19 @@ swap_float(void *buffer, size_t bytecount)
swap_data(B_FLOAT_TYPE, buffer, bytecount, B_SWAP_ALWAYS);
}
void
swap_int32(void *buffer, size_t bytecount)
{
swap_data(B_INT32_TYPE, buffer, bytecount, B_SWAP_ALWAYS);
}
void
swap_int16(void *buffer, size_t bytecount)
{
swap_data(B_INT16_TYPE, buffer, bytecount, B_SWAP_ALWAYS);
}
#endif

View File

@ -6,23 +6,26 @@
#ifndef _BYTE_SWAP_H
#define _BYTE_SWAP_H
#include <SupportDefs.h>
class ByteSwap
{
public:
ByteSwap(uint32 format);
~ByteSwap();
void Swap(void *buffer, size_t bytecount);
private:
void (*fFunc)(void *, size_t);
class ByteSwap {
public:
ByteSwap(uint32 format);
~ByteSwap();
void Swap(void *buffer, size_t bytecount);
private:
void (*fFunc)(void *, size_t);
};
inline void
ByteSwap::Swap(void *buffer, size_t bytecount)
{
(*fFunc)(buffer, bytecount);
}
#endif
#endif // _BYTE_SWAP_H

View File

@ -4,21 +4,28 @@
* Copyright 2007 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "MixerAddOn.h"
#include <stdio.h>
#include <string.h>
#include <MediaRoster.h>
#include <MediaNode.h>
#include <cstring>
#include <cstdio>
#include "AudioMixer.h"
#include "MixerAddOn.h"
// instantiation function
extern "C" _EXPORT BMediaAddOn* make_media_addon(image_id image) {
return new AudioMixerAddon(image);
}
AudioMixerAddon::AudioMixerAddon(image_id image)
: BMediaAddOn(image),
:
BMediaAddOn(image),
fFormat(new media_format),
fInfo(new flavor_info)
{
@ -38,15 +45,16 @@ AudioMixerAddon::AudioMixerAddon(image_id image)
fInfo->out_formats = fFormat;
}
AudioMixerAddon::~AudioMixerAddon()
{
delete fFormat;
delete fInfo;
}
// -------------------------------------------------------- //
// BMediaAddOn impl
// -------------------------------------------------------- //
// #pragma mark - BMediaAddOn implementation
status_t
AudioMixerAddon::InitCheck(const char** out_failure_text)
@ -54,46 +62,53 @@ 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)
{
// only the 0th flavor exists
if (n != 0)
return B_ERROR;
*out_info = fInfo;
return B_OK;
}
BMediaNode *
AudioMixerAddon::InstantiateNodeFor(const flavor_info* info, BMessage* config,
status_t* out_error)
status_t* out_error)
{
return new AudioMixer(this, false);
}
status_t
AudioMixerAddon::GetConfigurationFor(BMediaNode* your_node, BMessage* into_message)
AudioMixerAddon::GetConfigurationFor(BMediaNode* your_node,
BMessage* into_message)
{
// no config yet
return B_ERROR;
}
bool
AudioMixerAddon::WantsAutoStart()
{
return true;
}
status_t
AudioMixerAddon::AutoStart(int in_index, BMediaNode **out_node,
int32 *out_internal_id, bool *out_has_more)
int32 *out_internal_id, bool *out_has_more)
{
*out_has_more = false;
@ -103,6 +118,6 @@ AudioMixerAddon::AutoStart(int in_index, BMediaNode **out_node,
*out_internal_id = 0;
AudioMixer *mixer = new AudioMixer(this, true);
*out_node = mixer;
return B_OK;
}

View File

@ -7,33 +7,31 @@
#ifndef _AUDIOMIXER_ADDON_H
#define _AUDIOMIXER_ADDON_H
#include <MediaAddOn.h>
class AudioMixerAddon : public BMediaAddOn {
public:
virtual ~AudioMixerAddon();
explicit AudioMixerAddon(image_id image);
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);
public:
virtual ~AudioMixerAddon();
explicit AudioMixerAddon(image_id image);
virtual bool WantsAutoStart();
virtual status_t AutoStart(int in_index,
BMediaNode **out_node,
int32 *out_internal_id,
bool *out_has_more);
virtual status_t InitCheck(const char** _failureText);
virtual int32 CountFlavors();
virtual status_t GetFlavorAt(int32 n,
const flavor_info** _info);
virtual BMediaNode * InstantiateNodeFor(const flavor_info* info,
BMessage* config, status_t* _error);
virtual status_t GetConfigurationFor(BMediaNode* node,
BMessage* toMmessage);
private:
media_format *fFormat;
flavor_info *fInfo;
virtual bool WantsAutoStart();
virtual status_t AutoStart(int index, BMediaNode** _node,
int32* _internalID, bool* _hasMore);
private:
media_format* fFormat;
flavor_info* fInfo;
};
#endif
#endif // _AUDIOMIXER_ADDON_H

View File

@ -1,17 +1,15 @@
/*
* Copyright 2007 Haiku Inc. All rights reserved.
* Copyright 2003-2009 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Marcus Overhagen
* Marcus Overhagen
*/
#include "AudioMixer.h"
#include "MixerCore.h"
#include "MixerInput.h"
#include "MixerOutput.h"
#include "MixerUtils.h"
#include "Resampler.h"
#include "RtList.h"
#include <string.h>
#include <Buffer.h>
#include <BufferGroup.h>
@ -20,31 +18,49 @@
#include <RealtimeAlloc.h>
#include <StopWatch.h>
#include <TimeSource.h>
#include <string.h>
#include "AudioMixer.h"
#include "MixerInput.h"
#include "MixerOutput.h"
#include "MixerUtils.h"
#include "Resampler.h"
#include "RtList.h"
#define DOUBLE_RATE_MIXING 0
#if DEBUG > 1
#define ASSERT_LOCKED() if (fLocker->IsLocked()) {} else debugger("core not locked, meltdown occurred")
# define ASSERT_LOCKED() if (fLocker->IsLocked()) {} \
else debugger("core not locked, meltdown occurred")
#else
#define ASSERT_LOCKED() ((void)0)
# define ASSERT_LOCKED() ((void)0)
#endif
/* Mixer channels are identified by a type number, each type number corresponds
* to the one of the channel masks of enum media_multi_channels.
*
* The mixer buffer uses either the same frame rate and same count of frames as the
* output buffer, or the double frame rate and frame count.
*
* All mixer input ring buffers must be an exact multiple of the mixer buffer size,
* so that we do not get any buffer wrap around during reading from the input buffers.
* The mixer input is told by constructor (or after a format change by SetMixBufferFormat())
* of the current mixer buffer propertys, and must allocate a buffer that is an exact multiple,
*/
/*! Mixer channels are identified by a type number, each type number corresponds
to the one of the channel masks of enum media_multi_channels.
The mixer buffer uses either the same frame rate and same count of frames as
the output buffer, or the double frame rate and frame count.
All mixer input ring buffers must be an exact multiple of the mixer buffer
size, so that we do not get any buffer wrap around during reading from the
input buffers.
The mixer input is told by constructor (or after a format change by
SetMixBufferFormat() of the current mixer buffer propertys, and must
allocate a buffer that is an exact multiple,
*/
struct chan_info {
const char *base;
uint32 sample_offset;
float gain;
};
MixerCore::MixerCore(AudioMixer *node)
: fLocker(new BLocker("mixer core lock")),
:
fLocker(new BLocker("mixer core lock")),
fInputs(new BList),
fOutput(0),
fNextInputID(1),
@ -69,6 +85,7 @@ MixerCore::MixerCore(AudioMixer *node)
{
}
MixerCore::~MixerCore()
{
delete fSettings;
@ -90,16 +107,18 @@ MixerCore::~MixerCore()
delete fResampler[i];
delete [] fResampler;
}
delete fMixBufferChannelTypes;
}
MixerSettings *
MixerCore::Settings()
{
return fSettings;
}
void
MixerCore::SetOutputAttenuation(float gain)
{
@ -107,16 +126,18 @@ MixerCore::SetOutputAttenuation(float gain)
fOutputGain = gain;
}
MixerInput *
MixerCore::AddInput(const media_input &input)
{
ASSERT_LOCKED();
MixerInput *in = new MixerInput(this, input, fMixBufferFrameRate,
fMixBufferFrameCount);
fMixBufferFrameCount);
fInputs->AddItem(in);
return in;
}
MixerOutput *
MixerCore::AddOutput(const media_output &output)
{
@ -132,10 +153,11 @@ MixerCore::AddOutput(const media_output &output)
ASSERT(!fRunning);
if (fStarted && fOutputEnabled)
StartMixThread();
return fOutput;
}
bool
MixerCore::RemoveInput(int32 inputID)
{
@ -151,6 +173,7 @@ MixerCore::RemoveInput(int32 inputID)
return false;
}
bool
MixerCore::RemoveOutput()
{
@ -167,6 +190,7 @@ MixerCore::RemoveOutput()
return true;
}
int32
MixerCore::CreateInputID()
{
@ -174,6 +198,7 @@ MixerCore::CreateInputID()
return fNextInputID++;
}
MixerInput *
MixerCore::Input(int i)
{
@ -181,6 +206,7 @@ MixerCore::Input(int i)
return (MixerInput *)fInputs->ItemAt(i);
}
MixerOutput *
MixerCore::Output()
{
@ -188,6 +214,7 @@ MixerCore::Output()
return fOutput;
}
void
MixerCore::BufferReceived(BBuffer *buffer, bigtime_t lateness)
{
@ -200,16 +227,20 @@ MixerCore::BufferReceived(BBuffer *buffer, bigtime_t lateness)
return;
}
}
ERROR("MixerCore::BufferReceived: received buffer for unknown id %ld\n", id);
ERROR("MixerCore::BufferReceived: received buffer for unknown id %ld\n",
id);
}
void
MixerCore::InputFormatChanged(int32 inputID, const media_multi_audio_format &format)
MixerCore::InputFormatChanged(int32 inputID,
const media_multi_audio_format &format)
{
ASSERT_LOCKED();
ERROR("MixerCore::InputFormatChanged not handled\n");
}
void
MixerCore::OutputFormatChanged(const media_multi_audio_format &format)
{
@ -226,16 +257,17 @@ MixerCore::OutputFormatChanged(const media_multi_audio_format &format)
Start();
}
void
MixerCore::ApplyOutputFormat()
{
ASSERT_LOCKED();
media_multi_audio_format format = fOutput->MediaOutput().format.u.raw_audio;
if (fMixBuffer)
if (fMixBuffer != NULL)
rtm_free(fMixBuffer);
delete fMixBufferChannelTypes;
fMixBufferFrameRate = (int32)(0.5 + format.frame_rate);
@ -247,9 +279,11 @@ MixerCore::ApplyOutputFormat()
fMixBufferChannelCount = format.channel_count;
ASSERT(fMixBufferChannelCount == fOutput->GetOutputChannelCount());
fMixBufferChannelTypes = new int32 [format.channel_count];
for (int i = 0; i < fMixBufferChannelCount; i++)
fMixBufferChannelTypes[i] = ChannelMaskToChannelType(GetChannelMask(i, format.channel_mask));
for (int i = 0; i < fMixBufferChannelCount; i++) {
fMixBufferChannelTypes[i]
= ChannelMaskToChannelType(GetChannelMask(i, format.channel_mask));
}
fMixBuffer = (float *)rtm_alloc(NULL, sizeof(float) * fMixBufferFrameCount * fMixBufferChannelCount);
ASSERT(fMixBuffer);
@ -261,10 +295,11 @@ MixerCore::ApplyOutputFormat()
}
fResampler = new Resampler * [fMixBufferChannelCount];
for (int i = 0; i < fMixBufferChannelCount; i++)
fResampler[i] = new Resampler(media_raw_audio_format::B_AUDIO_FLOAT,
format.format);
for (int i = 0; i < fMixBufferChannelCount; i++) {
fResampler[i] = new Resampler(media_raw_audio_format::B_AUDIO_FLOAT,
format.format);
}
TRACE("MixerCore::OutputFormatChanged:\n");
TRACE(" fMixBufferFrameRate %ld\n", fMixBufferFrameRate);
TRACE(" fMixBufferFrameCount %ld\n", fMixBufferFrameCount);
@ -277,6 +312,7 @@ MixerCore::ApplyOutputFormat()
input->SetMixBufferFormat(fMixBufferFrameRate, fMixBufferFrameCount);
}
void
MixerCore::SetOutputBufferGroup(BBufferGroup *group)
{
@ -284,21 +320,22 @@ MixerCore::SetOutputBufferGroup(BBufferGroup *group)
fBufferGroup = group;
}
void
MixerCore::SetTimingInfo(BTimeSource *ts, bigtime_t downstream_latency)
{
ASSERT_LOCKED();
if (fTimeSource)
fTimeSource->Release();
fTimeSource = dynamic_cast<BTimeSource *>(ts->Acquire());
fDownstreamLatency = downstream_latency;
TRACE("MixerCore::SetTimingInfo, now = %Ld, downstream latency %Ld\n",
fTimeSource->Now(),
fDownstreamLatency);
TRACE("MixerCore::SetTimingInfo, now = %Ld, downstream latency %Ld\n",
fTimeSource->Now(), fDownstreamLatency);
}
void
MixerCore::EnableOutput(bool enabled)
{
@ -328,11 +365,11 @@ MixerCore::Start()
TRACE("MixerCore::Start\n");
if (fStarted)
return false;
fStarted = true;
ASSERT(!fRunning);
// only start the mix thread if we have an output
if (fOutput && fOutputEnabled)
StartMixThread();
@ -340,6 +377,7 @@ MixerCore::Start()
return true;
}
bool
MixerCore::Stop()
{
@ -347,7 +385,7 @@ MixerCore::Stop()
TRACE("MixerCore::Stop\n");
if (!fStarted)
return false;
if (fRunning)
StopMixThread();
@ -355,6 +393,7 @@ MixerCore::Stop()
return true;
}
void
MixerCore::StartMixThread()
{
@ -363,26 +402,29 @@ MixerCore::StartMixThread()
ASSERT(fOutput);
fRunning = true;
fMixThreadWaitSem = create_sem(0, "mix thread wait");
fMixThread = spawn_thread(_mix_thread_, "Yeah baby, very shagadelic", 120, this);
fMixThread = spawn_thread(_mix_thread_, "Yeah baby, very shagadelic", 120,
this);
resume_thread(fMixThread);
}
void
MixerCore::StopMixThread()
{
ASSERT(fRunning == true);
ASSERT(fMixThread > 0);
ASSERT(fMixThreadWaitSem > 0);
status_t unused;
delete_sem(fMixThreadWaitSem);
wait_for_thread(fMixThread, &unused);
wait_for_thread(fMixThread, &unused);
fMixThread = -1;
fMixThreadWaitSem = -1;
fRunning = false;
}
int32
MixerCore::_mix_thread_(void *arg)
{
@ -390,23 +432,18 @@ MixerCore::_mix_thread_(void *arg)
return 0;
}
struct chan_info {
const char *base;
uint32 sample_offset;
float gain;
};
void
MixerCore::MixThread()
{
bigtime_t event_time;
bigtime_t time_base;
bigtime_t latency;
bigtime_t start;
bigtime_t buffer_request_timeout;
int64 frame_base;
int64 frame_pos;
bigtime_t event_time;
bigtime_t time_base;
bigtime_t latency;
bigtime_t start;
bigtime_t buffer_request_timeout;
int64 frame_base;
int64 frame_pos;
// The broken BeOS R5 multiaudio node starts with time 0,
// then publishes negative times for about 50ms, publishes 0
// again until it finally reaches time values > 0
@ -415,7 +452,8 @@ MixerCore::MixThread()
start = fTimeSource->Now();
Unlock();
while (start <= 0) {
TRACE("MixerCore: delaying MixThread start, timesource is at %Ld\n", start);
TRACE("MixerCore: delaying MixThread start, timesource is at %Ld\n",
start);
snooze(5000);
if (!LockFromMixThread())
return;
@ -425,55 +463,65 @@ MixerCore::MixThread()
if (!LockFromMixThread())
return;
latency = max(3600LL, bigtime_t(0.4 * buffer_duration(fOutput->MediaOutput().format.u.raw_audio)));
// XXX when the format changes while running, everything is wrong!
buffer_request_timeout = buffer_duration(fOutput->MediaOutput().format.u.raw_audio) / 2;
TRACE("MixerCore: starting MixThread at %Ld with latency %Ld and downstream latency %Ld, buffer_request_timeout %Ld\n", start, latency, fDownstreamLatency, buffer_request_timeout);
latency = max(3600LL, bigtime_t(0.4 * buffer_duration(
fOutput->MediaOutput().format.u.raw_audio)));
/* We must read from the input buffer at a position (pos) that is always a multiple of fMixBufferFrameCount.
*/
// TODO: when the format changes while running, everything is wrong!
buffer_request_timeout = buffer_duration(
fOutput->MediaOutput().format.u.raw_audio) / 2;
TRACE("MixerCore: starting MixThread at %Ld with latency %Ld and "
"downstream latency %Ld, buffer_request_timeout %Ld\n", start, latency,
fDownstreamLatency, buffer_request_timeout);
// We must read from the input buffer at a position (pos) that is always
// a multiple of fMixBufferFrameCount.
int64 temp = frames_for_duration(fMixBufferFrameRate, start);
frame_base = ((temp / fMixBufferFrameCount) + 1) * fMixBufferFrameCount;
time_base = duration_for_frames(fMixBufferFrameRate, frame_base);
Unlock();
TRACE("MixerCore: starting MixThread, start %Ld, time_base %Ld, frame_base %Ld\n", start, time_base, frame_base);
TRACE("MixerCore: starting MixThread, start %Ld, time_base %Ld, "
"frame_base %Ld\n", start, time_base, frame_base);
ASSERT(fMixBufferFrameCount > 0);
#if DEBUG
uint64 buffer_num = 0;
#endif
RtList<chan_info> InputChanInfos[MAX_CHANNEL_TYPES];
RtList<chan_info> MixChanInfos[fMixBufferChannelCount]; // XXX this does not support changing output channel count
RtList<chan_info> MixChanInfos[fMixBufferChannelCount];
// TODO: this does not support changing output channel count
event_time = time_base;
frame_pos = 0;
for (;;) {
bigtime_t wait_until;
if (!LockFromMixThread())
return;
wait_until = fTimeSource->RealTimeFor(event_time, 0) - latency - fDownstreamLatency;
wait_until = fTimeSource->RealTimeFor(event_time, 0)
- latency - fDownstreamLatency;
Unlock();
status_t rv;
rv = acquire_sem_etc(fMixThreadWaitSem, 1, B_ABSOLUTE_TIMEOUT, wait_until);
rv = acquire_sem_etc(fMixThreadWaitSem, 1, B_ABSOLUTE_TIMEOUT,
wait_until);
if (rv == B_INTERRUPTED)
continue;
if (rv != B_TIMED_OUT && rv < B_OK)
return;
if (!LockWithTimeout(10000)) {
ERROR("MixerCore: LockWithTimeout failed\n");
continue;
}
// no inputs or output muted, skip further processing and just send an empty buffer
// no inputs or output muted, skip further processing and just send an
// empty buffer
if (fInputs->IsEmpty() || fOutput->IsMuted()) {
int size = fOutput->MediaOutput().format.u.raw_audio.buffer_size;
BBuffer* buf = fBufferGroup->RequestBuffer(size, buffer_request_timeout);
BBuffer* buf = fBufferGroup->RequestBuffer(size,
buffer_request_timeout);
if (buf) {
memset(buf->Data(), 0, size);
// fill in the buffer header
@ -482,9 +530,11 @@ MixerCore::MixThread()
hdr->size_used = size;
hdr->time_source = fTimeSource->ID();
hdr->start_time = event_time;
if (B_OK != fNode->SendBuffer(buf, fOutput->MediaOutput().destination)) {
if (fNode->SendBuffer(buf, fOutput->MediaOutput().destination)
!= B_OK) {
#if DEBUG
ERROR("MixerCore: SendBuffer failed for buffer %Ld\n", buffer_num);
ERROR("MixerCore: SendBuffer failed for buffer %Ld\n",
buffer_num);
#else
ERROR("MixerCore: SendBuffer failed\n");
#endif
@ -492,7 +542,8 @@ MixerCore::MixThread()
}
} else {
#if DEBUG
ERROR("MixerCore: RequestBuffer failed for buffer %Ld\n", buffer_num);
ERROR("MixerCore: RequestBuffer failed for buffer %Ld\n",
buffer_num);
#else
ERROR("MixerCore: RequestBuffer failed\n");
#endif
@ -502,12 +553,13 @@ MixerCore::MixThread()
int64 cur_framepos;
cur_framepos = frame_base + frame_pos;
// mix all data from all inputs into the mix buffer
ASSERT(cur_framepos % fMixBufferFrameCount == 0);
PRINT(4, "create new buffer event at %Ld, reading input frames at %Ld\n", event_time, cur_framepos);
PRINT(4, "create new buffer event at %Ld, reading input frames at "
"%Ld\n", event_time, cur_framepos);
MixerInput *input;
for (int i = 0; (input = Input(i)) != 0; i++) {
int count = input->GetMixerChannelCount();
@ -516,7 +568,8 @@ MixerCore::MixThread()
const float *base;
uint32 sample_offset;
float gain;
if (!input->GetMixerChannelInfo(chan, cur_framepos, event_time, &base, &sample_offset, &type, &gain))
if (!input->GetMixerChannelInfo(chan, cur_framepos, event_time,
&base, &sample_offset, &type, &gain))
continue;
if (type < 0 || type >= MAX_CHANNEL_TYPES)
continue;
@ -526,7 +579,7 @@ MixerCore::MixThread()
info->gain = gain;
}
}
for (int chan = 0; chan < fMixBufferChannelCount; chan++) {
int sourcecount = fOutput->GetOutputChannelSourceCount(chan);
for (int i = 0; i < sourcecount; i++) {
@ -546,16 +599,22 @@ MixerCore::MixThread()
}
}
memset(fMixBuffer, 0, fMixBufferChannelCount * fMixBufferFrameCount * sizeof(float));
memset(fMixBuffer, 0,
fMixBufferChannelCount * fMixBufferFrameCount * sizeof(float));
for (int chan = 0; chan < fMixBufferChannelCount; chan++) {
PRINT(5, "MixThread: chan %d has %d sources\n", chan, MixChanInfos[chan].CountItems());
PRINT(5, "MixThread: chan %d has %d sources\n", chan,
MixChanInfos[chan].CountItems());
int count = MixChanInfos[chan].CountItems();
for (int i = 0; i < count; i++) {
chan_info *info = MixChanInfos[chan].ItemAt(i);
PRINT(5, "MixThread: base %p, sample-offset %2d, gain %.3f\n", info->base, info->sample_offset, info->gain);
// This looks slightly ugly, but the current GCC will generate the fastest
// code this way. fMixBufferFrameCount is always > 0.
uint32 dst_sample_offset = fMixBufferChannelCount * sizeof(float);
PRINT(5, "MixThread: base %p, sample-offset %2d, gain %.3f\n",
info->base, info->sample_offset, info->gain);
// This looks slightly ugly, but the current GCC will generate
// the fastest code this way.
// fMixBufferFrameCount is always > 0.
uint32 dst_sample_offset
= fMixBufferChannelCount * sizeof(float);
uint32 src_sample_offset = info->sample_offset;
register char *dst = (char *)&fMixBuffer[chan];
register char *src = (char *)info->base;
@ -572,36 +631,45 @@ MixerCore::MixThread()
// request a buffer
BBuffer *buf;
buf = fBufferGroup->RequestBuffer(
fOutput->MediaOutput().format.u.raw_audio.buffer_size,
buffer_request_timeout);
fOutput->MediaOutput().format.u.raw_audio.buffer_size,
buffer_request_timeout);
if (buf) {
// copy data from mix buffer into output buffer
for (int i = 0; i < fMixBufferChannelCount; i++) {
fResampler[i]->Resample(reinterpret_cast<char *>(fMixBuffer) + i * sizeof(float),
fMixBufferChannelCount * sizeof(float),
fMixBufferFrameCount,
reinterpret_cast<char *>(buf->Data()) + (i * bytes_per_sample(fOutput->MediaOutput().format.u.raw_audio)),
bytes_per_frame(fOutput->MediaOutput().format.u.raw_audio),
frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio),
fOutputGain * fOutput->GetOutputChannelGain(i));
fResampler[i]->Resample(
reinterpret_cast<char *>(fMixBuffer) + i * sizeof(float),
fMixBufferChannelCount * sizeof(float),
fMixBufferFrameCount,
reinterpret_cast<char *>(buf->Data())
+ (i * bytes_per_sample(
fOutput->MediaOutput().format.u.raw_audio)),
bytes_per_frame(fOutput->MediaOutput().format.u.raw_audio),
frames_per_buffer(
fOutput->MediaOutput().format.u.raw_audio),
fOutputGain * fOutput->GetOutputChannelGain(i));
}
PRINT(4, "send buffer, inframes %ld, outframes %ld\n", fMixBufferFrameCount, frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio));
PRINT(4, "send buffer, inframes %ld, outframes %ld\n",
fMixBufferFrameCount,
frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio));
// fill in the buffer header
media_header* hdr = buf->Header();
hdr->type = B_MEDIA_RAW_AUDIO;
hdr->size_used = fOutput->MediaOutput().format.u.raw_audio.buffer_size;
hdr->size_used
= fOutput->MediaOutput().format.u.raw_audio.buffer_size;
hdr->time_source = fTimeSource->ID();
hdr->start_time = event_time;
// swap byte order if necessary
fOutput->AdjustByteOrder(buf);
// send the buffer
status_t res = fNode->SendBuffer(buf, fOutput->MediaOutput().destination);
if (B_OK != res) {
status_t res = fNode->SendBuffer(buf,
fOutput->MediaOutput().destination);
if (res != B_OK) {
#if DEBUG
ERROR("MixerCore: SendBuffer failed for buffer %Ld\n", buffer_num);
ERROR("MixerCore: SendBuffer failed for buffer %Ld\n",
buffer_num);
#else
ERROR("MixerCore: SendBuffer failed\n");
#endif
@ -609,7 +677,8 @@ MixerCore::MixThread()
}
} else {
#if DEBUG
ERROR("MixerCore: RequestBuffer failed for buffer %Ld\n", buffer_num);
ERROR("MixerCore: RequestBuffer failed for buffer %Ld\n",
buffer_num);
#else
ERROR("MixerCore: RequestBuffer failed\n");
#endif
@ -621,10 +690,11 @@ MixerCore::MixThread()
for (int i = 0; i < fOutput->GetOutputChannelCount(); i++)
MixChanInfos[i].MakeEmpty();
schedule_next_event:
schedule_next_event:
// schedule next event
frame_pos += fMixBufferFrameCount;
event_time = time_base + bigtime_t((1000000LL * frame_pos) / fMixBufferFrameRate);
event_time = time_base + bigtime_t((1000000LL * frame_pos)
/ fMixBufferFrameRate);
Unlock();
#if DEBUG
buffer_num++;

View File

@ -1,34 +1,40 @@
/*
* Copyright 2007-2009 Haiku Inc. All rights reserved.
* Copyright 2003-2009 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Marcus Overhagen
*/
#ifndef _MIXER_CORE_H
#define _MIXER_CORE_H
#include "MixerSettings.h"
#include <Buffer.h>
#include <Locker.h>
#include <TimeSource.h>
class AudioMixer;
class BBufferGroup;
class MixerInput;
class MixerOutput;
class Resampler;
// The number of "enum media_multi_channels" types from MediaDefs.h
// XXX should be 18, but limited to 12 here
#define MAX_CHANNEL_TYPES 12
// XXX using a dedicated mono channel, this should be channel type 31
// but for now we redefine type 12
// but for now we redefine type 12
#define B_CHANNEL_MONO B_CHANNEL_TOP_CENTER
class MixerCore {
public:
MixerCore(AudioMixer *node);
virtual ~MixerCore();
MixerSettings* Settings();
// To avoid calling Settings()->AttenuateOutput() for every outgoing
@ -41,11 +47,11 @@ public:
bool RemoveInput(int32 inputID);
bool RemoveOutput();
int32 CreateInputID();
// index = 0 to count-1, NOT inputID
MixerInput* Input(int index);
MixerOutput* Output();
void Lock();
bool LockWithTimeout(bigtime_t timeout);
bool LockFromMixThread();
@ -53,28 +59,28 @@ public:
void BufferReceived(BBuffer* buffer,
bigtime_t lateness);
void InputFormatChanged(int32 inputID,
void InputFormatChanged(int32 inputID,
const media_multi_audio_format& format);
void OutputFormatChanged(
const media_multi_audio_format& format);
void SetOutputBufferGroup(BBufferGroup* group);
void SetTimingInfo(BTimeSource* timeSource,
void SetTimingInfo(BTimeSource* timeSource,
bigtime_t downstream_latency);
void EnableOutput(bool enabled);
bool Start();
bool Stop();
void StartMixThread();
void StopMixThread();
void StopMixThread();
uint32 OutputChannelCount();
private:
void ApplyOutputFormat();
static int32 _mix_thread_(void* arg);
void MixThread();
private:
BLocker* fLocker;
BList* fInputs;
@ -84,7 +90,7 @@ private:
// true = the mix thread is running
bool fStarted;
// true = mix thread should be
// true = mix thread should be
// started of it is not running
bool fOutputEnabled;
@ -104,7 +110,7 @@ private:
BBufferGroup* fBufferGroup;
BTimeSource* fTimeSource;
thread_id fMixThread;
sem_id fMixThreadWaitSem;
sem_id fMixThreadWaitSem;
float fOutputGain;
friend class MixerInput;
@ -112,28 +118,28 @@ private:
};
inline void
inline void
MixerCore::Lock()
{
fLocker->Lock();
}
inline bool
inline bool
MixerCore::LockWithTimeout(bigtime_t timeout)
{
return fLocker->LockWithTimeout(timeout) == B_OK;
}
inline void
inline void
MixerCore::Unlock()
{
fLocker->Unlock();
}
inline bool
inline bool
MixerCore::LockFromMixThread()
{
for (;;) {

View File

@ -7,42 +7,41 @@
#ifndef _MIXER_DEBUG_H_
#define _MIXER_DEBUG_H_
#ifndef DEBUG
#define DEBUG 0
# define DEBUG 0
#endif
#include <Debug.h>
#include <stdio.h>
#undef TRACE
#undef PRINT
#if DEBUG > 0
#if DEBUG > 0
inline void ERROR(const char *fmt, ...) { va_list ap; va_start(ap, fmt); printf("### ERROR: "); vprintf(fmt, ap); va_end(ap); }
inline void PRINT(int level, const char *fmt, ...) { va_list ap; if (level > DEBUG) return; va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); }
#define PRINT_FORMAT(_text, _fmt) do { char _buf[300]; string_for_format((_fmt), _buf, sizeof(_buf)); printf("%s %s\n", (_text), (_buf)); } while (0)
#define PRINT_INPUT(_text, _in) do { char _buf[300]; string_for_format((_in).format, _buf, sizeof(_buf)); printf("%s node(node %ld, port %ld); source(port %ld, id %ld); dest(port %ld, id %ld); fmt(%s); name(%s)\n", (_text), (_in).node.node, (_in).node.port, (_in).source.port, (_in).source.id, (_in).destination.port, (_in).destination.id, _buf, (_in).name); } while (0)
#define PRINT_OUTPUT(_text, _out) do { char _buf[300]; string_for_format((_out).format, _buf, sizeof(_buf)); printf("%s node(node %ld, port %ld); source(port %ld, id %ld); dest(port %ld, id %ld); fmt(%s); name(%s)\n", (_text), (_out).node.node, (_out).node.port, (_out).source.port, (_out).source.id, (_out).destination.port, (_out).destination.id, _buf, (_out).name); } while (0)
#define PRINT_CHANNEL_MASK(fmt) do { char s[200]; StringForChannelMask(s, (fmt).u.raw_audio.channel_mask); printf(" channel_mask 0x%08lX %s\n", (fmt).u.raw_audio.channel_mask, s); } while (0)
#if DEBUG >= 2
#define TRACE printf
#else
#define TRACE(a...) ((void)0)
#endif
# define PRINT_FORMAT(_text, _fmt) do { char _buf[300]; string_for_format((_fmt), _buf, sizeof(_buf)); printf("%s %s\n", (_text), (_buf)); } while (0)
# define PRINT_INPUT(_text, _in) do { char _buf[300]; string_for_format((_in).format, _buf, sizeof(_buf)); printf("%s node(node %ld, port %ld); source(port %ld, id %ld); dest(port %ld, id %ld); fmt(%s); name(%s)\n", (_text), (_in).node.node, (_in).node.port, (_in).source.port, (_in).source.id, (_in).destination.port, (_in).destination.id, _buf, (_in).name); } while (0)
# define PRINT_OUTPUT(_text, _out) do { char _buf[300]; string_for_format((_out).format, _buf, sizeof(_buf)); printf("%s node(node %ld, port %ld); source(port %ld, id %ld); dest(port %ld, id %ld); fmt(%s); name(%s)\n", (_text), (_out).node.node, (_out).node.port, (_out).source.port, (_out).source.id, (_out).destination.port, (_out).destination.id, _buf, (_out).name); } while (0)
# define PRINT_CHANNEL_MASK(fmt) do { char s[200]; StringForChannelMask(s, (fmt).u.raw_audio.channel_mask); printf(" channel_mask 0x%08lX %s\n", (fmt).u.raw_audio.channel_mask, s); } while (0)
# if DEBUG >= 2
# define TRACE printf
# else
# define TRACE(a...) ((void)0)
# endif
#else
#define PRINT_FORMAT(_text, _fmt) ((void)0)
#define PRINT_INPUT(_text, _in) ((void)0)
#define PRINT_OUTPUT(_text, _out) ((void)0)
#define PRINT_CHANNEL_MASK(fmt) ((void)0)
#define PRINT(l, a...) ((void)0)
#define ERROR(a...) ((void)0)
#define TRACE(a...) ((void)0)
# define PRINT_FORMAT(_text, _fmt) ((void)0)
# define PRINT_INPUT(_text, _in) ((void)0)
# define PRINT_OUTPUT(_text, _out) ((void)0)
# define PRINT_CHANNEL_MASK(fmt) ((void)0)
# define PRINT(l, a...) ((void)0)
# define ERROR(a...) ((void)0)
# define TRACE(a...) ((void)0)
#endif
#endif /* _MIXER_DEBUG_H_ */

View File

@ -1,22 +1,28 @@
/*
* Copyright 2007 Haiku Inc. All rights reserved.
* Copyright 2003-2009 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Marcus Overhagen
* Marcus Overhagen
*/
#include "ByteSwap.h"
#include "MixerCore.h"
#include <Buffer.h>
#include <string.h>
#include <TimeSource.h> // TODO: debug only
#include "ByteSwap.h"
#include "MixerInput.h"
#include "MixerUtils.h"
#include "Resampler.h"
#include <Buffer.h>
#include <string.h>
#include <TimeSource.h> // XXX debug only
MixerInput::MixerInput(MixerCore *core, const media_input &input, float mixFrameRate, int32 mixFrameCount)
: fCore(core),
MixerInput::MixerInput(MixerCore *core, const media_input &input,
float mixFrameRate, int32 mixFrameCount)
:
fCore(core),
fInput(input),
fInputByteSwap(0),
fEnabled(true),
@ -38,7 +44,7 @@ MixerInput::MixerInput(MixerCore *core, const media_input &input, float mixFrame
fix_multiaudio_format(&fInput.format.u.raw_audio);
PRINT_INPUT("MixerInput::MixerInput", fInput);
PRINT_CHANNEL_MASK(fInput.format);
ASSERT(fInput.format.u.raw_audio.channel_count > 0);
for (int i = 0; i < MAX_CHANNEL_TYPES; i++)
@ -47,16 +53,19 @@ MixerInput::MixerInput(MixerCore *core, const media_input &input, float mixFrame
fInputChannelCount = fInput.format.u.raw_audio.channel_count;
fInputChannelMask = fInput.format.u.raw_audio.channel_mask;
fInputChannelInfo = new input_chan_info[fInputChannelCount];
// perhaps we need byte swapping
if (fInput.format.u.raw_audio.byte_order != B_MEDIA_HOST_ENDIAN) {
if ( fInput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_FLOAT
|| fInput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_INT
|| fInput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_SHORT) {
if (fInput.format.u.raw_audio.format
== media_raw_audio_format::B_AUDIO_FLOAT
|| fInput.format.u.raw_audio.format
== media_raw_audio_format::B_AUDIO_INT
|| fInput.format.u.raw_audio.format
== media_raw_audio_format::B_AUDIO_SHORT) {
fInputByteSwap = new ByteSwap(fInput.format.u.raw_audio.format);
}
}
// initialize fInputChannelInfo
for (int i = 0; i < fInputChannelCount; i++) {
fInputChannelInfo[i].buffer_base = 0; // will be set by SetMixBufferFormat()
@ -68,11 +77,12 @@ MixerInput::MixerInput(MixerCore *core, const media_input &input, float mixFrame
fResampler = new Resampler * [fInputChannelCount];
for (int i = 0; i < fInputChannelCount; i++)
fResampler[i] = new Resampler(fInput.format.u.raw_audio.format, media_raw_audio_format::B_AUDIO_FLOAT);
// fMixerChannelInfo and fMixerChannelCount will be initialized by UpdateInputChannelDestinations()
SetMixBufferFormat((int32)mixFrameRate, mixFrameCount);
}
MixerInput::~MixerInput()
{
if (fMixBuffer)
@ -87,7 +97,8 @@ MixerInput::~MixerInput()
delete fResampler[i];
delete [] fResampler;
}
void
MixerInput::BufferReceived(BBuffer *buffer)
{
@ -95,12 +106,12 @@ MixerInput::BufferReceived(BBuffer *buffer)
size_t size;
bigtime_t start;
bigtime_t buffer_duration;
if (!fMixBuffer) {
ERROR("MixerInput::BufferReceived: dropped incoming buffer as we don't have a mix buffer\n");
return;
}
data = buffer->Data();
size = buffer->SizeUsed();
start = buffer->Header()->start_time;
@ -109,15 +120,15 @@ MixerInput::BufferReceived(BBuffer *buffer)
ERROR("MixerInput::BufferReceived: buffer with negative start time of %Ld dropped\n", start);
return;
}
// swap the byte order of this buffer, if necessary
if (fInputByteSwap)
fInputByteSwap->Swap(data, size);
int offset = frames_for_duration(fMixBufferFrameRate, start) % fMixBufferFrameCount;
PRINT(4, "MixerInput::BufferReceived: buffer start %10Ld, offset %6d\n", start, offset);
int in_frames = size / bytes_per_frame(fInput.format.u.raw_audio);
double frames = double(in_frames * fMixBufferFrameRate) / fInput.format.u.raw_audio.frame_rate;
int out_frames = int(frames);
@ -197,7 +208,7 @@ MixerInput::BufferReceived(BBuffer *buffer)
fInputChannelCount * sizeof(float),
out_frames1,
fInputChannelInfo[i].gain);
fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_sample(fInput.format.u.raw_audio) + in_frames1 * bytes_per_frame(fInput.format.u.raw_audio),
bytes_per_frame(fInput.format.u.raw_audio),
in_frames2,
@ -205,7 +216,7 @@ MixerInput::BufferReceived(BBuffer *buffer)
fInputChannelCount * sizeof(float),
out_frames2,
fInputChannelInfo[i].gain);
}
} else {
//printf("at %10Ld, data arrived for %10Ld to %10Ld, storing at frames %ld to %ld\n", fCore->fTimeSource->Now(), start, start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio)), offset, offset + out_frames - 1);
@ -265,7 +276,7 @@ MixerInput::AddInputChannelDestination(int channel, int destination_type)
if (-1 != GetInputChannelForDestination(destination_type)) {
ERROR("MixerInput::AddInputChannelDestination: destination_type %d already assigned to channel %d\n", destination_type, GetInputChannelForDestination(destination_type));
return;
}
}
// add it to specified channel
fInputChannelInfo[channel].destination_mask |= mask;
@ -274,6 +285,7 @@ MixerInput::AddInputChannelDestination(int channel, int destination_type)
UpdateInputChannelDestinations();
}
void
MixerInput::RemoveInputChannelDestination(int channel, int destination_type)
{
@ -293,6 +305,7 @@ MixerInput::RemoveInputChannelDestination(int channel, int destination_type)
UpdateInputChannelDestinations();
}
bool
MixerInput::HasInputChannelDestination(int channel, int destination_type)
{
@ -303,6 +316,7 @@ MixerInput::HasInputChannelDestination(int channel, int destination_type)
return fInputChannelInfo[channel].destination_mask & ChannelTypeToChannelMask(destination_type);
}
int
MixerInput::GetInputChannelForDestination(int destination_type)
{
@ -316,6 +330,7 @@ MixerInput::GetInputChannelForDestination(int destination_type)
return -1;
}
int
MixerInput::GetInputChannelType(int channel)
{
@ -324,6 +339,7 @@ MixerInput::GetInputChannelType(int channel)
return GetChannelType(channel, fInputChannelMask);
}
void
MixerInput::SetInputChannelGain(int channel, float gain)
{
@ -331,10 +347,11 @@ MixerInput::SetInputChannelGain(int channel, float gain)
return;
if (gain < 0.0f)
gain = 0.0f;
fInputChannelInfo[channel].gain = gain;
}
float
MixerInput::GetInputChannelGain(int channel)
{
@ -343,6 +360,7 @@ MixerInput::GetInputChannelGain(int channel)
return fInputChannelInfo[channel].gain;
}
void
MixerInput::UpdateInputChannelDestinationMask()
{
@ -355,7 +373,7 @@ MixerInput::UpdateInputChannelDestinationMask()
// first apply a 1:1 mapping
for (int i = 0; i < fInputChannelCount; i++)
fInputChannelInfo[i].destination_mask = GetChannelMask(i, fInputChannelMask);
// specialize this, depending on the available physical output channels
if (fCore->OutputChannelCount() <= 2) {
// less or equal two channels
@ -386,23 +404,24 @@ MixerInput::UpdateInputChannelDestinationMask()
TRACE("UpdateInputChannelDestinationMask: leave\n");
}
void
MixerInput::UpdateInputChannelDestinations()
{
int channel_count;
uint32 all_bits;
uint32 mask;
TRACE("UpdateInputChannelDestinations: enter\n");
for (int i = 0; i < fInputChannelCount; i++)
TRACE("UpdateInputChannelDestinations: input channel %d, destination_mask 0x%08lX, base %p, gain %.3f\n", i, fInputChannelInfo[i].destination_mask, fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain);
all_bits = 0;
for (int i = 0; i < fInputChannelCount; i++)
all_bits |= fInputChannelInfo[i].destination_mask;
TRACE("UpdateInputChannelDestinations: all_bits = %08lx\n", all_bits);
channel_count = count_nonzero_bits(all_bits);
TRACE("UpdateInputChannelDestinations: %d input channels, %d mixer channels (%d old)\n", fInputChannelCount, channel_count, fMixerChannelCount);
if (channel_count != fMixerChannelCount) {
@ -410,7 +429,7 @@ MixerInput::UpdateInputChannelDestinations()
fMixerChannelInfo = new mixer_chan_info[channel_count];
fMixerChannelCount = channel_count;
}
// assign each mixer channel one type
// and the gain from the fChannelTypeGain[]
mask = 1;
@ -443,6 +462,7 @@ MixerInput::UpdateInputChannelDestinations()
TRACE("UpdateInputChannelDestinations: leave\n");
}
// Note: The following code is outcommented on purpose
// and is about to be modified at a later point
/*
@ -468,6 +488,7 @@ MixerInput::SetInputChannelDestinationGain(int channel, int destination_type, fl
}
}
float
MixerInput::GetInputChannelDestinationGain(int channel, int destination_type)
{
@ -482,6 +503,7 @@ MixerInput::GetInputChannelDestinationGain(int channel, int destination_type)
}
*/
void
MixerInput::SetMixerChannelGain(int mixer_channel, float gain)
{
@ -494,6 +516,7 @@ MixerInput::SetMixerChannelGain(int mixer_channel, float gain)
fChannelTypeGain[fMixerChannelInfo[mixer_channel].destination_type] = gain;
}
float
MixerInput::GetMixerChannelGain(int mixer_channel)
{
@ -502,6 +525,7 @@ MixerInput::GetMixerChannelGain(int mixer_channel)
return fMixerChannelInfo[mixer_channel].destination_gain;
}
int
MixerInput::GetMixerChannelType(int mixer_channel)
{
@ -510,31 +534,35 @@ MixerInput::GetMixerChannelType(int mixer_channel)
return fMixerChannelInfo[mixer_channel].destination_type;
}
void
MixerInput::SetEnabled(bool yesno)
{
fEnabled = yesno;
}
bool
MixerInput::IsEnabled()
{
return fEnabled;
}
void
MixerInput::SetMixBufferFormat(int32 framerate, int32 frames)
{
TRACE("MixerInput::SetMixBufferFormat: framerate %ld, frames %ld\n", framerate, frames);
TRACE("MixerInput::SetMixBufferFormat: framerate %ld, frames %ld\n",
framerate, frames);
fMixBufferFrameRate = framerate;
debugMixBufferFrames = frames;
fDebugMixBufferFrames = frames;
// frames and/or framerate can be 0 (if no output is connected)
if (framerate == 0 || frames == 0) {
if (fMixBuffer) {
if (fMixBuffer != NULL) {
rtm_free(fMixBuffer);
fMixBuffer = 0;
fMixBuffer = NULL;
}
for (int i = 0; i < fInputChannelCount; i++)
fInputChannelInfo[i].buffer_base = 0;
@ -553,28 +581,29 @@ MixerInput::SetMixBufferFormat(int32 framerate, int32 frames)
bigtime_t mixerBufferLength = max_c(3 * inputBufferLength, 2 * outputBufferLength);
int temp = frames_for_duration(framerate, mixerBufferLength);
fMixBufferFrameCount = ((temp / frames) + 1) * frames;
TRACE(" inputBufferLength %10Ld\n", inputBufferLength);
TRACE(" outputBufferLength %10Ld\n", outputBufferLength);
TRACE(" mixerBufferLength %10Ld\n", mixerBufferLength);
TRACE(" fMixBufferFrameCount %10d\n", fMixBufferFrameCount);
ASSERT((fMixBufferFrameCount % frames) == 0);
fLastDataFrameWritten = -1;
fFractionalFrames = 0.0;
if (fMixBuffer)
rtm_free(fMixBuffer);
if (fRtmPool)
rtm_delete_pool(fRtmPool);
rtm_free(fMixBuffer);
rtm_delete_pool(fRtmPool);
int size = sizeof(float) * fInputChannelCount * fMixBufferFrameCount;
if (B_OK != rtm_create_pool(&fRtmPool, size))
fRtmPool = 0;
if (rtm_create_pool(&fRtmPool, size) != B_OK)
fRtmPool = NULL;
fMixBuffer = (float *)rtm_alloc(fRtmPool, size);
ASSERT(fMixBuffer);
memset(fMixBuffer, 0, size);
if (fMixBuffer == NULL)
return;
memset(fMixBuffer, 0, size);
for (int i = 0; i < fInputChannelCount; i++)
fInputChannelInfo[i].buffer_base = &fMixBuffer[i];

View File

@ -1,149 +1,152 @@
/*
* Copyright 2007 Haiku Inc. All rights reserved.
* Copyright 2003-2009 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Marcus Overhagen
*/
#ifndef _MIXER_INPUT_H
#define _MIXER_INPUT_H
#include <MediaNode.h>
#include <RealtimeAlloc.h>
#include "MixerCore.h"
#include "MixerDebug.h"
#include "MixerUtils.h"
#include <MediaNode.h>
#include <RealtimeAlloc.h>
class ByteSwap;
class Resampler;
class MixerInput
{
public:
MixerInput(MixerCore *core,
const media_input &input,
float mixFrameRate,
int32 mixFrameCount);
~MixerInput();
int32 ID();
void BufferReceived(BBuffer *buffer);
media_input& MediaInput();
// The physical input channels
int GetInputChannelCount();
int GetInputChannelType(int channel);
void SetInputChannelGain(int channel,
float gain);
float GetInputChannelGain(int channel);
class MixerInput {
public:
MixerInput(MixerCore* core,
const media_input& input,
float mixFrameRate, int32 mixFrameCount);
~MixerInput();
// The destinations for each channel
void AddInputChannelDestination(
int channel,
int destination_type);
void RemoveInputChannelDestination(
int channel,
int destination_type);
bool HasInputChannelDestination(
int channel,
int destination_type);
int GetInputChannelForDestination(
int destination_type);
// returns -1 if not found
// The virtual mixer channels that are generated from destinations
int GetMixerChannelCount();
void SetMixerChannelGain(int mixer_channel,
float gain);
float GetMixerChannelGain(int mixer_channel);
int GetMixerChannelType(int mixer_channel);
void SetEnabled(bool yesno);
bool IsEnabled();
int32 ID();
void BufferReceived(BBuffer* buffer);
media_input& MediaInput();
// only for use by MixerCore
bool GetMixerChannelInfo(int mixer_channel,
int64 framepos,
bigtime_t time,
const float **buffer,
uint32 *sample_offset,
int *type,
float *gain);
// The physical input channels
int GetInputChannelCount();
int GetInputChannelType(int channel);
void SetInputChannelGain(int channel, float gain);
float GetInputChannelGain(int channel);
protected:
friend class MixerCore;
void SetMixBufferFormat(int32 framerate,
int32 frames);
private:
void UpdateInputChannelDestinationMask();
void UpdateInputChannelDestinations();
// The destinations for each channel
void AddInputChannelDestination(int channel,
int destinationType);
void RemoveInputChannelDestination(int channel,
int destinationType);
bool HasInputChannelDestination(int channel,
int destinationType);
int GetInputChannelForDestination(
int destinationType);
// returns -1 if not found
struct input_chan_info {
float *buffer_base;
uint32 destination_mask; // multiple or no bits sets
float gain;
};
struct mixer_chan_info {
float *buffer_base;
int destination_type;
float destination_gain;
};
private:
MixerCore *fCore;
media_input fInput;
ByteSwap *fInputByteSwap;
float fChannelTypeGain[MAX_CHANNEL_TYPES];
bool fEnabled;
input_chan_info *fInputChannelInfo; // array
int fInputChannelCount;
uint32 fInputChannelMask;
mixer_chan_info *fMixerChannelInfo; // array
int fMixerChannelCount;
float *fMixBuffer;
int32 fMixBufferFrameRate;
int fMixBufferFrameCount;
int32 fLastDataFrameWritten;
bigtime_t fLastDataAvailableTime;
double fFractionalFrames;
Resampler **fResampler; // array
rtm_pool *fRtmPool;
bool fUserOverridesChannelDestinations;
int32 debugMixBufferFrames;
// The virtual mixer channels that are generated from destinations
int GetMixerChannelCount();
void SetMixerChannelGain(int mixerChannel,
float gain);
float GetMixerChannelGain(int mixerChannel);
int GetMixerChannelType(int mixerChannel);
void SetEnabled(bool enabled);
bool IsEnabled();
// only for use by MixerCore
bool GetMixerChannelInfo(int mixerChannel,
int64 framepos, bigtime_t time,
const float** _buffer,
uint32* _sampleOffset, int* _type,
float* _gain);
protected:
friend class MixerCore;
void SetMixBufferFormat(int32 framerate,
int32 frames);
private:
void UpdateInputChannelDestinationMask();
void UpdateInputChannelDestinations();
struct input_chan_info {
float* buffer_base;
uint32 destination_mask; // multiple or no bits sets
float gain;
};
struct mixer_chan_info {
float* buffer_base;
int destination_type;
float destination_gain;
};
private:
MixerCore* fCore;
media_input fInput;
ByteSwap* fInputByteSwap;
float fChannelTypeGain[MAX_CHANNEL_TYPES];
bool fEnabled;
input_chan_info* fInputChannelInfo; // array
int fInputChannelCount;
uint32 fInputChannelMask;
mixer_chan_info* fMixerChannelInfo; // array
int fMixerChannelCount;
float* fMixBuffer;
int32 fMixBufferFrameRate;
int fMixBufferFrameCount;
int32 fLastDataFrameWritten;
bigtime_t fLastDataAvailableTime;
double fFractionalFrames;
Resampler** fResampler; // array
rtm_pool* fRtmPool;
bool fUserOverridesChannelDestinations;
int32 fDebugMixBufferFrames;
};
inline int
MixerInput::GetMixerChannelCount()
{
return fMixerChannelCount;
}
inline bool
MixerInput::GetMixerChannelInfo(int mixer_channel, int64 framepos,
bigtime_t time, const float **buffer,
uint32 *sample_offset, int *type, float *gain)
MixerInput::GetMixerChannelInfo(int mixer_channel, int64 framepos,
bigtime_t time, const float **buffer, uint32 *sample_offset, int *type,
float *gain)
{
// this function should not be called if we don't have a mix buffer!
ASSERT(fMixBuffer);
ASSERT(fMixBuffer);
ASSERT(mixer_channel >= 0 && mixer_channel < fMixerChannelCount);
if (!fEnabled)
return false;
#if 1
if (time < (fLastDataAvailableTime - duration_for_frames(fMixBufferFrameRate, fMixBufferFrameCount))
|| (time + duration_for_frames(fMixBufferFrameRate, debugMixBufferFrames)) >= fLastDataAvailableTime)
|| (time + duration_for_frames(fMixBufferFrameRate, fDebugMixBufferFrames)) >= fLastDataAvailableTime)
ERROR("MixerInput::GetMixerChannelInfo: reading wrong data, have %Ld to %Ld, reading from %Ld to %Ld\n",
fLastDataAvailableTime - duration_for_frames(fMixBufferFrameRate, fMixBufferFrameCount), fLastDataAvailableTime, time, time + duration_for_frames(fMixBufferFrameRate, debugMixBufferFrames));
fLastDataAvailableTime - duration_for_frames(fMixBufferFrameRate, fMixBufferFrameCount), fLastDataAvailableTime, time, time + duration_for_frames(fMixBufferFrameRate, fDebugMixBufferFrames));
#endif
if (time > fLastDataAvailableTime)
return false;
int32 offset = framepos % fMixBufferFrameCount;
if (mixer_channel == 0) PRINT(3, "GetMixerChannelInfo: frames %ld to %ld\n", offset, offset + debugMixBufferFrames - 1);
if (mixer_channel == 0) PRINT(3, "GetMixerChannelInfo: frames %ld to %ld\n", offset, offset + fDebugMixBufferFrames - 1);
*buffer = reinterpret_cast<float *>(reinterpret_cast<char *>(fMixerChannelInfo[mixer_channel].buffer_base) + (offset * sizeof(float) * fInputChannelCount));
*sample_offset = sizeof(float) * fInputChannelCount;
*type = fMixerChannelInfo[mixer_channel].destination_type;
*gain = fMixerChannelInfo[mixer_channel].destination_gain;
return true;
}
#endif
#endif // _MIXER_INPUT_H

View File

@ -1,19 +1,24 @@
/*
* Copyright 2007 Haiku Inc. All rights reserved.
* Copyright 2003-2009 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* probably Marcus Overhagen
* Marcus Overhagen
*/
#include "MixerCore.h"
#include "MixerDebug.h"
#include "MixerOutput.h"
#include "MixerUtils.h"
#include <MediaNode.h>
#include "MixerCore.h"
#include "MixerDebug.h"
#include "MixerUtils.h"
MixerOutput::MixerOutput(MixerCore *core, const media_output &output)
: fCore(core),
:
fCore(core),
fOutput(output),
fOutputChannelCount(0),
fOutputChannelInfo(0),
@ -28,24 +33,27 @@ MixerOutput::MixerOutput(MixerCore *core, const media_output &output)
UpdateByteOrderSwap();
}
MixerOutput::~MixerOutput()
{
delete fOutputChannelInfo;
delete fOutputByteSwap;
}
media_output &
MixerOutput::MediaOutput()
{
return fOutput;
}
void
MixerOutput::ChangeFormat(const media_multi_audio_format &format)
{
fOutput.format.u.raw_audio = format;
fix_multiaudio_format(&fOutput.format.u.raw_audio);
PRINT_OUTPUT("MixerOutput::ChangeFormat", fOutput);
PRINT_CHANNEL_MASK(fOutput.format);
@ -53,6 +61,7 @@ MixerOutput::ChangeFormat(const media_multi_audio_format &format)
UpdateByteOrderSwap();
}
void
MixerOutput::UpdateByteOrderSwap()
{
@ -69,6 +78,7 @@ MixerOutput::UpdateByteOrderSwap()
}
}
void
MixerOutput::UpdateOutputChannels()
{
@ -115,12 +125,13 @@ MixerOutput::UpdateOutputChannels()
TRACE("UpdateOutputChannels: output channel %d, type %2d, gain %.3f\n", i, fOutputChannelInfo[i].channel_type, fOutputChannelInfo[i].channel_gain);
}
void
MixerOutput::AssignDefaultSources()
{
uint32 mask = fOutput.format.u.raw_audio.channel_mask;
int count = fOutputChannelCount;
// assign default sources for a few known setups,
// everything else is left unchanged (it already is 1:1)
if (count == 1 && mask & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT)) {
@ -296,6 +307,7 @@ MixerOutput::AssignDefaultSources()
}
}
int
MixerOutput::GetOutputChannelType(int channel)
{
@ -304,6 +316,7 @@ MixerOutput::GetOutputChannelType(int channel)
return fOutputChannelInfo[channel].channel_type;
}
void
MixerOutput::SetOutputChannelGain(int channel, float gain)
{
@ -313,6 +326,7 @@ MixerOutput::SetOutputChannelGain(int channel, float gain)
fOutputChannelInfo[channel].channel_gain = gain;
}
void
MixerOutput::AddOutputChannelSource(int channel, int source_type)
{
@ -333,6 +347,7 @@ MixerOutput::AddOutputChannelSource(int channel, int source_type)
fOutputChannelInfo[channel].source_count++;
}
void
MixerOutput::RemoveOutputChannelSource(int channel, int source_type)
{
@ -351,6 +366,7 @@ MixerOutput::RemoveOutputChannelSource(int channel, int source_type)
}
}
void
MixerOutput::SetOutputChannelSourceGain(int channel, int source_type, float source_gain)
{
@ -369,6 +385,7 @@ MixerOutput::SetOutputChannelSourceGain(int channel, int source_type, float sour
fOutputChannelInfo[channel].source_gain_cache[source_type] = source_gain;
}
float
MixerOutput::GetOutputChannelSourceGain(int channel, int source_type)
{
@ -386,6 +403,7 @@ MixerOutput::GetOutputChannelSourceGain(int channel, int source_type)
return fOutputChannelInfo[channel].source_gain_cache[source_type];
}
bool
MixerOutput::HasOutputChannelSource(int channel, int source_type)
{
@ -399,6 +417,7 @@ MixerOutput::HasOutputChannelSource(int channel, int source_type)
return false;
}
void
MixerOutput::SetMuted(bool yesno)
{

View File

@ -1,30 +1,37 @@
/*
* Copyright 2007 Haiku Inc. All rights reserved.
* Copyright 2003-2009 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* probably Marcus Overhagen
* Marcus Overhagen
*/
#include "MixerCore.h"
#include "MixerDebug.h"
#include "MixerInput.h"
#include "MixerOutput.h"
#include "MixerSettings.h"
#include <string.h>
#include <File.h>
#include <Locker.h>
#include <MediaDefs.h>
#include <OS.h>
#include <Path.h>
#include <string.h>
#include "MixerCore.h"
#include "MixerDebug.h"
#include "MixerInput.h"
#include "MixerOutput.h"
#define SAVE_DELAY 5000000 // delay saving of settings for 5s
#define SAVE_RUNTIME 30000000 // stop save thread after 30s inactivity
#define SETTINGS_VERSION ((int32)0x94251601)
MixerSettings::MixerSettings()
: fLocker(new BLocker("mixer settings lock")),
:
fLocker(new BLocker("mixer settings lock")),
fSettingsFile(0),
fSettingsDirty(false),
fSettingsLastChange(0),
@ -35,6 +42,7 @@ MixerSettings::MixerSettings()
Load();
}
MixerSettings::~MixerSettings()
{
StopDeferredSave();
@ -44,6 +52,7 @@ MixerSettings::~MixerSettings()
delete fSettingsFile;
}
void
MixerSettings::SetSettingsFile(const char *file)
{
@ -54,6 +63,7 @@ MixerSettings::SetSettingsFile(const char *file)
Load();
}
bool
MixerSettings::AttenuateOutput()
{
@ -64,6 +74,7 @@ MixerSettings::AttenuateOutput()
return temp;
}
void
MixerSettings::SetAttenuateOutput(bool yesno)
{
@ -73,6 +84,7 @@ MixerSettings::SetAttenuateOutput(bool yesno)
StartDeferredSave();
}
bool
MixerSettings::NonLinearGainSlider()
{
@ -83,6 +95,7 @@ MixerSettings::NonLinearGainSlider()
return temp;
}
void
MixerSettings::SetNonLinearGainSlider(bool yesno)
{
@ -92,6 +105,7 @@ MixerSettings::SetNonLinearGainSlider(bool yesno)
StartDeferredSave();
}
bool
MixerSettings::UseBalanceControl()
{
@ -102,6 +116,7 @@ MixerSettings::UseBalanceControl()
return temp;
}
void
MixerSettings::SetUseBalanceControl(bool yesno)
{
@ -111,6 +126,7 @@ MixerSettings::SetUseBalanceControl(bool yesno)
StartDeferredSave();
}
bool
MixerSettings::AllowOutputChannelRemapping()
{
@ -121,6 +137,7 @@ MixerSettings::AllowOutputChannelRemapping()
return temp;
}
void
MixerSettings::SetAllowOutputChannelRemapping(bool yesno)
{
@ -130,6 +147,7 @@ MixerSettings::SetAllowOutputChannelRemapping(bool yesno)
StartDeferredSave();
}
bool
MixerSettings::AllowInputChannelRemapping()
{
@ -140,6 +158,7 @@ MixerSettings::AllowInputChannelRemapping()
return temp;
}
void
MixerSettings::SetAllowInputChannelRemapping(bool yesno)
{
@ -149,6 +168,7 @@ MixerSettings::SetAllowInputChannelRemapping(bool yesno)
StartDeferredSave();
}
int
MixerSettings::InputGainControls()
{
@ -159,6 +179,7 @@ MixerSettings::InputGainControls()
return temp;
}
void
MixerSettings::SetInputGainControls(int value)
{
@ -168,6 +189,7 @@ MixerSettings::SetInputGainControls(int value)
StartDeferredSave();
}
int
MixerSettings::ResamplingAlgorithm()
{
@ -178,6 +200,7 @@ MixerSettings::ResamplingAlgorithm()
return temp;
}
void
MixerSettings::SetResamplingAlgorithm(int value)
{
@ -187,6 +210,7 @@ MixerSettings::SetResamplingAlgorithm(int value)
StartDeferredSave();
}
bool
MixerSettings::RefuseOutputFormatChange()
{
@ -197,6 +221,7 @@ MixerSettings::RefuseOutputFormatChange()
return temp;
}
void
MixerSettings::SetRefuseOutputFormatChange(bool yesno)
{
@ -206,6 +231,7 @@ MixerSettings::SetRefuseOutputFormatChange(bool yesno)
StartDeferredSave();
}
bool
MixerSettings::RefuseInputFormatChange()
{
@ -216,6 +242,7 @@ MixerSettings::RefuseInputFormatChange()
return temp;
}
void
MixerSettings::SetRefuseInputFormatChange(bool yesno)
{
@ -225,17 +252,18 @@ MixerSettings::SetRefuseInputFormatChange(bool yesno)
StartDeferredSave();
}
void
MixerSettings::SaveConnectionSettings(MixerInput *input)
{
fLocker->Lock();
int index = -1;
// try to find matching name first
for (int i = 0; i < MAX_INPUT_SETTINGS; i++) {
if (fInputSetting[i].IsEmpty())
continue;
if (0 == strcmp(fInputSetting[i].FindString("name"), input->MediaInput().name)) {
if (!strcmp(fInputSetting[i].FindString("name"), input->MediaInput().name)) {
index = i;
break;
}
@ -267,7 +295,7 @@ MixerSettings::SaveConnectionSettings(MixerInput *input)
int count = input->GetInputChannelCount();
fInputSetting[index].AddInt32("InputChannelCount", count);
fInputSetting[index].AddBool("InputIsEnabled", input->IsEnabled());
for (int i = 0; i < count; i++)
fInputSetting[index].AddFloat("InputChannelGain", input->GetInputChannelGain(i));
@ -277,6 +305,7 @@ MixerSettings::SaveConnectionSettings(MixerInput *input)
StartDeferredSave();
}
void
MixerSettings::LoadConnectionSettings(MixerInput *input)
{
@ -285,7 +314,7 @@ MixerSettings::LoadConnectionSettings(MixerInput *input)
for (index = 0; index < MAX_INPUT_SETTINGS; index++) {
if (fInputSetting[index].IsEmpty())
continue;
if (0 == strcmp(fInputSetting[index].FindString("name"), input->MediaInput().name))
if (!strcmp(fInputSetting[index].FindString("name"), input->MediaInput().name))
break;
}
if (index == MAX_INPUT_SETTINGS) {
@ -293,58 +322,61 @@ MixerSettings::LoadConnectionSettings(MixerInput *input)
fLocker->Unlock();
return;
}
TRACE("LoadConnectionSettings: found entry %d\n", index);
int count = input->GetInputChannelCount();
if (fInputSetting[index].FindInt32("InputChannelCount") == count) {
for (int i = 0; i < count; i++)
input->SetInputChannelGain(i, fInputSetting[index].FindFloat("InputChannelGain", i));
input->SetEnabled(fInputSetting[index].FindBool("InputIsEnabled"));
}
// XXX should load channel destinations and mixer channels
fInputSetting[index].ReplaceInt64("lru", system_time());
fLocker->Unlock();
StartDeferredSave();
}
void
MixerSettings::SaveConnectionSettings(MixerOutput *output)
{
fLocker->Lock();
fOutputSetting.MakeEmpty();
int count = output->GetOutputChannelCount();
fOutputSetting.AddInt32("OutputChannelCount", count);
for (int i = 0; i < count; i++)
fOutputSetting.AddFloat("OutputChannelGain", output->GetOutputChannelGain(i));
fOutputSetting.AddBool("OutputIsMuted", output->IsMuted());
// XXX should save channel sources and source gains
fLocker->Unlock();
StartDeferredSave();
}
void
MixerSettings::LoadConnectionSettings(MixerOutput *output)
{
fLocker->Lock();
int count = output->GetOutputChannelCount();
if (fOutputSetting.FindInt32("OutputChannelCount") == count) {
for (int i = 0; i < count; i++)
output->SetOutputChannelGain(i, fOutputSetting.FindFloat("OutputChannelGain", i));
output->SetMuted(fOutputSetting.FindBool("OutputIsMuted"));
}
// XXX should load channel sources and source gains
fLocker->Unlock();
}
void
MixerSettings::Save()
{
@ -355,30 +387,31 @@ MixerSettings::Save()
return;
}
TRACE("MixerSettings: SAVE!\n");
BMessage msg;
msg.AddInt32("version", SETTINGS_VERSION);
msg.AddData("settings", B_RAW_TYPE, (void *)&fSettings, sizeof(fSettings));
msg.AddMessage("output", &fOutputSetting);
for (int i = 0; i < MAX_INPUT_SETTINGS; i++)
msg.AddMessage("input", &fInputSetting[i]);
char *buffer;
size_t length;
size_t length;
length = msg.FlattenedSize();
buffer = new char [length];
msg.Flatten(buffer, length);
BFile file(fSettingsFile->Path(), B_READ_WRITE | B_CREATE_FILE);
file.Write(buffer, length);
delete [] buffer;
fSettingsDirty = false;
fLocker->Unlock();
}
void
MixerSettings::Load()
{
@ -393,13 +426,13 @@ MixerSettings::Load()
fSettings.ResamplingAlgorithm = 0;
fSettings.RefuseOutputFormatChange = true;
fSettings.RefuseInputFormatChange = true;
// if we don't have a settings file, don't continue
if (!fSettingsFile) {
fLocker->Unlock();
return;
}
BFile file(fSettingsFile->Path(), B_READ_WRITE);
off_t size = 0;
file.GetSize(&size);
@ -432,10 +465,10 @@ MixerSettings::Load()
TRACE("MixerSettings: settings have wrong version\n");
return;
}
const void *data;
ssize_t datasize = 0;
msg.FindData("settings", B_RAW_TYPE, &data, &datasize);
if (datasize != sizeof(fSettings)) {
fLocker->Unlock();
@ -443,19 +476,20 @@ MixerSettings::Load()
return;
}
memcpy((void *)&fSettings, data, sizeof(fSettings));
msg.FindMessage("output", &fOutputSetting);
for (int i = 0; i < MAX_INPUT_SETTINGS; i++)
msg.FindMessage("input", i, &fInputSetting[i]);
fLocker->Unlock();
}
void
MixerSettings::StartDeferredSave()
{
fLocker->Lock();
// if we don't have a settings file, don't save the settings
if (!fSettingsFile) {
fLocker->Unlock();
@ -464,14 +498,14 @@ MixerSettings::StartDeferredSave()
fSettingsDirty = true;
fSettingsLastChange = system_time();
if (fSaveThreadRunning) {
fLocker->Unlock();
return;
}
StopDeferredSave();
ASSERT(fSaveThreadWaitSem < 0);
fSaveThreadWaitSem = create_sem(0, "save thread wait");
if (fSaveThreadWaitSem < B_OK) {
@ -491,42 +525,44 @@ MixerSettings::StartDeferredSave()
return;
}
resume_thread(fSaveThread);
fSaveThreadRunning = true;
fLocker->Unlock();
}
void
MixerSettings::StopDeferredSave()
{
fLocker->Lock();
if (fSaveThread > 0) {
if (fSaveThread >= 0) {
ASSERT(fSaveThreadWaitSem > 0);
status_t unused;
delete_sem(fSaveThreadWaitSem);
wait_for_thread(fSaveThread, &unused);
fSaveThread = -1;
fSaveThreadWaitSem = -1;
}
fLocker->Unlock();
}
void
MixerSettings::SaveThread()
{
bigtime_t timeout;
status_t rv;
TRACE("MixerSettings: save thread started\n");
fLocker->Lock();
timeout = fSettingsLastChange + SAVE_DELAY;
fLocker->Unlock();
for (;;) {
rv = acquire_sem_etc(fSaveThreadWaitSem, 1, B_ABSOLUTE_TIMEOUT, timeout);
if (rv == B_INTERRUPTED)
@ -535,11 +571,11 @@ MixerSettings::SaveThread()
break;
if (B_OK != fLocker->LockWithTimeout(200000))
continue;
TRACE("MixerSettings: save thread running\n");
bigtime_t delta = system_time() - fSettingsLastChange;
if (fSettingsDirty && delta > SAVE_DELAY) {
Save();
}
@ -553,10 +589,11 @@ MixerSettings::SaveThread()
timeout = system_time() + SAVE_DELAY;
fLocker->Unlock();
}
TRACE("MixerSettings: save thread ended\n");
}
int32
MixerSettings::_save_thread_(void *arg)
{

View File

@ -1,3 +1,12 @@
/*
* Copyright 2003-2009 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Marcus Overhagen
*/
#include <MediaDefs.h>
#include <OS.h>
#include <stdio.h>
@ -119,7 +128,7 @@ fix_multiaudio_format(media_multi_audio_format *format)
format->matrix_mask = 0;
}
break;
default:
if (count_nonzero_bits(format->channel_mask) != (int)format->channel_count) {
format->channel_mask = 0xffffffff;

View File

@ -1,12 +1,21 @@
/*
* Copyright 2003-2009 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Marcus Overhagen
*/
#ifndef _MIXER_UTILS_H
#define _MIXER_UTILS_H
#ifndef __SGI_STL_INTERNAL_ALGOBASE_H
template<class t> const t & max(const t &t1, const t &t2) { return (t1 > t2) ? t1 : t2; }
template<class t> const t & min(const t &t1, const t &t2) { return (t1 < t2) ? t1 : t2; }
#endif
template<class t> const t abs(const t t1) { return (t1 < 0) ? - t1 : t1; }
void fix_multiaudio_format(media_multi_audio_format *format);
int count_nonzero_bits(uint32 value);
@ -42,4 +51,4 @@ const char *StringForFormat(char *buf, MixerInput *input);
const char *StringForChannelMask(char *buf, uint32 mask);
const char *StringForChannelType(char *buf, int type);
#endif //_MIXER_UTILS_H
#endif // _MIXER_UTILS_H

View File

@ -1,20 +1,27 @@
/* Copyright (C) 2003 Marcus Overhagen
* Released under terms of the MIT license.
*
* A simple resampling class for the audio mixer.
* You pick the conversion function on object creation,
* and then call the Resample() function, specifying data pointer,
* offset (in bytes) to the next sample, and count of samples for
* both source and destination.
*
/*
* Copyright 2003 Marcus Overhagen
* Distributed under the terms of the MIT License.
*/
#include <MediaDefs.h>
#include "Resampler.h"
#include <MediaDefs.h>
#include "MixerDebug.h"
/*! A simple resampling class for the audio mixer.
You pick the conversion function on object creation,
and then call the Resample() function, specifying data pointer,
offset (in bytes) to the next sample, and count of samples for
both source and destination.
*/
Resampler::Resampler(uint32 src_format, uint32 dst_format)
: fFunc(0)
:
fFunc(0)
{
if (dst_format == media_raw_audio_format::B_AUDIO_FLOAT) {
switch (src_format) {
@ -34,7 +41,8 @@ Resampler::Resampler(uint32 src_format, uint32 dst_format)
fFunc = &Resampler::uint8_to_float;
return;
default:
ERROR("Resampler::Resampler: unknown source format 0x%x\n", src_format);
ERROR("Resampler::Resampler: unknown source format 0x%x\n",
src_format);
return;
}
}
@ -60,275 +68,290 @@ Resampler::Resampler(uint32 src_format, uint32 dst_format)
}
}
ERROR("Resampler::Resampler: source or destination format must be B_AUDIO_FLOAT\n");
ERROR("Resampler::Resampler: source or destination format must be "
"B_AUDIO_FLOAT\n");
}
Resampler::~Resampler()
{
}
status_t
Resampler::InitCheck()
Resampler::InitCheck() const
{
return (fFunc != 0) ? B_OK : B_ERROR;
return fFunc != 0 ? B_OK : B_ERROR;
}
void
Resampler::float_to_float(const void *_src, int32 src_sample_offset, int32 src_sample_count,
void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain)
Resampler::float_to_float(const void *_src, int32 srcSampleOffset,
int32 srcSampleCount, void *_dest, int32 destSampleOffset,
int32 destSampleCount, float _gain)
{
register const char * src = (const char *) _src;
register char * dst = (char *) _dst;
register int32 count = dst_sample_count;
register const char * src = (const char *)_src;
register char * dest = (char *)_dest;
register int32 count = destSampleCount;
register float gain = _gain;
if (src_sample_count == dst_sample_count) {
if (srcSampleCount == destSampleCount) {
// optimized case for no resampling
while (count--) {
*(float *)dst = *(const float *)src * gain;
src += src_sample_offset;
dst += dst_sample_offset;
*(float *)dest = *(const float *)src * gain;
src += srcSampleOffset;
dest += destSampleOffset;
}
return;
}
register float delta = float(src_sample_count) / float(dst_sample_count);
register float delta = float(srcSampleCount) / float(destSampleCount);
register float current = 0.0f;
if (delta < 1.0) {
// upsample
while (count--) {
*(float *)dst = *(const float *)src * gain;
dst += dst_sample_offset;
*(float *)dest = *(const float *)src * gain;
dest += destSampleOffset;
current += delta;
if (current >= 1.0f) {
current -= 1.0f;
src += src_sample_offset;
src += srcSampleOffset;
}
}
} else {
// downsample
while (count--) {
*(float *)dst = *(const float *)src * gain;
dst += dst_sample_offset;
*(float *)dest = *(const float *)src * gain;
dest += destSampleOffset;
current += delta;
register int32 skipcount = (int32)current;
current -= skipcount;
src += skipcount * src_sample_offset;
src += skipcount * srcSampleOffset;
}
}
}
void
Resampler::int32_to_float(const void *_src, int32 src_sample_offset, int32 src_sample_count,
void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain)
Resampler::int32_to_float(const void *_src, int32 srcSampleOffset,
int32 srcSampleCount, void *_dest, int32 destSampleOffset,
int32 destSampleCount, float _gain)
{
register const char * src = (const char *) _src;
register char * dst = (char *) _dst;
register int32 count = dst_sample_count;
register const char * src = (const char *)_src;
register char * dest = (char *)_dest;
register int32 count = destSampleCount;
register float gain = _gain / 2147483647.0;
if (src_sample_count == dst_sample_count) {
if (srcSampleCount == destSampleCount) {
// optimized case for no resampling
while (count--) {
*(float *)dst = *(const int32 *)src * gain;
src += src_sample_offset;
dst += dst_sample_offset;
*(float *)dest = *(const int32 *)src * gain;
src += srcSampleOffset;
dest += destSampleOffset;
}
return;
}
register float delta = float(src_sample_count) / float(dst_sample_count);
register float delta = float(srcSampleCount) / float(destSampleCount);
register float current = 0.0f;
if (delta < 1.0) {
// upsample
while (count--) {
*(float *)dst = *(const int32 *)src * gain;
dst += dst_sample_offset;
*(float *)dest = *(const int32 *)src * gain;
dest += destSampleOffset;
current += delta;
if (current >= 1.0f) {
current -= 1.0f;
src += src_sample_offset;
src += srcSampleOffset;
}
}
} else {
// downsample
while (count--) {
*(float *)dst = *(const int32 *)src * gain;
dst += dst_sample_offset;
*(float *)dest = *(const int32 *)src * gain;
dest += destSampleOffset;
current += delta;
register int32 skipcount = (int32)current;
current -= skipcount;
src += skipcount * src_sample_offset;
src += skipcount * srcSampleOffset;
}
}
}
void
Resampler::int16_to_float(const void *_src, int32 src_sample_offset, int32 src_sample_count,
void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain)
Resampler::int16_to_float(const void *_src, int32 srcSampleOffset,
int32 srcSampleCount, void *_dest, int32 destSampleOffset,
int32 destSampleCount, float _gain)
{
register const char * src = (const char *) _src;
register char * dst = (char *) _dst;
register int32 count = dst_sample_count;
register const char * src = (const char *)_src;
register char * dest = (char *)_dest;
register int32 count = destSampleCount;
register float gain = _gain / 32767.0;
if (src_sample_count == dst_sample_count) {
if (srcSampleCount == destSampleCount) {
// optimized case for no resampling
while (count--) {
*(float *)dst = *(const int16 *)src * gain;
src += src_sample_offset;
dst += dst_sample_offset;
*(float *)dest = *(const int16 *)src * gain;
src += srcSampleOffset;
dest += destSampleOffset;
}
return;
}
register float delta = float(src_sample_count) / float(dst_sample_count);
register float delta = float(srcSampleCount) / float(destSampleCount);
register float current = 0.0f;
if (delta < 1.0) {
// upsample
while (count--) {
*(float *)dst = *(const int16 *)src * gain;
dst += dst_sample_offset;
*(float *)dest = *(const int16 *)src * gain;
dest += destSampleOffset;
current += delta;
if (current >= 1.0f) {
current -= 1.0f;
src += src_sample_offset;
src += srcSampleOffset;
}
}
} else {
// downsample
while (count--) {
*(float *)dst = *(const int16 *)src * gain;
dst += dst_sample_offset;
*(float *)dest = *(const int16 *)src * gain;
dest += destSampleOffset;
current += delta;
register int32 skipcount = (int32)current;
current -= skipcount;
src += skipcount * src_sample_offset;
src += skipcount * srcSampleOffset;
}
}
}
void
Resampler::int8_to_float(const void *_src, int32 src_sample_offset, int32 src_sample_count,
void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain)
Resampler::int8_to_float(const void *_src, int32 srcSampleOffset,
int32 srcSampleCount, void *_dest, int32 destSampleOffset,
int32 destSampleCount, float _gain)
{
register const char * src = (const char *) _src;
register char * dst = (char *) _dst;
register int32 count = dst_sample_count;
register const char * src = (const char *)_src;
register char * dest = (char *)_dest;
register int32 count = destSampleCount;
register float gain = _gain / 127.0;
if (src_sample_count == dst_sample_count) {
if (srcSampleCount == destSampleCount) {
// optimized case for no resampling
while (count--) {
*(float *)dst = *(const int8 *)src * gain;
src += src_sample_offset;
dst += dst_sample_offset;
*(float *)dest = *(const int8 *)src * gain;
src += srcSampleOffset;
dest += destSampleOffset;
}
return;
}
register float delta = float(src_sample_count) / float(dst_sample_count);
register float delta = float(srcSampleCount) / float(destSampleCount);
register float current = 0.0f;
if (delta < 1.0) {
// upsample
while (count--) {
*(float *)dst = *(const int8 *)src * gain;
dst += dst_sample_offset;
*(float *)dest = *(const int8 *)src * gain;
dest += destSampleOffset;
current += delta;
if (current >= 1.0f) {
current -= 1.0f;
src += src_sample_offset;
src += srcSampleOffset;
}
}
} else {
// downsample
while (count--) {
*(float *)dst = *(const int8 *)src * gain;
dst += dst_sample_offset;
*(float *)dest = *(const int8 *)src * gain;
dest += destSampleOffset;
current += delta;
register int32 skipcount = (int32)current;
current -= skipcount;
src += skipcount * src_sample_offset;
src += skipcount * srcSampleOffset;
}
}
}
void
Resampler::uint8_to_float(const void *_src, int32 src_sample_offset, int32 src_sample_count,
void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain)
Resampler::uint8_to_float(const void *_src, int32 srcSampleOffset,
int32 srcSampleCount, void *_dest, int32 destSampleOffset,
int32 destSampleCount, float _gain)
{
register const char * src = (const char *) _src;
register char * dst = (char *) _dst;
register int32 count = dst_sample_count;
register const char * src = (const char *)_src;
register char * dest = (char *)_dest;
register int32 count = destSampleCount;
register float gain = _gain / 127.0;
if (src_sample_count == dst_sample_count) {
if (srcSampleCount == destSampleCount) {
// optimized case for no resampling
while (count--) {
*(float *)dst = (((int32) *(const uint8 *)src) - 128) * gain;
src += src_sample_offset;
dst += dst_sample_offset;
*(float *)dest = (((int32) *(const uint8 *)src) - 128) * gain;
src += srcSampleOffset;
dest += destSampleOffset;
}
return;
}
register float delta = float(src_sample_count) / float(dst_sample_count);
register float delta = float(srcSampleCount) / float(destSampleCount);
register float current = 0.0f;
if (delta < 1.0) {
// upsample
while (count--) {
*(float *)dst = (((int32) *(const uint8 *)src) - 128) * gain;
dst += dst_sample_offset;
*(float *)dest = (((int32) *(const uint8 *)src) - 128) * gain;
dest += destSampleOffset;
current += delta;
if (current >= 1.0f) {
current -= 1.0f;
src += src_sample_offset;
src += srcSampleOffset;
}
}
} else {
// downsample
while (count--) {
*(float *)dst = (((int32) *(const uint8 *)src) - 128) * gain;
dst += dst_sample_offset;
*(float *)dest = (((int32) *(const uint8 *)src) - 128) * gain;
dest += destSampleOffset;
current += delta;
register int32 skipcount = (int32)current;
current -= skipcount;
src += skipcount * src_sample_offset;
src += skipcount * srcSampleOffset;
}
}
}
void
Resampler::float_to_int32(const void *_src, int32 src_sample_offset, int32 src_sample_count,
void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain)
Resampler::float_to_int32(const void *_src, int32 srcSampleOffset,
int32 srcSampleCount, void *_dest, int32 destSampleOffset,
int32 destSampleCount, float _gain)
{
register const char * src = (const char *) _src;
register char * dst = (char *) _dst;
register int32 count = dst_sample_count;
register const char * src = (const char *)_src;
register char * dest = (char *)_dest;
register int32 count = destSampleCount;
register float gain = _gain * 2147483647.0;
if (src_sample_count == dst_sample_count) {
if (srcSampleCount == destSampleCount) {
// optimized case for no resampling
while (count--) {
register float sample = *(const float *)src * gain;
if (sample > 2147483647.0f)
*(int32 *)dst = 2147483647L;
*(int32 *)dest = 2147483647L;
else if (sample < -2147483647.0f)
*(int32 *)dst = -2147483647L;
*(int32 *)dest = -2147483647L;
else
*(int32 *)dst = (int32)sample;
src += src_sample_offset;
dst += dst_sample_offset;
*(int32 *)dest = (int32)sample;
src += srcSampleOffset;
dest += destSampleOffset;
}
return;
}
register float delta = float(src_sample_count) / float(dst_sample_count);
register float delta = float(srcSampleCount) / float(destSampleCount);
register float current = 0.0f;
if (delta < 1.0) {
@ -336,16 +359,16 @@ Resampler::float_to_int32(const void *_src, int32 src_sample_offset, int32 src_s
while (count--) {
register float sample = *(const float *)src * gain;
if (sample > 2147483647.0f)
*(int32 *)dst = 2147483647L;
*(int32 *)dest = 2147483647L;
else if (sample < -2147483647.0f)
*(int32 *)dst = -2147483647L;
*(int32 *)dest = -2147483647L;
else
*(int32 *)dst = (int32)sample;
dst += dst_sample_offset;
*(int32 *)dest = (int32)sample;
dest += destSampleOffset;
current += delta;
if (current >= 1.0f) {
current -= 1.0f;
src += src_sample_offset;
src += srcSampleOffset;
}
}
} else {
@ -353,47 +376,48 @@ Resampler::float_to_int32(const void *_src, int32 src_sample_offset, int32 src_s
while (count--) {
register float sample = *(const float *)src * gain;
if (sample > 2147483647.0f)
*(int32 *)dst = 2147483647L;
*(int32 *)dest = 2147483647L;
else if (sample < -2147483647.0f)
*(int32 *)dst = -2147483647L;
*(int32 *)dest = -2147483647L;
else
*(int32 *)dst = (int32)sample;
dst += dst_sample_offset;
*(int32 *)dest = (int32)sample;
dest += destSampleOffset;
current += delta;
register int32 skipcount = (int32)current;
current -= skipcount;
src += skipcount * src_sample_offset;
src += skipcount * srcSampleOffset;
}
}
}
void
Resampler::float_to_int16(const void *_src, int32 src_sample_offset, int32 src_sample_count,
void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain)
Resampler::float_to_int16(const void *_src, int32 srcSampleOffset,
int32 srcSampleCount, void *_dest, int32 destSampleOffset,
int32 destSampleCount, float _gain)
{
register const char * src = (const char *) _src;
register char * dst = (char *) _dst;
register int32 count = dst_sample_count;
register const char * src = (const char *)_src;
register char * dest = (char *)_dest;
register int32 count = destSampleCount;
register float gain = _gain * 32767.0;
if (src_sample_count == dst_sample_count) {
if (srcSampleCount == destSampleCount) {
// optimized case for no resampling
while (count--) {
register float sample = *(const float *)src * gain;
if (sample > 32767.0f)
*(int16 *)dst = 32767;
*(int16 *)dest = 32767;
else if (sample < -32767.0f)
*(int16 *)dst = -32767;
*(int16 *)dest = -32767;
else
*(int16 *)dst = (int16)sample;
src += src_sample_offset;
dst += dst_sample_offset;
*(int16 *)dest = (int16)sample;
src += srcSampleOffset;
dest += destSampleOffset;
}
return;
}
register float delta = float(src_sample_count) / float(dst_sample_count);
register float delta = float(srcSampleCount) / float(destSampleCount);
register float current = 0.0f;
if (delta < 1.0) {
@ -401,16 +425,16 @@ Resampler::float_to_int16(const void *_src, int32 src_sample_offset, int32 src_s
while (count--) {
register float sample = *(const float *)src * gain;
if (sample > 32767.0f)
*(int16 *)dst = 32767;
*(int16 *)dest = 32767;
else if (sample < -32767.0f)
*(int16 *)dst = -32767;
*(int16 *)dest = -32767;
else
*(int16 *)dst = (int16)sample;
dst += dst_sample_offset;
*(int16 *)dest = (int16)sample;
dest += destSampleOffset;
current += delta;
if (current >= 1.0f) {
current -= 1.0f;
src += src_sample_offset;
src += srcSampleOffset;
}
}
} else {
@ -418,46 +442,48 @@ Resampler::float_to_int16(const void *_src, int32 src_sample_offset, int32 src_s
while (count--) {
register float sample = *(const float *)src * gain;
if (sample > 32767.0f)
*(int16 *)dst = 32767;
*(int16 *)dest = 32767;
else if (sample < -32767.0f)
*(int16 *)dst = -32767;
*(int16 *)dest = -32767;
else
*(int16 *)dst = (int16)sample;
dst += dst_sample_offset;
*(int16 *)dest = (int16)sample;
dest += destSampleOffset;
current += delta;
register int32 skipcount = (int32)current;
current -= skipcount;
src += skipcount * src_sample_offset;
src += skipcount * srcSampleOffset;
}
}
}
void
Resampler::float_to_int8(const void *_src, int32 src_sample_offset, int32 src_sample_count,
void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain)
Resampler::float_to_int8(const void *_src, int32 srcSampleOffset,
int32 srcSampleCount, void *_dest, int32 destSampleOffset,
int32 destSampleCount, float _gain)
{
register const char * src = (const char *) _src;
register char * dst = (char *) _dst;
register int32 count = dst_sample_count;
register const char * src = (const char *)_src;
register char * dest = (char *)_dest;
register int32 count = destSampleCount;
register float gain = _gain * 127.0;
if (src_sample_count == dst_sample_count) {
if (srcSampleCount == destSampleCount) {
// optimized case for no resampling
while (count--) {
register float sample = *(const float *)src * gain;
if (sample > 127.0f)
*(int8 *)dst = 127;
*(int8 *)dest = 127;
else if (sample < -127.0f)
*(int8 *)dst = -127;
*(int8 *)dest = -127;
else
*(int8 *)dst = (int8)sample;
src += src_sample_offset;
dst += dst_sample_offset;
*(int8 *)dest = (int8)sample;
src += srcSampleOffset;
dest += destSampleOffset;
}
return;
}
register float delta = float(src_sample_count) / float(dst_sample_count);
register float delta = float(srcSampleCount) / float(destSampleCount);
register float current = 0.0f;
if (delta < 1.0) {
@ -465,16 +491,16 @@ Resampler::float_to_int8(const void *_src, int32 src_sample_offset, int32 src_sa
while (count--) {
register float sample = *(const float *)src * gain;
if (sample > 127.0f)
*(int8 *)dst = 127;
*(int8 *)dest = 127;
else if (sample < -127.0f)
*(int8 *)dst = -127;
*(int8 *)dest = -127;
else
*(int8 *)dst = (int8)sample;
dst += dst_sample_offset;
*(int8 *)dest = (int8)sample;
dest += destSampleOffset;
current += delta;
if (current >= 1.0f) {
current -= 1.0f;
src += src_sample_offset;
src += srcSampleOffset;
}
}
} else {
@ -482,46 +508,48 @@ Resampler::float_to_int8(const void *_src, int32 src_sample_offset, int32 src_sa
while (count--) {
register float sample = *(const float *)src * gain;
if (sample > 127.0f)
*(int8 *)dst = 127;
*(int8 *)dest = 127;
else if (sample < -127.0f)
*(int8 *)dst = -127;
*(int8 *)dest = -127;
else
*(int8 *)dst = (int8)sample;
dst += dst_sample_offset;
*(int8 *)dest = (int8)sample;
dest += destSampleOffset;
current += delta;
register int32 skipcount = (int32)current;
current -= skipcount;
src += skipcount * src_sample_offset;
src += skipcount * srcSampleOffset;
}
}
}
void
Resampler::float_to_uint8(const void *_src, int32 src_sample_offset, int32 src_sample_count,
void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain)
Resampler::float_to_uint8(const void *_src, int32 srcSampleOffset,
int32 srcSampleCount, void *_dest, int32 destSampleOffset,
int32 destSampleCount, float _gain)
{
register const char * src = (const char *) _src;
register char * dst = (char *) _dst;
register int32 count = dst_sample_count;
register const char * src = (const char *)_src;
register char * dest = (char *)_dest;
register int32 count = destSampleCount;
register float gain = _gain * 127.0;
if (src_sample_count == dst_sample_count) {
if (srcSampleCount == destSampleCount) {
// optimized case for no resampling
while (count--) {
register float sample = 128.0f + *(const float *)src * gain;
if (sample > 255.0f)
*(uint8 *)dst = 255;
*(uint8 *)dest = 255;
else if (sample < 1.0f)
*(uint8 *)dst = 1;
*(uint8 *)dest = 1;
else
*(uint8 *)dst = (uint8)sample;
src += src_sample_offset;
dst += dst_sample_offset;
*(uint8 *)dest = (uint8)sample;
src += srcSampleOffset;
dest += destSampleOffset;
}
return;
}
register float delta = float(src_sample_count) / float(dst_sample_count);
register float delta = float(srcSampleCount) / float(destSampleCount);
register float current = 0.0f;
if (delta < 1.0) {
@ -529,16 +557,16 @@ Resampler::float_to_uint8(const void *_src, int32 src_sample_offset, int32 src_s
while (count--) {
register float sample = 128.0f + *(const float *)src * gain;
if (sample > 255.0f)
*(uint8 *)dst = 255;
*(uint8 *)dest = 255;
else if (sample < 1.0f)
*(uint8 *)dst = 1;
*(uint8 *)dest = 1;
else
*(uint8 *)dst = (uint8)sample;
dst += dst_sample_offset;
*(uint8 *)dest = (uint8)sample;
dest += destSampleOffset;
current += delta;
if (current >= 1.0f) {
current -= 1.0f;
src += src_sample_offset;
src += srcSampleOffset;
}
}
} else {
@ -546,16 +574,16 @@ Resampler::float_to_uint8(const void *_src, int32 src_sample_offset, int32 src_s
while (count--) {
register float sample = 128.0f + *(const float *)src * gain;
if (sample > 255.0f)
*(uint8 *)dst = 255;
*(uint8 *)dest = 255;
else if (sample < 1.0f)
*(uint8 *)dst = 1;
*(uint8 *)dest = 1;
else
*(uint8 *)dst = (uint8)sample;
dst += dst_sample_offset;
*(uint8 *)dest = (uint8)sample;
dest += destSampleOffset;
current += delta;
register int32 skipcount = (int32)current;
current -= skipcount;
src += skipcount * src_sample_offset;
src += skipcount * srcSampleOffset;
}
}
}

View File

@ -1,59 +1,80 @@
/* Copyright (C) 2003 Marcus Overhagen
* Released under terms of the MIT license.
*
* A simple resampling class for the audio mixer.
* You pick the conversion function on object creation,
* and then call the Resample() function, specifying data pointer,
* offset (in bytes) to the next sample, and count of samples for
* both source and destination.
*
/*
* Copyright 2003 Marcus Overhagen
* Distributed under the terms of the MIT License.
*/
#ifndef _RESAMPLER_H
#define _RESAMPLER_H
#include <SupportDefs.h>
class Resampler
{
class Resampler {
public:
Resampler(uint32 sourceformat, uint32 destformat);
virtual ~Resampler();
status_t InitCheck();
void Resample(const void *src, int32 src_sample_offset, int32 src_sample_count,
void *dst, int32 dst_sample_offset, int32 dst_sample_count, float gain);
Resampler(uint32 sourceFormat,
uint32 destFormat);
virtual ~Resampler();
status_t InitCheck() const;
void Resample(const void* src, int32 srcSampleOffset,
int32 srcSampleCount, void* dest,
int32 destSampleOffset,
int32 destSampleCount, float gain);
protected:
virtual void float_to_float (const void *src, int32 src_sample_offset, int32 src_sample_count,
void *dst, int32 dst_sample_offset, int32 dst_sample_count, float gain);
virtual void int32_to_float (const void *src, int32 src_sample_offset, int32 src_sample_count,
void *dst, int32 dst_sample_offset, int32 dst_sample_count, float gain);
virtual void int16_to_float (const void *src, int32 src_sample_offset, int32 src_sample_count,
void *dst, int32 dst_sample_offset, int32 dst_sample_count, float gain);
virtual void int8_to_float (const void *src, int32 src_sample_offset, int32 src_sample_count,
void *dst, int32 dst_sample_offset, int32 dst_sample_count, float gain);
virtual void uint8_to_float (const void *src, int32 src_sample_offset, int32 src_sample_count,
void *dst, int32 dst_sample_offset, int32 dst_sample_count, float gain);
virtual void float_to_int32 (const void *src, int32 src_sample_offset, int32 src_sample_count,
void *dst, int32 dst_sample_offset, int32 dst_sample_count, float gain);
virtual void float_to_int16 (const void *src, int32 src_sample_offset, int32 src_sample_count,
void *dst, int32 dst_sample_offset, int32 dst_sample_count, float gain);
virtual void float_to_int8 (const void *src, int32 src_sample_offset, int32 src_sample_count,
void *dst, int32 dst_sample_offset, int32 dst_sample_count, float gain);
virtual void float_to_uint8 (const void *src, int32 src_sample_offset, int32 src_sample_count,
void *dst, int32 dst_sample_offset, int32 dst_sample_count, float gain);
virtual void float_to_float(const void* src,
int32 srcSampleOffset, int32 srcSampleCount,
void* dest, int32 destSampleOffset,
int32 destSampleCount, float gain);
virtual void int32_to_float(const void* src,
int32 srcSampleOffset, int32 srcSampleCount,
void* dest, int32 destSampleOffset,
int32 destSampleCount, float gain);
virtual void int16_to_float(const void* src,
int32 srcSampleOffset, int32 srcSampleCount,
void* dest, int32 destSampleOffset,
int32 destSampleCount, float gain);
virtual void int8_to_float(const void* src,
int32 srcSampleOffset, int32 srcSampleCount,
void* dest, int32 destSampleOffset,
int32 destSampleCount, float gain);
virtual void uint8_to_float(const void* src,
int32 srcSampleOffset, int32 srcSampleCount,
void* dest, int32 destSampleOffset,
int32 destSampleCount, float gain);
virtual void float_to_int32(const void* src,
int32 srcSampleOffset, int32 srcSampleCount,
void* dest, int32 destSampleOffset,
int32 destSampleCount, float gain);
virtual void float_to_int16(const void* src,
int32 srcSampleOffset, int32 srcSampleCount,
void* dest, int32 destSampleOffset,
int32 destSampleCount, float gain);
virtual void float_to_int8(const void* src,
int32 srcSampleOffset, int32 srcSampleCount,
void* dest, int32 destSampleOffset,
int32 destSampleCount, float gain);
virtual void float_to_uint8(const void* src,
int32 srcSampleOffset, int32 srcSampleCount,
void* dest, int32 destSampleOffset,
int32 destSampleCount, float gain);
private:
void (Resampler::*fFunc) (const void *, int32, int32, void *, int32, int32, float);
void (Resampler::*fFunc)(const void* src,
int32 srcSampleOffset, int32 srcSampleCount,
void* dest, int32 destSampleOffset,
int32 destSampleCount, float gain);
};
inline void
Resampler::Resample(const void *src, int32 src_sample_offset, int32 src_sample_count,
void *dst, int32 dst_sample_offset, int32 dst_sample_count, float gain)
Resampler::Resample(const void *src, int32 srcSampleOffset,
int32 srcSampleCount, void *dest, int32 destSampleOffset,
int32 destSampleCount, float gain)
{
(this->*fFunc)(src, src_sample_offset, src_sample_count, dst, dst_sample_offset, dst_sample_count, gain);
(this->*fFunc)(src, srcSampleOffset, srcSampleCount, dest, destSampleOffset,
destSampleCount, gain);
}
#endif // _RESAMPLER_H

View File

@ -1,41 +1,48 @@
/*
* Copyright 2003 Marcus Overhagen
* Distributed under the terms of the MIT License.
*/
#ifndef _MEDIA_RT_LIST_H
#define _MEDIA_RT_LIST_H
/* Copyright (C) 2003 Marcus Overhagen
* Released under terms of the MIT license.
*
* A simple list template that uses realtime
* memory and does no error checking. Since
* it doesn't call constructors or destructors,
* don't use it to store objects.
*/
/*! A simple list template that uses realtime
memory and does no error checking. Since
it doesn't call constructors or destructors,
don't use it to store objects.
// TODO: no error checking? Great.
*/
#include <RealtimeAlloc.h>
template<class value> class RtList
{
template<class value> class RtList {
public:
RtList()
: item_max(INIT_COUNT),
:
item_max(INIT_COUNT),
item_count(0),
items((value *)rtm_alloc(NULL, sizeof(value) * INIT_COUNT))
items((value*)rtm_alloc(NULL, sizeof(value) * INIT_COUNT))
{
}
~RtList()
{
rtm_free(items);
}
value *Create()
value* Create()
{
if (item_count == item_max) {
item_max += INC_COUNT;
rtm_realloc((void **)&items, sizeof(value) * item_max);
rtm_realloc((void**)&items, sizeof(value) * item_max);
}
return &items[item_count++];
}
value *ItemAt(int index)
value* ItemAt(int index)
{
return &items[index];
}
@ -51,14 +58,15 @@ public:
}
private:
RtList(const RtList<value> &other);
RtList<value> &operator=(const RtList<value> &other);
RtList(const RtList<value>& other);
RtList<value> &operator=(const RtList<value>& other);
private:
enum { INIT_COUNT = 8, INC_COUNT = 16 };
int item_max;
int item_count;
value *items;
int item_max;
int item_count;
value* items;
};
#endif // _MEDIA_RT_LIST_H