Fixed WaveOut to actually use both channels, instead of just the left one. Also fixed a few bugs related to closing WaveOut.

This commit is contained in:
casey 2016-04-30 14:31:37 -07:00
parent fe1b2827e4
commit a0f7a7670c
16 changed files with 542 additions and 412 deletions

View File

@ -1,233 +0,0 @@
//////////////////////////////////////////////////////////////////////////////
// Copyright © 2007, mC2 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 "StdAfx.h"
#include "OGGDecoder.h"
OGGDecoder::OGGDecoder()
{
// Set the callbacks to handle all file io
this->oggCallbacks.read_func = &OggRead;
this->oggCallbacks.seek_func = &OggSeek;
this->oggCallbacks.tell_func = &OggTell;
this->oggCallbacks.close_func = &OggClose;
}
size_t OGGDecoder::OggRead(void *buffer, size_t nofParts, size_t partSize, void *datasource){
return (size_t)((OGGDecoder*)datasource)->fileStream->Read(buffer,(long)(nofParts*partSize));
}
int OGGDecoder::OggSeek(void *datasource, ogg_int64_t offset, int whence){
switch(whence){
case SEEK_CUR:
{
long currentPosition = ((OGGDecoder*)datasource)->fileStream->Position();
if( ((OGGDecoder*)datasource)->fileStream->SetPosition(currentPosition+(long)offset)){
return 0;
}
}
break;
case SEEK_END:
{
long fileSize = ((OGGDecoder*)datasource)->fileStream->Filesize();
if( ((OGGDecoder*)datasource)->fileStream->SetPosition(fileSize)){
return 0;
}
}
break;
default:
{
if( ((OGGDecoder*)datasource)->fileStream->SetPosition((long)offset)){
return 0;
}
}
}
// Unsuccessfull
return -1;
}
long OGGDecoder::OggTell(void *datasource){
return ((OGGDecoder*)datasource)->fileStream->Position();
}
int OGGDecoder::OggClose(void *datasource){
if( ((OGGDecoder*)datasource)->fileStream->Close() ){
return 0;
}
return -1;
}
OGGDecoder::~OGGDecoder()
{
}
bool OGGDecoder::Open(musik::core::filestreams::IFileStream *fileStream)
{
this->fileStream = fileStream;
if(ov_open_callbacks(this,&this->oggFile,NULL,0,this->oggCallbacks)!=0){
return false;
}
return true;
}
void OGGDecoder::Destroy(void){
ov_clear(&this->oggFile);
delete this;
}
/*
bool OGGDecoder::GetFormat(unsigned long * SampleRate, unsigned long * Channels){
vorbis_info *info = ov_info(&this->oggFile,-1);
if(info){
*SampleRate = info->rate;
*Channels = info->channels;
return true;
}
return false;
}
bool OGGDecoder::GetLength(unsigned long * MS){
double time = ov_time_total(&this->oggFile, 0);
if( time!=OV_EINVAL ){
*MS = (unsigned long)(time * 1000.0);
return true;
}
return false;
}
*/
double OGGDecoder::SetPosition(double second,double totalLength){
if(ov_seekable(&this->oggFile)){
if(!ov_time_seek(&this->oggFile, second)){
return ov_time_tell(&this->oggFile);
}
}
return -1;
}
bool OGGDecoder::GetBuffer(IBuffer *buffer){
vorbis_info *info = ov_info(&this->oggFile, -1);
long nofSamplesMax = 1024*2;
int currentSelection;
buffer->SetChannels(info->channels);
buffer->SetSampleRate(info->rate);
buffer->SetSamples(nofSamplesMax);
float ** pcm;
unsigned long samplesRead = ov_read_float(&this->oggFile, &pcm, nofSamplesMax, &currentSelection);
if(samplesRead == 0) {
return false;
}
buffer->SetSamples(samplesRead);
/* MUSIKCUBE EXPECTS
SPEAKER_FRONT_LEFT 0x1
SPEAKER_FRONT_RIGHT 0x2
SPEAKER_FRONT_CENTER 0x4
SPEAKER_LOW_FREQUENCY 0x8
SPEAKER_BACK_LEFT 0x10
SPEAKER_BACK_RIGHT 0x20
*/
/* OGG DOES
One channel: the stream is monophonic
Two channels: the stream is stereo. channel order: left, right.
Three channels: the stream is a 1d-surround encoding. channel order: left, center, right
Four channels: the stream is quadraphonic surround. channel order: front left, front right, rear left, rear right
Five channels: the stream is five-channel surround. channel order: front left, front center, front right, rear left, rear right
Six channels: (used in Dolby Digital/AC3) the stream is 5,1 surround. channel order: front left, front center, front right, rear left, rear right, LFE (the sixth channel is entirely bass).
*/
// so we need to REORDER
float *pDataBuffer = buffer->BufferPointer();
if(info->channels == 3){
float *pDataBuffer = buffer->BufferPointer();
for(unsigned long x=0; x<samplesRead; ++x){
*pDataBuffer = pcm[0][x];
++pDataBuffer;
*pDataBuffer = pcm[2][x];
++pDataBuffer;
*pDataBuffer = pcm[1][x];
++pDataBuffer;
}
}else if(info->channels == 5){
for(unsigned long x=0; x<samplesRead; ++x){
*pDataBuffer = pcm[0][x];
++pDataBuffer;
*pDataBuffer = pcm[2][x];
++pDataBuffer;
*pDataBuffer = pcm[1][x];
++pDataBuffer;
*pDataBuffer = pcm[3][x];
++pDataBuffer;
*pDataBuffer = pcm[4][x];
++pDataBuffer;
}
}else if(info->channels == 6){
for(unsigned long x=0; x<samplesRead; ++x){
*pDataBuffer = pcm[0][x];
++pDataBuffer;
*pDataBuffer = pcm[2][x];
++pDataBuffer;
*pDataBuffer = pcm[1][x];
++pDataBuffer;
*pDataBuffer = pcm[5][x];
++pDataBuffer;
*pDataBuffer = pcm[3][x];
++pDataBuffer;
*pDataBuffer = pcm[4][x];
++pDataBuffer;
}
}else{
for(unsigned long x=0; x<samplesRead; ++x){
for(int channel(0); channel<info->channels; ++channel){
*pDataBuffer = pcm[channel][x];
++pDataBuffer;
}
}
}
return true;
}

View File

@ -32,47 +32,41 @@
//////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include <cctype>
#include "OggDecoderFactory.h"
#include "VorbisDecoder.h"
#include "OggSourceSupplier.h"
#include "OggDecoder.h"
OggSourceSupplier::OggSourceSupplier()
{
OggDecoderFactory::OggDecoderFactory() {
}
OggSourceSupplier::~OggSourceSupplier()
{
OggDecoderFactory::~OggDecoderFactory() {
}
void OggSourceSupplier::Destroy()
{
void OggDecoderFactory::Destroy() {
delete this;
}
IDecoder* OggSourceSupplier::CreateDecoder()
{
return new OGGDecoder();
IDecoder* OggDecoderFactory::CreateDecoder() {
return new VorbisDecoder();
}
bool OggSourceSupplier::CanHandle(const utfchar* type) const
{
if(type){
bool OggDecoderFactory::CanHandle(const utfchar* type) const {
if (type) {
utfstring typeString(type);
if(typeString.find(UTF("ogg"))!=utfstring::npos){
if (typeString.find(UTF("ogg")) != utfstring::npos) {
return true;
}
if(typeString.find(UTF("oga"))!=utfstring::npos){
if (typeString.find(UTF("oga")) != utfstring::npos) {
return true;
}
if(typeString.find(UTF("audio/ogg"))!=utfstring::npos){
if (typeString.find(UTF("audio/ogg")) != utfstring::npos) {
return true;
}
if(typeString.find(UTF("audio/vorbis"))!=utfstring::npos){
if (typeString.find(UTF("audio/vorbis")) != utfstring::npos) {
return true;
}
}
return false;
}

View File

@ -37,10 +37,10 @@
using namespace musik::core::audio;
class OggSourceSupplier : public IDecoderFactory {
class OggDecoderFactory : public IDecoderFactory {
public:
OggSourceSupplier();
~OggSourceSupplier();
OggDecoderFactory();
~OggDecoderFactory();
IDecoder* CreateDecoder();
void Destroy();

View File

@ -0,0 +1,214 @@
//////////////////////////////////////////////////////////////////////////////
// Copyright © 2007, mC2 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 "StdAfx.h"
#include "VorbisDecoder.h"
VorbisDecoder::VorbisDecoder() {
this->oggCallbacks.read_func = &OggRead;
this->oggCallbacks.seek_func = &OggSeek;
this->oggCallbacks.tell_func = &OggTell;
this->oggCallbacks.close_func = &OggClose;
}
size_t VorbisDecoder::OggRead(void *buffer, size_t nofParts, size_t partSize, void *datasource) {
return (size_t)((VorbisDecoder*)datasource)->fileStream->Read(buffer,(long)(nofParts*partSize));
}
int VorbisDecoder::OggSeek(void *datasource, ogg_int64_t offset, int whence) {
switch(whence) {
case SEEK_CUR:
{
long currentPosition = ((VorbisDecoder*)datasource)->fileStream->Position();
if(((VorbisDecoder*)datasource)->fileStream->SetPosition(currentPosition+(long) offset)) {
return 0;
}
}
break;
case SEEK_END:
{
long fileSize = ((VorbisDecoder*) datasource)->fileStream->Filesize();
if(((VorbisDecoder*) datasource)->fileStream->SetPosition(fileSize)) {
return 0;
}
}
break;
default:
{
if(((VorbisDecoder*) datasource)->fileStream->SetPosition((long) offset)) {
return 0;
}
}
}
return -1;
}
long VorbisDecoder::OggTell(void *datasource) {
return ((VorbisDecoder*)datasource)->fileStream->Position();
}
int VorbisDecoder::OggClose(void *datasource) {
if(((VorbisDecoder*)datasource)->fileStream->Close()) {
return 0;
}
return -1;
}
VorbisDecoder::~VorbisDecoder() {
}
bool VorbisDecoder::Open(musik::core::filestreams::IFileStream *fileStream) {
this->fileStream = fileStream;
if (ov_open_callbacks(this, &this->oggFile, NULL, 0, this->oggCallbacks) != 0) {
return false;
}
return true;
}
void VorbisDecoder::Destroy() {
ov_clear(&this->oggFile);
delete this;
}
double VorbisDecoder::SetPosition(double second, double totalLength) {
if (ov_seekable(&this->oggFile)) {
if (!ov_time_seek(&this->oggFile, second)) {
return ov_time_tell(&this->oggFile);
}
}
return -1;
}
#define OGG_MAX_SAMPLES 1024
bool VorbisDecoder::GetBuffer(IBuffer *buffer) {
int bitstream;
float **pcm;
unsigned long samplesRead = ov_read_float(&this->oggFile, &pcm, OGG_MAX_SAMPLES, &bitstream);
if (samplesRead == 0) {
return false;
}
vorbis_info *info = ov_info(&this->oggFile, -1);
buffer->SetChannels(info->channels);
buffer->SetSampleRate(info->rate);
buffer->SetSamples(samplesRead);
/*
The musik audio engine expects:
SPEAKER_FRONT_LEFT 0x1
SPEAKER_FRONT_RIGHT 0x2
SPEAKER_FRONT_CENTER 0x4
SPEAKER_LOW_FREQUENCY 0x8
SPEAKER_BACK_LEFT 0x10
SPEAKER_BACK_RIGHT 0x20
OGG returns:
One channel: the stream is monophonic
Two channels: the stream is stereo. channel order: left, right.
Three channels: the stream is a 1d-surround encoding. channel order: left, center, right
Four channels: the stream is quadraphonic surround. channel order: front left, front right, rear left, rear right
Five channels: the stream is five-channel surround. channel order: front left, front center, front right, rear left, rear right
Six channels: (used in Dolby Digital/AC3) the stream is 5,1 surround. channel order: front left, front center, front right, rear left, rear right, LFE (the sixth channel is entirely bass).
... so let's re-order when writing to our output buffer ...
*/
float *pDataBuffer = buffer->BufferPointer();
if (info->channels == 2) {
for (unsigned long x = 0; x < samplesRead; ++x) {
pDataBuffer[0] = pcm[0][x];
pDataBuffer[1] = pcm[1][x];
pDataBuffer += 2;
}
}
else if (info->channels == 3) {
for (unsigned long x=0; x < samplesRead; ++x) {
*pDataBuffer = pcm[0][x];
++pDataBuffer;
*pDataBuffer = pcm[2][x];
++pDataBuffer;
*pDataBuffer = pcm[1][x];
++pDataBuffer;
}
}
else if (info->channels == 5) {
for (unsigned long x = 0; x < samplesRead; ++x) {
*pDataBuffer = pcm[0][x];
++pDataBuffer;
*pDataBuffer = pcm[2][x];
++pDataBuffer;
*pDataBuffer = pcm[1][x];
++pDataBuffer;
*pDataBuffer = pcm[3][x];
++pDataBuffer;
*pDataBuffer = pcm[4][x];
++pDataBuffer;
}
}
else if (info->channels == 6) {
for (unsigned long x = 0; x < samplesRead; ++x) {
*pDataBuffer = pcm[0][x];
++pDataBuffer;
*pDataBuffer = pcm[2][x];
++pDataBuffer;
*pDataBuffer = pcm[1][x];
++pDataBuffer;
*pDataBuffer = pcm[5][x];
++pDataBuffer;
*pDataBuffer = pcm[3][x];
++pDataBuffer;
*pDataBuffer = pcm[4][x];
++pDataBuffer;
}
}
else {
for (unsigned long x = 0; x < samplesRead; ++x) {
for (int channel(0); channel < info->channels; ++channel) {
*pDataBuffer = pcm[channel][x];
++pDataBuffer;
}
}
}
return true;
}

View File

@ -39,29 +39,28 @@
using namespace musik::core::audio;
class OGGDecoder : public IDecoder
class VorbisDecoder : public IDecoder
{
public:
OGGDecoder();
~OGGDecoder();
VorbisDecoder();
~VorbisDecoder();
public:
virtual void Destroy();
virtual double SetPosition(double second,double totalLength);
virtual bool GetBuffer(IBuffer *buffer);
virtual bool Open(musik::core::filestreams::IFileStream *fileStream);
virtual void Destroy();
virtual double SetPosition(double second, double totalLength);
virtual bool GetBuffer(IBuffer *buffer);
virtual bool Open(musik::core::filestreams::IFileStream *fileStream);
public:
// OGG callbacks
static size_t OggRead(void *buffer, size_t nofParts, size_t partSize, void *datasource);
static int OggSeek(void *datasource, ogg_int64_t offset, int whence);
static long OggTell(void *datasource);
static int OggClose(void *datasource);
/* libvorbis callbacks */
static size_t OggRead(void *buffer, size_t nofParts, size_t partSize, void *datasource);
static int OggSeek(void *datasource, ogg_int64_t offset, int whence);
static long OggTell(void *datasource);
static int OggClose(void *datasource);
protected:
musik::core::filestreams::IFileStream *fileStream;
OggVorbis_File oggFile;
ov_callbacks oggCallbacks;
OggVorbis_File oggFile;
ov_callbacks oggCallbacks;
};

View File

@ -93,14 +93,14 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="OGGDecoder.cpp" />
<ClCompile Include="VorbisDecoder.cpp" />
<ClCompile Include="oggdecoder_plugin.cpp" />
<ClCompile Include="OggSourceSupplier.cpp" />
<ClCompile Include="OggDecoderFactory.cpp" />
<ClCompile Include="stdafx.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="OGGDecoder.h" />
<ClInclude Include="OggSourceSupplier.h" />
<ClInclude Include="VorbisDecoder.h" />
<ClInclude Include="OggDecoderFactory.h" />
<ClInclude Include="stdafx.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@ -38,7 +38,7 @@
#include <core/sdk/IPlugin.h>
#include "OggSourceSupplier.h"
#include "OggDecoderFactory.h"
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
return true;
@ -57,5 +57,5 @@ extern "C" __declspec(dllexport) musik::core::IPlugin* GetPlugin() {
}
extern "C" __declspec(dllexport) IDecoderFactory* GetDecoderFactory() {
return new OggSourceSupplier();
return new OggDecoderFactory();
}

View File

@ -33,7 +33,7 @@
#include "WaveOut.h"
#define MAX_VOLUME 65535.0
#define MAX_VOLUME 0xFFFF
WaveOut::WaveOut()
: waveHandle(NULL)
@ -51,7 +51,7 @@ WaveOut::~WaveOut(){
}
}
void WaveOut::Destroy(){
void WaveOut::Destroy() {
delete this;
}
@ -66,7 +66,8 @@ void WaveOut::Resume() {
void WaveOut::SetVolume(double volume) {
if (this->waveHandle) {
DWORD newVolume = (DWORD)(volume * MAX_VOLUME);
waveOutSetVolume(this->waveHandle,newVolume);
DWORD leftAndRight = (newVolume << 16) | newVolume;
waveOutSetVolume(this->waveHandle, leftAndRight);
}
this->currentVolume = volume;
@ -148,7 +149,7 @@ void WaveOut::SetFormat(IBuffer *buffer) {
this->currentSampleRate = buffer->SampleRate();
/* format changed, kill the old output device */
if(this->waveHandle!=NULL) {
if (this->waveHandle != NULL) {
waveOutClose(this->waveHandle);
this->waveHandle = NULL;
}
@ -156,44 +157,41 @@ void WaveOut::SetFormat(IBuffer *buffer) {
/* reset, and configure speaker output */
ZeroMemory(&this->waveFormat, sizeof(this->waveFormat));
DWORD speakerconfig = 0;
DWORD speakerConfig = 0;
switch (buffer->Channels()) {
case 1:
speakerconfig = KSAUDIO_SPEAKER_MONO;
speakerConfig = KSAUDIO_SPEAKER_MONO;
break;
case 2:
speakerconfig = KSAUDIO_SPEAKER_STEREO;
speakerConfig = KSAUDIO_SPEAKER_STEREO;
break;
case 4:
speakerconfig = KSAUDIO_SPEAKER_QUAD;
speakerConfig = KSAUDIO_SPEAKER_QUAD;
break;
case 5:
speakerconfig = (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT);
speakerConfig = (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT);
break;
case 6:
speakerconfig = KSAUDIO_SPEAKER_5POINT1;
speakerConfig = KSAUDIO_SPEAKER_5POINT1;
break;
}
this->waveFormat.Format.cbSize = 22;
this->waveFormat.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
this->waveFormat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
this->waveFormat.Format.nChannels = (WORD) buffer->Channels();
this->waveFormat.Format.wBitsPerSample = sizeof(float) * 8;
this->waveFormat.Format.nSamplesPerSec = (DWORD) buffer->SampleRate();
this->waveFormat.Format.wBitsPerSample = 32;
this->waveFormat.Format.nBlockAlign =
(this->waveFormat.Format.wBitsPerSample / 8) * this->waveFormat.Format.nChannels;
int bytesPerSample = this->waveFormat.Format.wBitsPerSample / 8;
this->waveFormat.Format.nBlockAlign = bytesPerSample * this->waveFormat.Format.nChannels;
this->waveFormat.Format.nAvgBytesPerSec =
((this->waveFormat.Format.wBitsPerSample/8) *
this->waveFormat.Format.nChannels) *
this->waveFormat.Format.nSamplesPerSec; /* Compute using nBlkAlign * nSamp/Sec */
this->waveFormat.Format.nBlockAlign * this->waveFormat.Format.nSamplesPerSec;
/* IMPORTANT NOTE: wValidBitsPerSample/wReserved/wSamplesPerBlock are a union,
so don't set wReserved or wSamplesPerBlock to 0 after assigning wValidBitsPerSample. */
this->waveFormat.Samples.wValidBitsPerSample = 32;
this->waveFormat.dwChannelMask = speakerconfig;
/* NOTE: wValidBitsPerSample/wReserved/wSamplesPerBlock are a union */
this->waveFormat.Samples.wValidBitsPerSample = this->waveFormat.Format.wBitsPerSample;
this->waveFormat.dwChannelMask = speakerConfig;
this->waveFormat.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
/* create the output device */

View File

@ -34,6 +34,8 @@
#include "WaveOutBuffer.h"
#include "WaveOut.h"
#include <iostream>
WaveOutBuffer::WaveOutBuffer(WaveOut *waveOut, IBuffer *buffer, IPlayer *player)
: waveOut(waveOut)
, buffer(buffer)
@ -44,9 +46,9 @@ WaveOutBuffer::WaveOutBuffer(WaveOut *waveOut, IBuffer *buffer, IPlayer *player)
}
void WaveOutBuffer::Initialize() {
this->header.dwBufferLength = this->buffer->Samples() * this->buffer->Channels()*sizeof(float);
this->header.lpData = (LPSTR)this->buffer->BufferPointer();
this->header.dwUser = (DWORD_PTR)this;
this->header.dwBufferLength = this->buffer->Samples() * this->buffer->Channels() * sizeof(float);
this->header.lpData = (LPSTR) this->buffer->BufferPointer();
this->header.dwUser = (DWORD_PTR) this;
this->header.dwBytesRecorded = 0;
this->header.dwFlags = 0;
this->header.dwLoops = 0;
@ -57,14 +59,13 @@ void WaveOutBuffer::Initialize() {
if (result != MMSYSERR_NOERROR) {
throw;
}
this->header.dwFlags |= WHDR_DONE;
}
void WaveOutBuffer::Destroy() {
if (!this->destroyed) {
if (this->waveOut->waveHandle && this->header.dwFlags & WHDR_PREPARED) {
waveOutUnprepareHeader(this->waveOut->waveHandle, &this->header, sizeof(WAVEHDR));
this->header.dwFlags = WHDR_DONE;
}
this->player->Notify();

View File

@ -186,7 +186,9 @@ void Player::ThreadLoop() {
}
}
/* TODO: why do we release buffers from the output here?? */
/* TODO: why do we release buffers from the output here?? this appears to be
an old hack to fix up some WaveOut issues where pending buffers need to be
released before the device can be closed. we can probably remove this now. */
this->output->ReleaseBuffers();
BufferPtr buffer;
@ -207,6 +209,8 @@ void Player::ThreadLoop() {
}
}
/* TODO CLEAN UP AND DOCUMENT */
/* if we have a buffer available, let's try to send it to the output device */
if (buffer) {
{
@ -232,7 +236,7 @@ void Player::ThreadLoop() {
}
}
}
else{
else {
// Buffer send to output
boost::mutex::scoped_lock lock(this->mutex);
if(!this->bufferQueue.empty()) {
@ -246,6 +250,8 @@ void Player::ThreadLoop() {
}
}
/* END TODO CLEAN UP AND DOCUMENT */
/* if we're unable to obtain a buffer, it means we're out of data and the
player is finished. terminate the thread. */
else {

View File

@ -38,6 +38,7 @@
#include <core/PluginFactory.h>
using namespace musik::core::audio;
using musik::core::PluginFactory;
Stream::Stream(unsigned int options)
:preferedBufferSampleSize(4096)
@ -45,12 +46,9 @@ Stream::Stream(unsigned int options)
,decoderSampleRate(0)
,decoderSamplePosition(0)
{
// Get all DSPs
// TODO: fixing PluginFactory
if( (this->options&NoDSP)==0){
this->dsps = musik::core::PluginFactory::Instance().QueryInterface<
IDSP,
musik::core::PluginFactory::DestroyDeleter<IDSP> >("GetDSP");
if((this->options&NoDSP) == 0){
typedef PluginFactory::DestroyDeleter<IDSP> Deleter;
this->dsps = PluginFactory::Instance().QueryInterface<IDSP, Deleter>("GetDSP");
}
}
@ -62,9 +60,7 @@ StreamPtr Stream::Create(unsigned int options){
return StreamPtr(new Stream(options));
}
BufferPtr Stream::NextBuffer(){
// Decode a new buffer
BufferPtr Stream::NextBuffer() {
return this->GetNextBuffer();
}
@ -82,110 +78,104 @@ double Stream::SetPosition(double seconds){
}
return newPosition;
}
/*
void Stream::SetMaxCacheLength(double seconds){
}
void Stream::SetPreferedBufferSampleSize(long samples){
}
*/
bool Stream::OpenStream(utfstring uri){
// Open the filestream
this->fileStream = musik::core::filestreams::Factory::OpenFile(uri.c_str());
if(!this->fileStream){
bool Stream::OpenStream(utfstring uri) {
/* use our file stream abstraction to open the data at the
specified URI */
this->fileStream = musik::core::filestreams::Factory::OpenFile(uri.c_str());
if (!this->fileStream) {
return false;
}
// Look up what DecoderFactory to use
/* find a DecoderFactory we can use for this type of data*/
StreamHelper::DecoderFactoryPtr decoderFactory;
for(StreamHelper::DecoderFactories::iterator decoderFactoryIt=Stream::Helper()->decoderFactories.begin();decoderFactoryIt!=Stream::Helper()->decoderFactories.end() && !decoderFactory;++decoderFactoryIt){
if( (*decoderFactoryIt)->CanHandle(this->fileStream->Type())){
decoderFactory = (*decoderFactoryIt);
StreamHelper::DecoderFactories::iterator factories = Stream::Helper()->decoderFactories.begin();
StreamHelper::DecoderFactories::iterator end = Stream::Helper()->decoderFactories.end();
for( ; factories != end && !decoderFactory; ++factories) {
if((*factories)->CanHandle(this->fileStream->Type())){
decoderFactory = (*factories);
}
}
if(!decoderFactory){
// We have failed to get a working decoderFactory
if (!decoderFactory) {
/* nothing can decode this type of file */
return false;
}
// Create the decoder
IDecoder *decoderPtr = decoderFactory->CreateDecoder();
if(!decoderPtr){
IDecoder *decoder = decoderFactory->CreateDecoder();
if (!decoder) {
/* shouldn't ever happen, the factory said it can handle this file */
return false;
}
typedef PluginFactory::DestroyDeleter<IDecoder> Deleter;
// Open the decoder
typedef musik::core::PluginFactory::DestroyDeleter<IDecoder> IDecoderDeleter;
this->decoder.reset(decoderPtr,IDecoderDeleter());
if( !this->decoder->Open(this->fileStream.get()) ){
/* ask the decoder to open the data stream. if it returns true we're
good to start pulling data out of it! */
this->decoder.reset(decoder, Deleter());
if (!this->decoder->Open(this->fileStream.get())) {
return false;
}
return true;
}
BufferPtr Stream::GetNextDecoderBuffer(){
// First get a buffer
BufferPtr Stream::GetNextDecoderBuffer() {
/* get a spare buffer, then ask the decoder for some data */
BufferPtr buffer = this->NewBuffer();
// Get the buffer from the decoder
if(!this->decoder->GetBuffer(buffer.get())){
// Nothing to decode left, return a empty buffer
if(!this->decoder->GetBuffer(buffer.get())) {
return BufferPtr();
}
// We need to save the decoders samplerate to be able to calculate the current time-position
/* remember the samplerate so we can calculate the current time-position */
if(!this->decoderSampleRate){
this->decoderSampleRate = buffer->SampleRate();
}
// Calculate the current sample position
/* calculate the current offset, in samples */
this->decoderSamplePosition += buffer->Samples();
// Save the position (seconds) in the buffer
buffer->position = ((double)this->decoderSamplePosition)/((double)this->decoderSampleRate);
/* calculate the position (seconds) in the buffer */
buffer->position = ((double)this->decoderSamplePosition) / ((double)this->decoderSampleRate);
return buffer;
}
BufferPtr Stream::GetNextBuffer(){
// First get the next decoded buffer
BufferPtr Stream::GetNextBuffer() {
/* ask the decoder for the next buffer */
BufferPtr currentBuffer = this->GetNextDecoderBuffer();
if(currentBuffer){
/////////////////////////////////////////////
// Lets check if the buffer is too small
bool moreBuffers(true);
while(currentBuffer->Samples()<this->preferedBufferSampleSize && moreBuffers){
BufferPtr appendBuffer = this->GetNextDecoderBuffer();
if(appendBuffer){
currentBuffer->Append(appendBuffer);
this->DeleteBuffer(appendBuffer);
}else{
if(currentBuffer) {
/* try to fill the buffer to its optimal size; if the decoder didn't return
a full buffer, ask it for some more data. */
bool moreBuffers = true;
while (currentBuffer->Samples() < this->preferedBufferSampleSize && moreBuffers) {
BufferPtr bufferToAppend = this->GetNextDecoderBuffer();
if (bufferToAppend) {
currentBuffer->Append(bufferToAppend);
this->DeleteBuffer(bufferToAppend);
}
else {
moreBuffers = false;
}
}
/////////////////////////////////////////////
BufferPtr oldBuffer = this->NewBuffer();
/* let DSP plugins process the buffer */
if (this->dsps.size() > 0) {
BufferPtr oldBuffer = this->NewBuffer();
// Now lets loop through all DSP plugins
for(Dsps::iterator dsp=this->dsps.begin();dsp!=this->dsps.end();++dsp){
oldBuffer->CopyFormat(currentBuffer);
oldBuffer->position = currentBuffer->position;
for (Dsps::iterator dsp = this->dsps.begin(); dsp != this->dsps.end(); ++dsp) {
oldBuffer->CopyFormat(currentBuffer);
oldBuffer->position = currentBuffer->position;
if( (*dsp)->ProcessBuffers(currentBuffer.get(),oldBuffer.get()) ){
// Success in processing DSP, swap the buffers
currentBuffer.swap(oldBuffer);
if ((*dsp)->ProcessBuffers(currentBuffer.get(), oldBuffer.get())) {
currentBuffer.swap(oldBuffer);
}
}
}
this->DeleteBuffer(oldBuffer);
this->DeleteBuffer(oldBuffer);
}
}
@ -203,7 +193,7 @@ BufferPtr Stream::NewBuffer(){
return buffer;
}
void Stream::DeleteBuffer(BufferPtr oldBuffer){
void Stream::DeleteBuffer(BufferPtr oldBuffer) {
this->availableBuffers.push_back(oldBuffer);
}
@ -215,20 +205,22 @@ Stream::StreamHelperPtr Stream::Helper(){
return helper;
}
Stream::StreamHelper::StreamHelper(){
// Look up all DecoderFactories
this->decoderFactories = musik::core::PluginFactory::Instance().QueryInterface<
IDecoderFactory,
musik::core::PluginFactory::DestroyDeleter<IDecoderFactory> >("GetDecoderFactory");
Stream::StreamHelper::StreamHelper() {
PluginFactory::DestroyDeleter<IDecoderFactory> typedef Deleter;
this->decoderFactories = PluginFactory::Instance()
.QueryInterface<IDecoderFactory, Deleter>("GetDecoderFactory");
}
double Stream::DecoderProgress(){
if(this->fileStream){
long fileSize = this->fileStream->Filesize();
long filePosition = this->fileStream->Position();
if(fileSize && filePosition){
return ((double)filePosition)/((double)fileSize);
double Stream::DecoderProgress() {
if (this->fileStream) {
long fileSize = this->fileStream->Filesize();
long filePosition = this->fileStream->Position();
if (fileSize && filePosition) {
return ((double) filePosition) / ((double) fileSize);
}
}
return 0;
}

View File

@ -41,8 +41,6 @@
#include <core/Common.h>
#include <core/config_filesystem.h>
//////////////////////////////////////////////////////////////////////////////
#ifdef UTF_WIDECHAR
#define UTFFopen _wfopen
typedef fpos_t stdioPositionType;
@ -51,11 +49,8 @@ typedef fpos_t stdioPositionType;
typedef fpos_t stdioPositionType;
#endif
//////////////////////////////////////////////////////////////////////////////
using namespace musik::core::filestreams;
//////////////////////////////////////////////////////////////////////////////
LocalFileStream::LocalFileStream()
: file(NULL)
, filesize(-1)
@ -82,10 +77,10 @@ bool LocalFileStream::Open(const utfchar *filename,unsigned int options){
std::cerr << "File not a regular file" << std::endl;
}
this->filesize = (long)boost::filesystem::file_size(file);
this->filesize = (long)boost::filesystem::file_size(file);
this->extension = file.extension().wstring();
this->file = UTFFopen(filename,UTF("rb"));
this->fd = new boost::iostreams::file_descriptor(file);
this->fd = new boost::iostreams::file_descriptor(file);
this->fileStream = new boost::iostreams::stream<boost::iostreams::file_descriptor>(*this->fd);
this->fileStream->exceptions(std::ios_base::eofbit | std::ios_base::failbit | std::ios_base::badbit);
@ -128,8 +123,6 @@ PositionType LocalFileStream::Read(void* buffer,PositionType readBytes) {
}
bool LocalFileStream::SetPosition(PositionType position) {
/*stdioPositionType newPosition = (stdioPositionType)position;
return fsetpos(this->file,&newPosition)==0;*/
try {
this->fileStream->clear();
this->fileStream->seekg(position);
@ -142,16 +135,10 @@ bool LocalFileStream::SetPosition(PositionType position) {
}
PositionType LocalFileStream::Position() {
/*stdioPositionType currentPosition(0);
if(fgetpos(this->file,&currentPosition)==0){
return (PositionType)currentPosition;
}
return -1;*/
return this->fileStream->tellg();
}
bool LocalFileStream::Eof() {
//return feof(this->file)!=0;
return this->fileStream->eof();
}

View File

@ -37,17 +37,12 @@
#pragma once
namespace musik { namespace core {
class IPlugin{
protected:
virtual ~IPlugin() {};
class IPlugin{
public:
virtual void Destroy() =0;
virtual const utfchar* Name()=0;
virtual const utfchar* Version()=0;
virtual const utfchar* Author()=0;
virtual void Destroy() = 0;
virtual const utfchar* Name() = 0;
virtual const utfchar* Version() = 0;
virtual const utfchar* Author() = 0;
};
} }

View File

@ -0,0 +1,58 @@
//////////////////////////////////////////////////////////////////////////////
//
// License Agreement:
//
// The following are Copyright © 2008, Daniel Önnerby
//
// 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>
//////////////////////////////////////////////////////////////////////////////
namespace musik{ namespace core{ namespace http{
//////////////////////////////////////////////////////////////////////////////
class IRequestParser{
public:
virtual const char* Attribute(const char* key)=0;
virtual const char* Path()=0;
virtual const char* SubPath(int position)=0;
};
//////////////////////////////////////////////////////////////////////////////
} } } // musik::core:http
//////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,61 @@
//////////////////////////////////////////////////////////////////////////////
//
// License Agreement:
//
// The following are Copyright © 2008, Daniel Önnerby
//
// 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 "IResponder.h"
#include "IRequestParser.h"
#include "ITrack.h"
//////////////////////////////////////////////////////////////////////////////
namespace musik{ namespace core{ namespace http{
//////////////////////////////////////////////////////////////////////////////
class IRequestPlugin{
public:
virtual void Destroy()=0;
virtual const char* WatchPath()=0;
virtual void Execute(musik::core::http::IResponder* responder,musik::core::http::IRequestParser* request,musik::core::ITrack* track)=0;
};
//////////////////////////////////////////////////////////////////////////////
} } }
//////////////////////////////////////////////////////////////////////////////

58
src/core/sdk/IResponder.h Normal file
View File

@ -0,0 +1,58 @@
//////////////////////////////////////////////////////////////////////////////
//
// License Agreement:
//
// The following are Copyright © 2008, Daniel Önnerby
//
// 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 <stddef.h>
//////////////////////////////////////////////////////////////////////////////
namespace musik{ namespace core{ namespace http{
//////////////////////////////////////////////////////////////////////////////
class IResponder{
public:
virtual void SendContent(const char* buffer,const std::size_t bufferSize)=0;
virtual bool Exited()=0;
};
//////////////////////////////////////////////////////////////////////////////
} } }
//////////////////////////////////////////////////////////////////////////////