* 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:
parent
1fd264a18e
commit
a9cf57cff5
@ -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(),
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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++;
|
||||
|
@ -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 (;;) {
|
||||
|
@ -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_ */
|
||||
|
@ -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];
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user