mirror of
https://github.com/clangen/musikcube.git
synced 2025-03-14 04:18:36 +00:00
Bifrucated stream functionality into DynamicStream (with buffers of
potentially dynamic/changing size), and FixedSizeStream where we try really hard to ensure the buffers are a consistent size.
This commit is contained in:
parent
08a876edb2
commit
30aba00e23
@ -2,8 +2,9 @@ set(CORE_SOURCES
|
||||
./debug.cpp
|
||||
./audio/Buffer.cpp
|
||||
./audio/Player.cpp
|
||||
./audio/Stream.cpp
|
||||
./audio/GaplessTransport.cpp
|
||||
./audio/DynamicStream.cpp
|
||||
./audio/FixedSizeStream.cpp
|
||||
./audio/Visualizer.cpp
|
||||
./db/Connection.cpp
|
||||
./db/ScopedTransaction.cpp
|
||||
|
@ -35,7 +35,7 @@
|
||||
#include "pch.hpp"
|
||||
|
||||
#include <core/debug.h>
|
||||
#include <core/audio/Stream.h>
|
||||
#include <core/audio/DynamicStream.h>
|
||||
#include <core/sdk/IDecoderFactory.h>
|
||||
#include <core/plugin/PluginFactory.h>
|
||||
|
||||
@ -43,14 +43,14 @@ using namespace musik::core::audio;
|
||||
using namespace musik::core::sdk;
|
||||
using musik::core::PluginFactory;
|
||||
|
||||
static std::string TAG = "Stream";
|
||||
static std::string TAG = "DynamicStream";
|
||||
|
||||
Stream::Stream(unsigned int options)
|
||||
: preferedBufferSampleSize(4096)
|
||||
, options(options)
|
||||
, decoderSampleRate(0)
|
||||
, decoderChannels(0)
|
||||
, decoderSamplePosition(0)
|
||||
DynamicStream::DynamicStream(unsigned int options)
|
||||
: preferedBufferSampleSize(4096)
|
||||
, options(options)
|
||||
, decoderSampleRate(0)
|
||||
, decoderChannels(0)
|
||||
, decoderSamplePosition(0)
|
||||
{
|
||||
if ((this->options & NoDSP) == 0) {
|
||||
typedef PluginFactory::DestroyDeleter<IDSP> Deleter;
|
||||
@ -60,14 +60,14 @@ Stream::Stream(unsigned int options)
|
||||
this->LoadDecoderPlugins();
|
||||
}
|
||||
|
||||
Stream::~Stream() {
|
||||
DynamicStream::~DynamicStream() {
|
||||
}
|
||||
|
||||
StreamPtr Stream::Create(unsigned int options) {
|
||||
return StreamPtr(new Stream(options));
|
||||
StreamPtr DynamicStream::Create(unsigned int options) {
|
||||
return StreamPtr(new DynamicStream(options));
|
||||
}
|
||||
|
||||
double Stream::SetPosition(double requestedSeconds) {
|
||||
double DynamicStream::SetPosition(double requestedSeconds) {
|
||||
double actualSeconds = this->decoder->SetPosition(requestedSeconds);
|
||||
|
||||
if (actualSeconds != -1) {
|
||||
@ -80,7 +80,7 @@ double Stream::SetPosition(double requestedSeconds) {
|
||||
return actualSeconds;
|
||||
}
|
||||
|
||||
bool Stream::OpenStream(std::string uri) {
|
||||
bool DynamicStream::OpenStream(std::string uri) {
|
||||
musik::debug::info(TAG, "opening " + uri);
|
||||
|
||||
/* use our file stream abstraction to open the data at the
|
||||
@ -97,9 +97,9 @@ bool Stream::OpenStream(std::string uri) {
|
||||
DecoderFactoryList::iterator end = this->decoderFactories.end();
|
||||
DecoderFactoryPtr decoderFactory;
|
||||
|
||||
for ( ; factories != end && !decoderFactory; ++factories) {
|
||||
for (; factories != end && !decoderFactory; ++factories) {
|
||||
if ((*factories)->CanHandle(this->dataStream->Type())) {
|
||||
decoderFactory = (*factories);
|
||||
decoderFactory = (*factories);
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,11 +130,11 @@ bool Stream::OpenStream(std::string uri) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void Stream::OnBufferProcessedByPlayer(BufferPtr buffer) {
|
||||
void DynamicStream::OnBufferProcessedByPlayer(BufferPtr buffer) {
|
||||
this->RecycleBuffer(buffer);
|
||||
}
|
||||
|
||||
BufferPtr Stream::GetNextBufferFromDecoder() {
|
||||
BufferPtr DynamicStream::GetNextBufferFromDecoder() {
|
||||
/* get a spare buffer, then ask the decoder for some data */
|
||||
BufferPtr buffer = this->GetEmptyBuffer();
|
||||
if (!this->decoder->GetBuffer(buffer.get())) {
|
||||
@ -153,13 +153,13 @@ BufferPtr Stream::GetNextBufferFromDecoder() {
|
||||
/* calculate the position (seconds) in the buffer */
|
||||
buffer->SetPosition(
|
||||
((double) this->decoderSamplePosition) /
|
||||
((double) buffer->Channels()) /
|
||||
((double)buffer->Channels()) /
|
||||
((double) this->decoderSampleRate));
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
BufferPtr Stream::GetNextProcessedOutputBuffer() {
|
||||
BufferPtr DynamicStream::GetNextProcessedOutputBuffer() {
|
||||
/* ask the decoder for the next buffer */
|
||||
BufferPtr currentBuffer = this->GetNextBufferFromDecoder();
|
||||
|
||||
@ -200,7 +200,7 @@ BufferPtr Stream::GetNextProcessedOutputBuffer() {
|
||||
|
||||
/* returns a previously used buffer, if one is available. otherwise, a
|
||||
new one will be allocated. */
|
||||
BufferPtr Stream::GetEmptyBuffer() {
|
||||
BufferPtr DynamicStream::GetEmptyBuffer() {
|
||||
BufferPtr buffer;
|
||||
if (!this->recycledBuffers.empty()) {
|
||||
buffer = this->recycledBuffers.front();
|
||||
@ -214,26 +214,13 @@ BufferPtr Stream::GetEmptyBuffer() {
|
||||
}
|
||||
|
||||
/* marks a used buffer as recycled so it can be re-used later. */
|
||||
void Stream::RecycleBuffer(BufferPtr oldBuffer) {
|
||||
void DynamicStream::RecycleBuffer(BufferPtr oldBuffer) {
|
||||
this->recycledBuffers.push_back(oldBuffer);
|
||||
}
|
||||
|
||||
double Stream::DecoderProgress() {
|
||||
if (this->dataStream) {
|
||||
long fileSize = this->dataStream->Length();
|
||||
long filePosition = this->dataStream->Position();
|
||||
|
||||
if (fileSize && filePosition) {
|
||||
return ((double) filePosition) / ((double) fileSize);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Stream::LoadDecoderPlugins() {
|
||||
void DynamicStream::LoadDecoderPlugins() {
|
||||
PluginFactory::DestroyDeleter<IDecoderFactory> typedef Deleter;
|
||||
|
||||
this->decoderFactories = PluginFactory::Instance()
|
||||
.QueryInterface<IDecoderFactory, Deleter>("GetDecoderFactory");
|
||||
}
|
||||
}
|
@ -37,6 +37,7 @@
|
||||
#include <core/config.h>
|
||||
#include <core/io/DataStreamFactory.h>
|
||||
#include <core/audio/Buffer.h>
|
||||
#include <core/audio/IStream.h>
|
||||
#include <core/sdk/IDecoder.h>
|
||||
#include <core/sdk/IDSP.h>
|
||||
#include <core/sdk/IDecoderFactory.h>
|
||||
@ -46,33 +47,23 @@
|
||||
|
||||
namespace musik { namespace core { namespace audio {
|
||||
|
||||
class Stream;
|
||||
class Player;
|
||||
typedef std::shared_ptr<Stream> StreamPtr;
|
||||
|
||||
class Stream {
|
||||
class DynamicStream : public IStream {
|
||||
using IDSP = musik::core::sdk::IDSP;
|
||||
using IDecoder = musik::core::sdk::IDecoder;
|
||||
using IDecoderFactory = musik::core::sdk::IDecoderFactory;
|
||||
|
||||
public:
|
||||
static StreamPtr Create(unsigned int options=0);
|
||||
|
||||
typedef enum {
|
||||
NoDSP = 1
|
||||
} Options;
|
||||
|
||||
private:
|
||||
Stream(unsigned int options);
|
||||
|
||||
public:
|
||||
~Stream();
|
||||
virtual ~DynamicStream();
|
||||
|
||||
BufferPtr GetNextProcessedOutputBuffer();
|
||||
void OnBufferProcessedByPlayer(BufferPtr buffer);
|
||||
double SetPosition(double seconds);
|
||||
bool OpenStream(std::string uri);
|
||||
double DecoderProgress();
|
||||
|
||||
static StreamPtr Create(unsigned int options = 0);
|
||||
|
||||
private:
|
||||
DynamicStream(unsigned int options);
|
||||
|
||||
private:
|
||||
void RecycleBuffer(BufferPtr oldBuffer);
|
||||
@ -88,7 +79,6 @@ namespace musik { namespace core { namespace audio {
|
||||
typedef std::vector<DspPtr> Dsps;
|
||||
|
||||
long preferedBufferSampleSize;
|
||||
double maxCacheLength;
|
||||
unsigned int options;
|
||||
long decoderSampleRate;
|
||||
long decoderChannels;
|
257
src/core/audio/FixedSizeStream.cpp
Normal file
257
src/core/audio/FixedSizeStream.cpp
Normal file
@ -0,0 +1,257 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2007-2016 musikcube team
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// * Neither the name of the author nor the names of other contributors may
|
||||
// be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pch.hpp"
|
||||
|
||||
#include "FixedSizeStream.h"
|
||||
#include <core/debug.h>
|
||||
#include <core/sdk/IDecoderFactory.h>
|
||||
#include <core/plugin/PluginFactory.h>
|
||||
|
||||
using namespace musik::core::audio;
|
||||
using namespace musik::core::sdk;
|
||||
using musik::core::PluginFactory;
|
||||
|
||||
static std::string TAG = "FixedSizeStream";
|
||||
|
||||
FixedSizeStream::FixedSizeStream(int samplesPerChannel, int bufferCount, unsigned int options)
|
||||
: options(options)
|
||||
, samplesPerChannel(samplesPerChannel)
|
||||
, bufferCount(bufferCount)
|
||||
, decoderSampleRate(0)
|
||||
, decoderChannels(0)
|
||||
, decoderSamplePosition(0)
|
||||
, currentBuffer(Buffer::Create())
|
||||
, dspBuffer(Buffer::Create())
|
||||
{
|
||||
if ((this->options & NoDSP) == 0) {
|
||||
typedef PluginFactory::DestroyDeleter<IDSP> Deleter;
|
||||
this->dsps = PluginFactory::Instance().QueryInterface<IDSP, Deleter>("GetDSP");
|
||||
}
|
||||
|
||||
this->LoadDecoderPlugins();
|
||||
}
|
||||
|
||||
FixedSizeStream::~FixedSizeStream() {
|
||||
}
|
||||
|
||||
StreamPtr FixedSizeStream::Create(int samplesPerChannel, int bufferCount, unsigned int options) {
|
||||
return StreamPtr(new FixedSizeStream(samplesPerChannel, bufferCount, options));
|
||||
}
|
||||
|
||||
double FixedSizeStream::SetPosition(double requestedSeconds) {
|
||||
double actualSeconds = this->decoder->SetPosition(requestedSeconds);
|
||||
|
||||
if (actualSeconds != -1) {
|
||||
double rate = (double) this->decoderSampleRate;
|
||||
|
||||
this->decoderSamplePosition =
|
||||
(uint64)(actualSeconds * rate) * this->decoderChannels;
|
||||
}
|
||||
|
||||
return actualSeconds;
|
||||
}
|
||||
|
||||
bool FixedSizeStream::OpenStream(std::string uri) {
|
||||
musik::debug::info(TAG, "opening " + uri);
|
||||
|
||||
/* use our file stream abstraction to open the data at the
|
||||
specified URI */
|
||||
this->dataStream = musik::core::io::DataStreamFactory::OpenUri(uri.c_str());
|
||||
|
||||
if (!this->dataStream) {
|
||||
musik::debug::err(TAG, "failed to open " + uri);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* find a DecoderFactory we can use for this type of data*/
|
||||
DecoderFactoryList::iterator factories = this->decoderFactories.begin();
|
||||
DecoderFactoryList::iterator end = this->decoderFactories.end();
|
||||
DecoderFactoryPtr decoderFactory;
|
||||
|
||||
for ( ; factories != end && !decoderFactory; ++factories) {
|
||||
if ((*factories)->CanHandle(this->dataStream->Type())) {
|
||||
decoderFactory = (*factories);
|
||||
}
|
||||
}
|
||||
|
||||
if (!decoderFactory) {
|
||||
/* nothing can decode this type of file */
|
||||
musik::debug::err(TAG, "nothing could open " + uri);
|
||||
return false;
|
||||
}
|
||||
|
||||
IDecoder *decoder = decoderFactory->CreateDecoder();
|
||||
if (!decoder) {
|
||||
/* shouldn't ever happen, the factory said it can handle this file */
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ask the decoder to open the data stream. if it returns true we're
|
||||
good to start pulling data out of it! */
|
||||
typedef PluginFactory::DestroyDeleter<IDecoder> Deleter;
|
||||
|
||||
this->decoder.reset(decoder, Deleter());
|
||||
if (!this->decoder->Open(this->dataStream.get())) {
|
||||
musik::debug::err(TAG, "open ok, but decode failed " + uri);
|
||||
return false;
|
||||
}
|
||||
|
||||
musik::debug::info(TAG, "about ready to play: " + uri);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FixedSizeStream::OnBufferProcessedByPlayer(BufferPtr buffer) {
|
||||
this->RecycleBuffer(buffer);
|
||||
}
|
||||
|
||||
BufferPtr FixedSizeStream::GetNextBufferFromDecoder() {
|
||||
BufferPtr buffer = this->currentBuffer;
|
||||
|
||||
/* get a spare buffer, then ask the decoder for some data */
|
||||
if (!this->decoder->GetBuffer(buffer.get())) {
|
||||
return BufferPtr();
|
||||
}
|
||||
|
||||
/* remember the sample rate so we can calculate the current time-position */
|
||||
if (!this->decoderSampleRate || !this->decoderChannels) {
|
||||
this->decoderSampleRate = buffer->SampleRate();
|
||||
this->decoderChannels = buffer->Channels();
|
||||
}
|
||||
|
||||
/* offset, in samples */
|
||||
this->decoderSamplePosition += buffer->Samples();
|
||||
|
||||
/* calculate the position (seconds) in the buffer */
|
||||
buffer->SetPosition(
|
||||
((double) this->decoderSamplePosition) /
|
||||
((double) buffer->Channels()) /
|
||||
((double) this->decoderSampleRate));
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
inline BufferPtr FixedSizeStream::GetEmptyBuffer() {
|
||||
BufferPtr target;
|
||||
|
||||
if (recycledBuffers.size()) {
|
||||
target = recycledBuffers.back();
|
||||
recycledBuffers.pop_back();
|
||||
}
|
||||
else {
|
||||
target = Buffer::Create();
|
||||
target->CopyFormat(this->currentBuffer);
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
#define COPY_BUFFER(target, current, count, offset) \
|
||||
target->Copy(¤t->BufferPointer()[offset], count); \
|
||||
target->SetPosition( \
|
||||
((double) this->decoderSamplePosition + offset) / \
|
||||
((double) current->Channels()) / \
|
||||
((double) this->decoderSampleRate)); \
|
||||
this->filledBuffers.push_back(target);
|
||||
|
||||
BufferPtr FixedSizeStream::GetNextProcessedOutputBuffer() {
|
||||
BufferPtr currentBuffer;
|
||||
|
||||
/* ensure we have at least BUFFER_COUNT buffers, and that at least half of them
|
||||
are filled with data! */
|
||||
while (this->filledBuffers.size() < (this->bufferCount / 2) ||
|
||||
this->filledBuffers.size() + this->recycledBuffers.size() < this->bufferCount)
|
||||
{
|
||||
/* ask the decoder for the next buffer */
|
||||
currentBuffer = this->GetNextBufferFromDecoder();
|
||||
|
||||
if (!currentBuffer) {
|
||||
break; /* important... bust out of the loop when we're done! */
|
||||
}
|
||||
|
||||
/* break the buffer into 512 sample per channel buffers. this will
|
||||
help us ensure visualizer data is uniform. note that the last buffer
|
||||
may not be exactly 512 -- that should be fine, generally. */
|
||||
BufferPtr target;
|
||||
|
||||
int floatsPerBuffer = this->samplesPerChannel * currentBuffer->Channels();
|
||||
int buffers = currentBuffer->Samples() / floatsPerBuffer;
|
||||
int offset = 0;
|
||||
|
||||
for (int i = 0; i < buffers; i++) {
|
||||
target = this->GetEmptyBuffer();
|
||||
COPY_BUFFER(target, currentBuffer, floatsPerBuffer, offset);
|
||||
offset += floatsPerBuffer;
|
||||
}
|
||||
|
||||
if (offset < this->currentBuffer->Samples()) {
|
||||
target = this->GetEmptyBuffer();
|
||||
COPY_BUFFER(target, currentBuffer, this->currentBuffer->Samples() - offset, offset);
|
||||
}
|
||||
}
|
||||
|
||||
if (this->filledBuffers.size()) {
|
||||
currentBuffer = this->filledBuffers.front();
|
||||
this->filledBuffers.pop_front();
|
||||
|
||||
/* let DSP plugins process the buffer */
|
||||
if (this->dsps.size() > 0) {
|
||||
for (Dsps::iterator dsp = this->dsps.begin(); dsp != this->dsps.end(); ++dsp) {
|
||||
dspBuffer->CopyFormat(currentBuffer);
|
||||
dspBuffer->SetPosition(currentBuffer->Position());
|
||||
|
||||
if ((*dsp)->Process(currentBuffer.get(), dspBuffer.get())) {
|
||||
currentBuffer.swap(dspBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return currentBuffer;
|
||||
}
|
||||
|
||||
return BufferPtr();
|
||||
}
|
||||
|
||||
/* marks a used buffer as recycled so it can be re-used later. */
|
||||
void FixedSizeStream::RecycleBuffer(BufferPtr oldBuffer) {
|
||||
this->recycledBuffers.push_back(oldBuffer);
|
||||
}
|
||||
|
||||
void FixedSizeStream::LoadDecoderPlugins() {
|
||||
PluginFactory::DestroyDeleter<IDecoderFactory> typedef Deleter;
|
||||
|
||||
this->decoderFactories = PluginFactory::Instance()
|
||||
.QueryInterface<IDecoderFactory, Deleter>("GetDecoderFactory");
|
||||
}
|
105
src/core/audio/FixedSizeStream.h
Normal file
105
src/core/audio/FixedSizeStream.h
Normal file
@ -0,0 +1,105 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2007-2016 musikcube team
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// * Neither the name of the author nor the names of other contributors may
|
||||
// be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <core/config.h>
|
||||
#include <core/io/DataStreamFactory.h>
|
||||
#include <core/audio/Buffer.h>
|
||||
#include <core/audio/IStream.h>
|
||||
#include <core/sdk/IDecoder.h>
|
||||
#include <core/sdk/IDSP.h>
|
||||
#include <core/sdk/IDecoderFactory.h>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <list>
|
||||
|
||||
namespace musik { namespace core { namespace audio {
|
||||
|
||||
class FixedSizeStream : public IStream {
|
||||
using IDSP = musik::core::sdk::IDSP;
|
||||
using IDecoder = musik::core::sdk::IDecoder;
|
||||
using IDecoderFactory = musik::core::sdk::IDecoderFactory;
|
||||
|
||||
public:
|
||||
static StreamPtr Create(
|
||||
int samplesPerChannel = 512,
|
||||
int bufferCount = 32,
|
||||
unsigned int options = 0);
|
||||
|
||||
private:
|
||||
FixedSizeStream(int samplesPerChannel, int bufferCount, unsigned int options);
|
||||
|
||||
public:
|
||||
virtual ~FixedSizeStream();
|
||||
|
||||
virtual BufferPtr GetNextProcessedOutputBuffer();
|
||||
virtual void OnBufferProcessedByPlayer(BufferPtr buffer);
|
||||
virtual double SetPosition(double seconds);
|
||||
virtual bool OpenStream(std::string uri);
|
||||
|
||||
private:
|
||||
void RecycleBuffer(BufferPtr oldBuffer);
|
||||
BufferPtr GetNextBufferFromDecoder();
|
||||
BufferPtr GetEmptyBuffer();
|
||||
void LoadDecoderPlugins();
|
||||
|
||||
typedef std::list<BufferPtr> BufferList;
|
||||
typedef std::shared_ptr<IDecoderFactory> DecoderFactoryPtr;
|
||||
typedef std::vector<DecoderFactoryPtr> DecoderFactoryList;
|
||||
typedef std::shared_ptr<IDecoder> DecoderPtr;
|
||||
typedef std::shared_ptr<IDSP> DspPtr;
|
||||
typedef std::vector<DspPtr> Dsps;
|
||||
|
||||
long decoderSampleRate;
|
||||
long decoderChannels;
|
||||
uint64 decoderSamplePosition;
|
||||
std::string uri;
|
||||
musik::core::io::DataStreamFactory::DataStreamPtr dataStream;
|
||||
|
||||
BufferList recycledBuffers;
|
||||
BufferList filledBuffers;
|
||||
BufferPtr currentBuffer;
|
||||
BufferPtr dspBuffer;
|
||||
|
||||
unsigned int options;
|
||||
int samplesPerChannel;
|
||||
int bufferCount;
|
||||
|
||||
DecoderFactoryList decoderFactories;
|
||||
DecoderPtr decoder;
|
||||
Dsps dsps;
|
||||
};
|
||||
|
||||
} } }
|
63
src/core/audio/IStream.h
Normal file
63
src/core/audio/IStream.h
Normal file
@ -0,0 +1,63 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2007-2016 musikcube team
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// * Neither the name of the author nor the names of other contributors may
|
||||
// be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <core/config.h>
|
||||
#include <core/io/DataStreamFactory.h>
|
||||
#include <core/audio/Buffer.h>
|
||||
#include <core/sdk/IDecoder.h>
|
||||
#include <core/sdk/IDSP.h>
|
||||
#include <core/sdk/IDecoderFactory.h>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <list>
|
||||
|
||||
namespace musik { namespace core { namespace audio {
|
||||
|
||||
class IStream {
|
||||
public:
|
||||
typedef enum {
|
||||
NoDSP = 1
|
||||
} Options;
|
||||
|
||||
virtual BufferPtr GetNextProcessedOutputBuffer() = 0;
|
||||
virtual void OnBufferProcessedByPlayer(BufferPtr buffer) = 0;
|
||||
virtual double SetPosition(double seconds) = 0;
|
||||
virtual bool OpenStream(std::string uri) = 0;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<IStream> StreamPtr;
|
||||
|
||||
} } }
|
@ -36,6 +36,8 @@
|
||||
|
||||
#include <core/debug.h>
|
||||
#include <core/audio/Player.h>
|
||||
#include <core/audio/FixedSizeStream.h>
|
||||
#include <core/audio/DynamicStream.h>
|
||||
#include <core/audio/Visualizer.h>
|
||||
#include <core/plugin/PluginFactory.h>
|
||||
#include <algorithm>
|
||||
@ -137,7 +139,7 @@ int Player::State() {
|
||||
|
||||
void Player::ThreadLoop() {
|
||||
/* create and open the stream */
|
||||
this->stream = Stream::Create();
|
||||
this->stream = DynamicStream::Create();
|
||||
|
||||
BufferPtr buffer;
|
||||
|
||||
@ -314,8 +316,9 @@ static inline void writeToVisualizer(IBuffer *buffer, float *spectrum) {
|
||||
IPcmVisualizer* pcmVis = vis::PcmVisualizer();
|
||||
|
||||
if (specVis && specVis->Visible()) {
|
||||
buffer->Fft(spectrum, FFT_N);
|
||||
vis::SpectrumVisualizer()->Write(spectrum, FFT_N);
|
||||
if (buffer->Fft(spectrum, FFT_N)) {
|
||||
vis::SpectrumVisualizer()->Write(spectrum, FFT_N);
|
||||
}
|
||||
}
|
||||
else if (pcmVis && pcmVis->Visible()) {
|
||||
vis::PcmVisualizer()->Write(buffer);
|
||||
|
@ -35,7 +35,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <core/config.h>
|
||||
#include <core/audio/Stream.h>
|
||||
#include <core/audio/IStream.h>
|
||||
#include <core/sdk/IOutput.h>
|
||||
#include <core/sdk/IBufferProvider.h>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
@ -84,6 +84,7 @@
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="audio\DynamicStream.cpp" />
|
||||
<ClCompile Include="audio\GaplessTransport.cpp" />
|
||||
<ClCompile Include="audio\Visualizer.cpp" />
|
||||
<ClCompile Include="debug.cpp" />
|
||||
@ -107,14 +108,16 @@
|
||||
<ClCompile Include="db\Statement.cpp" />
|
||||
<ClCompile Include="audio\Buffer.cpp" />
|
||||
<ClCompile Include="audio\Player.cpp" />
|
||||
<ClCompile Include="audio\Stream.cpp" />
|
||||
<ClCompile Include="audio\FixedSizeStream.cpp" />
|
||||
<ClCompile Include="plugin\PluginFactory.cpp" />
|
||||
<ClCompile Include="support\Common.cpp" />
|
||||
<ClCompile Include="support\PreferenceKeys.cpp" />
|
||||
<ClCompile Include="support\Preferences.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="audio\DynamicStream.h" />
|
||||
<ClInclude Include="audio\GaplessTransport.h" />
|
||||
<ClInclude Include="audio\IStream.h" />
|
||||
<ClInclude Include="audio\ITransport.h" />
|
||||
<ClInclude Include="audio\Visualizer.h" />
|
||||
<ClInclude Include="debug.h" />
|
||||
@ -158,7 +161,7 @@
|
||||
<ClInclude Include="db\Statement.h" />
|
||||
<ClInclude Include="audio\Buffer.h" />
|
||||
<ClInclude Include="audio\Player.h" />
|
||||
<ClInclude Include="audio\Stream.h" />
|
||||
<ClInclude Include="audio\FixedSizeStream.h" />
|
||||
<ClInclude Include="sdk\IRetainedTrack.h" />
|
||||
<ClInclude Include="sdk\ISpectrumVisualizer.h" />
|
||||
<ClInclude Include="sdk\ITrack.h" />
|
||||
|
@ -55,9 +55,6 @@
|
||||
<ClCompile Include="audio\Player.cpp">
|
||||
<Filter>src\audio</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="audio\Stream.cpp">
|
||||
<Filter>src\audio</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Library\query\QueryBase.cpp">
|
||||
<Filter>src\library\query</Filter>
|
||||
</ClCompile>
|
||||
@ -112,6 +109,12 @@
|
||||
<ClCompile Include="library\track\RetainedTrack.cpp">
|
||||
<Filter>src\library\track</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="audio\FixedSizeStream.cpp">
|
||||
<Filter>src\audio</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="audio\DynamicStream.cpp">
|
||||
<Filter>src\audio</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.hpp">
|
||||
@ -132,9 +135,6 @@
|
||||
<ClInclude Include="audio\Player.h">
|
||||
<Filter>src\audio</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="audio\Stream.h">
|
||||
<Filter>src\audio</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="sdk\IDecoder.h">
|
||||
<Filter>src\sdk</Filter>
|
||||
</ClInclude>
|
||||
@ -273,5 +273,14 @@
|
||||
<ClInclude Include="library\track\RetainedTrack.h">
|
||||
<Filter>src\library\track</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="audio\IStream.h">
|
||||
<Filter>src\audio</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="audio\FixedSizeStream.h">
|
||||
<Filter>src\audio</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="audio\DynamicStream.h">
|
||||
<Filter>src\audio</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -47,7 +47,7 @@
|
||||
#include <core/support/Preferences.h>
|
||||
#include <core/support/PreferenceKeys.h>
|
||||
#include <core/sdk/IAnalyzer.h>
|
||||
#include <core/audio/Stream.h>
|
||||
#include <core/audio/DynamicStream.h>
|
||||
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
@ -635,7 +635,7 @@ void Indexer::RunAnalyzers() {
|
||||
}
|
||||
|
||||
if (!runningAnalyzers.empty()) {
|
||||
audio::StreamPtr stream = audio::Stream::Create(audio::Stream::NoDSP);
|
||||
audio::StreamPtr stream = audio::DynamicStream::Create(audio::IStream::NoDSP);
|
||||
|
||||
if (stream) {
|
||||
if (stream->OpenStream(track.Uri())) {
|
||||
|
@ -78,11 +78,12 @@
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<ImportLibrary>../../bin/$(Configuration)/mC2.lib</ImportLibrary>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<AdditionalDependencies>pdcursesd.lib;pdh.lib;psapi.lib;libfftw3-3.lib;libfftw3f-3.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>pdcursesd.lib;pdh.lib;psapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y $(SolutionDir)src\3rdparty\win32_bin\*.dll $(OutDir)</Command>
|
||||
<Command>
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
@ -109,11 +110,12 @@
|
||||
<ImportLibrary>
|
||||
</ImportLibrary>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<AdditionalDependencies>pdcurses.lib;pdh.lib;psapi.lib;libfftw3-3.lib;libfftw3f-3.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>pdcurses.lib;pdh.lib;psapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ImageHasSafeExceptionHandlers>true</ImageHasSafeExceptionHandlers>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y $(SolutionDir)src\3rdparty\win32_bin\*.dll $(OutDir)</Command>
|
||||
<Command>
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
Loading…
x
Reference in New Issue
Block a user