mirror of
https://github.com/clangen/musikcube.git
synced 2025-03-01 10:13:22 +00:00
- Only use mpg123decoder in *nix -- the Tuniac one doesn't work out of the box
- Added CMake support for oggdecoder - Fleshed out most of the CoreAudioOut implementation -- but it's playing at 2x speed (some sort of buffering issue)
This commit is contained in:
parent
e172c258e4
commit
7ed083a692
@ -24,8 +24,8 @@ add_definitions (-DHAVE_BOOST
|
|||||||
set (BOOST_LINK_LIBS
|
set (BOOST_LINK_LIBS
|
||||||
${Boost_LIBRARIES})
|
${Boost_LIBRARIES})
|
||||||
|
|
||||||
#message(STATUS "Libs: " ${BOOST_LINK_LIBS})
|
#message(STATUS "boost libs: " ${BOOST_LINK_LIBS})
|
||||||
#message(STATUS "Includes: " ${Boost_INCLUDE_DIRS})
|
#message(STATUS "boost includes: " ${Boost_INCLUDE_DIRS})
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}
|
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Modules)
|
${CMAKE_CURRENT_SOURCE_DIR}/Modules)
|
||||||
@ -55,6 +55,6 @@ add_subdirectory(src/3rdparty)
|
|||||||
add_subdirectory(src/core)
|
add_subdirectory(src/core)
|
||||||
add_subdirectory(src/musikbox)
|
add_subdirectory(src/musikbox)
|
||||||
add_subdirectory(src/contrib/taglib_plugin)
|
add_subdirectory(src/contrib/taglib_plugin)
|
||||||
add_subdirectory(src/contrib/mp3decoder)
|
add_subdirectory(src/contrib/oggdecoder)
|
||||||
add_subdirectory(src/contrib/mpg123decoder)
|
add_subdirectory(src/contrib/mpg123decoder)
|
||||||
add_subdirectory(src/contrib/coreaudioout)
|
add_subdirectory(src/contrib/coreaudioout)
|
||||||
|
@ -3,9 +3,15 @@ set (coreaudioout_SOURCES
|
|||||||
CoreAudioOut.cpp
|
CoreAudioOut.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_definitions(
|
IF(APPLE)
|
||||||
-D_DEBUG
|
FIND_LIBRARY(CORE_FOUNDATION_LIBRARY CoreFoundation)
|
||||||
)
|
FIND_LIBRARY(CORE_AUDIO_LIBRARY CoreAudio)
|
||||||
|
FIND_LIBRARY(AUDIO_TOOLBOX_LIBRARY AudioToolbox)
|
||||||
|
MARK_AS_ADVANCED (CORE_FOUNDATION_LIBRARY
|
||||||
|
CORE_AUDIO_LIBRARY
|
||||||
|
AUDIO_TOOLBOX_LIBRARY)
|
||||||
|
SET(FRAMEWORK_LIBS ${CORE_FOUNDATION_LIBRARY} ${CORE_AUDIO_LIBRARY} ${AUDIO_TOOLBOX_LIBRARY})
|
||||||
|
ENDIF (APPLE)
|
||||||
|
|
||||||
add_library(coreaudioout SHARED ${coreaudioout_SOURCES})
|
add_library(coreaudioout SHARED ${coreaudioout_SOURCES})
|
||||||
target_link_libraries(coreaudioout ${musikbox_LINK_LIBS})
|
target_link_libraries(coreaudioout ${musikbox_LINK_LIBS} ${FRAMEWORK_LIBS})
|
||||||
|
@ -1,35 +1,183 @@
|
|||||||
#include "CoreAudioOut.h"
|
#include "CoreAudioOut.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#define BUFFER_COUNT 3
|
||||||
|
|
||||||
using namespace musik::core::audio;
|
using namespace musik::core::audio;
|
||||||
|
|
||||||
|
void audioCallback(void *customData, AudioQueueRef queue, AudioQueueBufferRef buffer)
|
||||||
|
{
|
||||||
|
OSStatus result = AudioQueueFreeBuffer(queue, buffer);
|
||||||
|
|
||||||
|
if (result != 0) {
|
||||||
|
std::cerr << "AudioQueueFreeBuffer failed: " << result << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreAudioOut* output = (CoreAudioOut *) customData;
|
||||||
|
IBuffer* coreBuffer = (IBuffer *) buffer->mUserData;
|
||||||
|
output->NotifyBufferCompleted(coreBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreAudioOut::NotifyBufferCompleted(IBuffer *buffer) {
|
||||||
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||||||
|
--bufferCount;
|
||||||
|
this->bufferProvider->OnBufferProcessed(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
CoreAudioOut::CoreAudioOut() {
|
CoreAudioOut::CoreAudioOut() {
|
||||||
|
this->bufferProvider = NULL;
|
||||||
|
this->quit = false;
|
||||||
|
this->bufferCount = 0;
|
||||||
|
|
||||||
}
|
this->audioFormat = (AudioStreamBasicDescription) { 0 };
|
||||||
|
|
||||||
CoreAudioOut::~CoreAudioOut() {
|
this->audioFormat.mFormatID = kAudioFormatLinearPCM;
|
||||||
|
this->audioFormat.mFormatFlags = kAudioFormatFlagIsFloat;
|
||||||
|
this->audioFormat.mFramesPerPacket = 1;
|
||||||
|
this->audioFormat.mBitsPerChannel = 32;
|
||||||
|
this->audioFormat.mReserved = 0;
|
||||||
|
|
||||||
}
|
/* these get filled in later */
|
||||||
|
this->audioFormat.mChannelsPerFrame = -1;
|
||||||
void CoreAudioOut::Destroy() {
|
this->audioFormat.mSampleRate = -1;
|
||||||
|
this->audioFormat.mBytesPerFrame = -1;
|
||||||
}
|
this->audioFormat.mBytesPerPacket = -1;
|
||||||
|
|
||||||
void CoreAudioOut::Pause() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void CoreAudioOut::Resume() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void CoreAudioOut::SetVolume(double volume) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void CoreAudioOut::Stop() {
|
|
||||||
|
|
||||||
|
this->audioQueue = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CoreAudioOut::Play(IBuffer *buffer, IBufferProvider *provider) {
|
bool CoreAudioOut::Play(IBuffer *buffer, IBufferProvider *provider) {
|
||||||
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||||||
|
|
||||||
|
if (this->bufferCount >= BUFFER_COUNT) {
|
||||||
|
/* enough buffers are already in the queue. bail, we'll notify the
|
||||||
|
caller when there's more data available */
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus result;
|
||||||
|
|
||||||
|
if (buffer->SampleRate() != this->audioFormat.mSampleRate ||
|
||||||
|
buffer->Channels() != this->audioFormat.mChannelsPerFrame ||
|
||||||
|
this->audioQueue == NULL)
|
||||||
|
{
|
||||||
|
this->audioFormat.mSampleRate = buffer->SampleRate();
|
||||||
|
this->audioFormat.mChannelsPerFrame = buffer->Channels();
|
||||||
|
this->audioFormat.mBytesPerFrame = (this->audioFormat.mBitsPerChannel / 8) * this->audioFormat.mChannelsPerFrame;
|
||||||
|
this->audioFormat.mBytesPerPacket = this->audioFormat.mBytesPerFrame * this->audioFormat.mFramesPerPacket;
|
||||||
|
|
||||||
|
this->Stop();
|
||||||
|
|
||||||
|
result = AudioQueueNewOutput(
|
||||||
|
&this->audioFormat,
|
||||||
|
audioCallback,
|
||||||
|
this,
|
||||||
|
NULL,
|
||||||
|
kCFRunLoopCommonModes,
|
||||||
|
0,
|
||||||
|
&this->audioQueue);
|
||||||
|
|
||||||
|
if (result != 0) {
|
||||||
|
std::cerr << "AudioQueueNewOutput failed: " << result << "\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = AudioQueueStart(this->audioQueue, NULL);
|
||||||
|
|
||||||
|
if (result != 0) {
|
||||||
|
std::cerr << "AudioQueueStart failed: " << result << "\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->bufferProvider = provider;
|
||||||
|
|
||||||
|
AudioQueueBufferRef audioQueueBuffer = NULL;
|
||||||
|
|
||||||
|
result = AudioQueueAllocateBuffer(
|
||||||
|
this->audioQueue, buffer->Bytes(), &audioQueueBuffer);
|
||||||
|
|
||||||
|
if (result != 0) {
|
||||||
|
std::cerr << "AudioQueueAllocateBuffer failed: " << result << "\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
audioQueueBuffer->mUserData = (void *) buffer;
|
||||||
|
audioQueueBuffer->mAudioDataByteSize = buffer->Bytes();
|
||||||
|
|
||||||
|
memcpy(
|
||||||
|
audioQueueBuffer->mAudioData,
|
||||||
|
(void *) buffer->BufferPointer(),
|
||||||
|
buffer->Bytes());
|
||||||
|
|
||||||
|
result = AudioQueueEnqueueBuffer(
|
||||||
|
this->audioQueue, audioQueueBuffer, 0, NULL);
|
||||||
|
|
||||||
|
if (result != 0) {
|
||||||
|
std::cerr << "AudioQueueEnqueueBuffer failed: " << result << "\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
++bufferCount;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreAudioOut::~CoreAudioOut() {
|
||||||
|
this->Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreAudioOut::Destroy() {
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreAudioOut::Pause() {
|
||||||
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||||||
|
|
||||||
|
if (this->audioQueue) {
|
||||||
|
AudioQueuePause(this->audioQueue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreAudioOut::Resume() {
|
||||||
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||||||
|
|
||||||
|
if (this->audioQueue) {
|
||||||
|
AudioQueueStart(this->audioQueue, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreAudioOut::SetVolume(double volume) {
|
||||||
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||||||
|
|
||||||
|
if (this->audioQueue) {
|
||||||
|
OSStatus result = AudioQueueSetParameter(
|
||||||
|
this->audioQueue,
|
||||||
|
kAudioQueueParam_Volume,
|
||||||
|
volume);
|
||||||
|
|
||||||
|
if (result != 0) {
|
||||||
|
std::cerr << "AudioQueueSetParameter(volume) failed: " << result << "\n";
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreAudioOut::Stop() {
|
||||||
|
AudioQueueRef queue = NULL;
|
||||||
|
|
||||||
|
{
|
||||||
|
/* AudioQueueStop/AudioQueueDispose will trigger the callback, which
|
||||||
|
will try to dispose of the samples on a separate thread and deadlock.
|
||||||
|
cache the queue and reset outside of the critical section */
|
||||||
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||||||
|
queue = this->audioQueue;
|
||||||
|
this->audioQueue = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queue) {
|
||||||
|
AudioQueueStop(queue, true);
|
||||||
|
AudioQueueDispose(queue, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
#include <core/sdk/IOutput.h>
|
#include <core/sdk/IOutput.h>
|
||||||
#include <core/sdk/IBufferProvider.h>
|
#include <core/sdk/IBufferProvider.h>
|
||||||
|
#include <queue>
|
||||||
|
#include <boost/thread.hpp>
|
||||||
|
#include <boost/thread/condition.hpp>
|
||||||
|
#include <boost/thread/recursive_mutex.hpp>
|
||||||
|
#include <AudioToolbox/AudioQueue.h>
|
||||||
|
#include <CoreAudio/CoreAudioTypes.h>
|
||||||
|
#include <CoreFoundation/CFRunLoop.h>
|
||||||
|
|
||||||
class CoreAudioOut : public musik::core::audio::IOutput {
|
class CoreAudioOut : public musik::core::audio::IOutput {
|
||||||
public:
|
public:
|
||||||
@ -17,4 +24,15 @@ class CoreAudioOut : public musik::core::audio::IOutput {
|
|||||||
virtual bool Play(
|
virtual bool Play(
|
||||||
musik::core::audio::IBuffer *buffer,
|
musik::core::audio::IBuffer *buffer,
|
||||||
musik::core::audio::IBufferProvider *provider);
|
musik::core::audio::IBufferProvider *provider);
|
||||||
|
|
||||||
|
void NotifyBufferCompleted(musik::core::audio::IBuffer *buffer);
|
||||||
|
|
||||||
|
private:
|
||||||
|
musik::core::audio::IBufferProvider *bufferProvider;
|
||||||
|
AudioStreamBasicDescription audioFormat;
|
||||||
|
AudioQueueRef audioQueue;
|
||||||
|
size_t bufferCount;
|
||||||
|
boost::thread thread;
|
||||||
|
boost::recursive_mutex mutex;
|
||||||
|
bool quit;
|
||||||
};
|
};
|
||||||
|
@ -1,26 +1,9 @@
|
|||||||
set ( oggdecoder_SOURCES
|
set (oggdecoder_SOURCES
|
||||||
oggdecoder_plugin.cpp
|
oggdecoder_plugin.cpp
|
||||||
OGGDecoder.cpp
|
OggDecoder.cpp
|
||||||
OggSourceSupplier.cpp
|
OggDecoderFactory.cpp
|
||||||
stdafx.cpp
|
stdafx.cpp
|
||||||
)
|
|
||||||
|
|
||||||
if(CMAKE_SYSTEM_NAME MATCHES "Windows")
|
|
||||||
add_definitions(-DWIN32)
|
|
||||||
if(NOT DEFINED MINGW)
|
|
||||||
|
|
||||||
endif(NOT DEFINED MINGW)
|
|
||||||
else(CMAKE_SYSTEM_NAME MATCHES "Windows")
|
|
||||||
set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -fpermissive)
|
|
||||||
endif(CMAKE_SYSTEM_NAME MATCHES "Windows")
|
|
||||||
|
|
||||||
add_definitions(
|
|
||||||
-DXML_STATIC
|
|
||||||
-D_CRT_SECURE_NO_DEPRECATE
|
|
||||||
-D_DEBUG
|
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library( oggdecoder SHARED ${oggdecoder_SOURCES} )
|
add_library(oggdecoder SHARED ${oggdecoder_SOURCES})
|
||||||
target_link_libraries( oggdecoder ${musikCube_LINK_LIBS})
|
target_link_libraries(oggdecoder ${musikbox_LINK_LIBS} ogg vorbis vorbisfile)
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,9 +40,17 @@
|
|||||||
|
|
||||||
#include "OggDecoderFactory.h"
|
#include "OggDecoderFactory.h"
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#define DLLEXPORT __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define DLLEXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
|
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
class OggDecoderPlugin : public musik::core::IPlugin {
|
class OggDecoderPlugin : public musik::core::IPlugin {
|
||||||
public:
|
public:
|
||||||
@ -52,10 +60,10 @@ public:
|
|||||||
const char* Author() { return "Björn Olievier, _avatar"; };
|
const char* Author() { return "Björn Olievier, _avatar"; };
|
||||||
};
|
};
|
||||||
|
|
||||||
extern "C" __declspec(dllexport) musik::core::IPlugin* GetPlugin() {
|
extern "C" DLLEXPORT musik::core::IPlugin* GetPlugin() {
|
||||||
return new OggDecoderPlugin();
|
return new OggDecoderPlugin();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" __declspec(dllexport) IDecoderFactory* GetDecoderFactory() {
|
extern "C" DLLEXPORT IDecoderFactory* GetDecoderFactory() {
|
||||||
return new OggDecoderFactory();
|
return new OggDecoderFactory();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user