From 68c87d72dd28b523a09f661264837f4aa3e7025d Mon Sep 17 00:00:00 2001 From: trialuser02 Date: Fri, 14 Feb 2014 11:34:05 +0000 Subject: added directsound plugin git-svn-id: http://svn.code.sf.net/p/qmmp-dev/code/trunk/qmmp@4089 90c681e8-e032-0410-971d-27865f9a5e38 --- src/plugins/Output/Output.pro | 1 + src/plugins/Output/directsound/directsound.pro | 46 ++++ .../Output/directsound/outputdirectsound.cpp | 264 +++++++++++++++++++++ src/plugins/Output/directsound/outputdirectsound.h | 73 ++++++ .../directsound/outputdirectsoundfactory.cpp | 66 ++++++ .../Output/directsound/outputdirectsoundfactory.h | 45 ++++ 6 files changed, 495 insertions(+) create mode 100644 src/plugins/Output/directsound/directsound.pro create mode 100644 src/plugins/Output/directsound/outputdirectsound.cpp create mode 100644 src/plugins/Output/directsound/outputdirectsound.h create mode 100644 src/plugins/Output/directsound/outputdirectsoundfactory.cpp create mode 100644 src/plugins/Output/directsound/outputdirectsoundfactory.h (limited to 'src') diff --git a/src/plugins/Output/Output.pro b/src/plugins/Output/Output.pro index c17adbeac..d07513257 100644 --- a/src/plugins/Output/Output.pro +++ b/src/plugins/Output/Output.pro @@ -2,6 +2,7 @@ include(../../../qmmp.pri) TEMPLATE = subdirs win32:SUBDIRS += waveout +win32:SUBDIRS += directsound SUBDIRS += null diff --git a/src/plugins/Output/directsound/directsound.pro b/src/plugins/Output/directsound/directsound.pro new file mode 100644 index 000000000..71ea2bfbc --- /dev/null +++ b/src/plugins/Output/directsound/directsound.pro @@ -0,0 +1,46 @@ +include(../../plugins.pri) + +HEADERS += outputdirectsoundfactory.h \ + outputdirectsound.h + +SOURCES += outputdirectsoundfactory.cpp \ + outputdirectsound.cpp + +HEADERS += ../../../../src/qmmp/output.h + + +TARGET=$$PLUGINS_PREFIX/Output/directsound + +INCLUDEPATH += ../../../ +QMAKE_LIBDIR += ../../../../bin + +CONFIG += warn_on \ +thread \ +plugin + +TEMPLATE = lib +LIBS += -lqmmp0 -ldxguid -lstrmiids -ldmoguids -lmsdmo -lole32 -loleaut32 -luuid -lgdi32 -ldsound + +TRANSLATIONS = translations/directsound_plugin_cs.ts \ + translations/directsound_plugin_de.ts \ + translations/directsound_plugin_zh_CN.ts \ + translations/directsound_plugin_zh_TW.ts \ + translations/directsound_plugin_ru.ts \ + translations/directsound_plugin_pl.ts \ + translations/directsound_plugin_uk_UA.ts \ + translations/directsound_plugin_it.ts \ + translations/directsound_plugin_tr.ts \ + translations/directsound_plugin_lt.ts \ + translations/directsound_plugin_nl.ts \ + translations/directsound_plugin_ja.ts \ + translations/directsound_plugin_es.ts \ + translations/directsound_plugin_sr_BA.ts \ + translations/directsound_plugin_sr_RS.ts +#RESOURCES = translations/translations.qrc + +isEmpty (LIB_DIR){ +LIB_DIR = /lib +} + +target.path = $$LIB_DIR/qmmp/Output +INSTALLS += target diff --git a/src/plugins/Output/directsound/outputdirectsound.cpp b/src/plugins/Output/directsound/outputdirectsound.cpp new file mode 100644 index 000000000..feaa2cf08 --- /dev/null +++ b/src/plugins/Output/directsound/outputdirectsound.cpp @@ -0,0 +1,264 @@ +/*************************************************************************** + * Copyright (C) 2014 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "outputdirectsound.h" + +#define DS_BUFSIZE (48*1024) + +OutputDirectSound::OutputDirectSound() : Output() +{ + m_ds = 0; + m_primaryBuffer = 0; + m_dsBuffer = 0; + m_dsBufferAt = 0; +} + +OutputDirectSound::~OutputDirectSound() +{ + uninitialize(); +} + +bool OutputDirectSound::initialize(quint32 freq, int chan, Qmmp::AudioFormat format) +{ + Q_UNUSED(format); + DSBUFFERDESC bufferDesc; + + HRESULT result = DirectSoundCreate8(0, &m_ds, 0); + if(result != DS_OK) + { + qWarning("OutputDirectSound: DirectSoundCreate8 failed, error code = 0x%lx", result); + m_ds = 0; + return false; + } + + if((result = m_ds->SetCooperativeLevel(GetDesktopWindow(), DSSCL_PRIORITY)) != DS_OK) + { + qWarning("OutputDirectSound: SetCooperativeLevel failed, error code = 0x%lx", result); + return false; + } + + ZeroMemory(&bufferDesc, sizeof(DSBUFFERDESC)); + bufferDesc.dwSize = sizeof(DSBUFFERDESC); + bufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME; + bufferDesc.dwBufferBytes = 0; + bufferDesc.lpwfxFormat = NULL; + + if((result = m_ds->CreateSoundBuffer(&bufferDesc, &m_primaryBuffer, NULL)) != DS_OK) + { + m_primaryBuffer = 0; + qWarning("OutputDirectSound: CreateSoundBuffer failed, error code = 0x%lx", result); + return false; + } + + WAVEFORMATEX wfex; + ZeroMemory(&wfex, sizeof(WAVEFORMATEX)); + wfex.wFormatTag = WAVE_FORMAT_PCM; + wfex.nChannels = chan; + wfex.nSamplesPerSec = freq; + wfex.wBitsPerSample = 16; + wfex.nBlockAlign = (wfex.wBitsPerSample / 8) * wfex.nChannels; + wfex.nAvgBytesPerSec = wfex.nSamplesPerSec * wfex.nBlockAlign; + + if((result = m_primaryBuffer->SetFormat(&wfex)) != DS_OK) + { + qWarning("OutputDirectSound: SetFormat failed, error code = 0x%lx", result); + return false; + } + + if((result = m_primaryBuffer->Play(0, 0, DSBPLAY_LOOPING)) != DS_OK) + { + qWarning("OutputDirectSound: Play failed, error code = 0x%lx", result); + return false; + } + + ZeroMemory(&wfex, sizeof(WAVEFORMATEX)); + wfex.wFormatTag = WAVE_FORMAT_PCM; + wfex.nChannels = chan; + wfex.nSamplesPerSec = freq; + wfex.wBitsPerSample = 16; + wfex.nBlockAlign = (wfex.wBitsPerSample / 8) * wfex.nChannels; + wfex.nAvgBytesPerSec = wfex.nSamplesPerSec * wfex.nBlockAlign; + + ZeroMemory(&bufferDesc, sizeof(DSBUFFERDESC)); + bufferDesc.dwSize = sizeof(DSBUFFERDESC); + bufferDesc.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPAN | + DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY; + bufferDesc.lpwfxFormat = &wfex; + bufferDesc.dwBufferBytes = DS_BUFSIZE; // buffer size + + IDirectSoundBuffer *pDSB; + if((result = m_ds->CreateSoundBuffer(&bufferDesc, &pDSB, NULL)) != DS_OK) + { + qWarning("OutputDirectSound: CreateSoundBuffer failed, error code = 0x%lx", result); + return false; + } + + if((result = pDSB->QueryInterface(IID_IDirectSoundBuffer8, (void**)&m_dsBuffer)) != DS_OK) + { + m_dsBuffer = 0; + qWarning("OutputDirectSound: QueryInterface failed, error code = 0x%lx", result); + pDSB->Release(); + return false; + } + + m_dsBuffer->SetCurrentPosition(0); + m_dsBuffer->Play(0,0,DSBPLAY_LOOPING); + m_dsBufferAt = 0; + configure(freq, chan, Qmmp::PCM_S16LE); + return true; +} + + +qint64 OutputDirectSound::latency() +{ + return 0; +} + +qint64 OutputDirectSound::writeAudio(unsigned char *data, qint64 len) +{ + unsigned char *ptr = 0, *ptr2 = 0; + DWORD size = 0, size2 = 0; + + DWORD available = bytesToWrite(); //available bytes + if(available < 128) + { + usleep(5000); + return 0; + } + DWORD lockSize = qMin((DWORD)len, available); //required size + + HRESULT result = m_dsBuffer->Lock(m_dsBufferAt, lockSize, + (void**)&ptr, (DWORD*)&size, + (void**)&ptr2, (DWORD*)&size2, 0); + if(result == DSERR_BUFFERLOST) + { + m_dsBuffer->Restore(); + result = m_dsBuffer->Lock(m_dsBufferAt, lockSize, + (void**)&ptr, (DWORD*)&size, + (void**)&ptr2, (DWORD*)&size2, 0); + } + if(result != DS_OK) + { + qWarning("OutputDirectSound: unable to lock buffer, error = 0x%lx", result); + return -1; + } + + DWORD totalSize = size + size2; //total locked size + memmove(ptr, data, size); + if(size2 > 0) + memmove(ptr2, data + size, size2); + + m_dsBuffer->Unlock((void*)ptr, size, (void*)ptr2, size2); + + m_dsBufferAt += totalSize; + m_dsBufferAt %= DS_BUFSIZE; + return totalSize; +} + +void OutputDirectSound::drain() +{ + DWORD dsCurrentPlayCursor = 0; + m_dsBuffer->GetCurrentPosition((DWORD*)&dsCurrentPlayCursor, 0); + + while(dsCurrentPlayCursor >= m_dsBufferAt) + { + m_dsBuffer->GetCurrentPosition((DWORD*)&dsCurrentPlayCursor, 0); + } + while (dsCurrentPlayCursor <= m_dsBufferAt) + { + m_dsBuffer->GetCurrentPosition((DWORD*)&dsCurrentPlayCursor, 0); + } +} + +void OutputDirectSound::suspend() +{ + m_dsBuffer->Stop(); +} + +void OutputDirectSound::resume() +{ + HRESULT result = m_dsBuffer->Play(0,0,DSBPLAY_LOOPING); + if(result == DSERR_BUFFERLOST) + { + result = m_dsBuffer->Play(0,0,DSBPLAY_LOOPING); + m_dsBuffer->Restore(); + } +} + +void OutputDirectSound::reset() +{ + m_dsBuffer->SetCurrentPosition(m_dsBufferAt-128); +} + +void OutputDirectSound::uninitialize() +{ + m_dsBufferAt = 0; + if(m_dsBuffer) + { + m_dsBuffer->Stop(); + m_dsBuffer->Release(); + m_dsBuffer = 0; + } + if(m_primaryBuffer) + { + m_primaryBuffer->Stop(); + m_primaryBuffer->Release(); + m_primaryBuffer = 0; + } + if(m_ds) + { + m_ds->Release(); + m_ds = 0; + } +} + +DWORD OutputDirectSound::bytesToWrite() +{ + DWORD dsCurrentPlayCursor = 0; + m_dsBuffer->GetCurrentPosition((DWORD*)&dsCurrentPlayCursor, 0); + long available = dsCurrentPlayCursor - m_dsBufferAt; //available bytes + + if(available < 0) + { + available += DS_BUFSIZE; + } + return available; +} + +/***** MIXER *****/ +VolumeDirectSound::VolumeDirectSound() +{} + +VolumeDirectSound::~VolumeDirectSound() +{} + +void VolumeDirectSound::setVolume(const VolumeSettings &vol) +{ +} + +VolumeSettings VolumeDirectSound::volume() const +{ +} diff --git a/src/plugins/Output/directsound/outputdirectsound.h b/src/plugins/Output/directsound/outputdirectsound.h new file mode 100644 index 000000000..c78d88fb4 --- /dev/null +++ b/src/plugins/Output/directsound/outputdirectsound.h @@ -0,0 +1,73 @@ +/*************************************************************************** + * Copyright (C) 2014 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef OUTPUTDIRECTSOUND_H +#define OUTPUTDIRECTSOUND_H + +#include +#include +#include +#include +#include +#include + +/** + @author Ilya Kotov +*/ +class OutputDirectSound : public Output +{ +public: + OutputDirectSound(); + ~OutputDirectSound(); + + bool initialize(quint32, int, Qmmp::AudioFormat format); + + //output api + qint64 latency(); + qint64 writeAudio(unsigned char *data, qint64 size); + void drain(); + void suspend(); + void resume(); + void reset(); + +private: + // helper functions + void status(); + void uninitialize(); + DWORD bytesToWrite(); + + IDirectSound8 *m_ds; + IDirectSoundBuffer *m_primaryBuffer; + IDirectSoundBuffer8 *m_dsBuffer; + DWORD m_dsBufferAt; +}; + +class VolumeDirectSound : public Volume +{ +public: + VolumeDirectSound(); + ~VolumeDirectSound(); + + void setVolume(const VolumeSettings &vol); + VolumeSettings volume() const; +}; + + +#endif // OUTPUTDIRECTSOUND_H diff --git a/src/plugins/Output/directsound/outputdirectsoundfactory.cpp b/src/plugins/Output/directsound/outputdirectsoundfactory.cpp new file mode 100644 index 000000000..3238b8ff8 --- /dev/null +++ b/src/plugins/Output/directsound/outputdirectsoundfactory.cpp @@ -0,0 +1,66 @@ +/*************************************************************************** + * Copyright (C) 2014 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include +#include "outputdirectsound.h" +#include "outputdirectsoundfactory.h" + + +const OutputProperties OutputDirectSoundFactory::properties() const +{ + OutputProperties properties; + properties.name = tr("DirectSound Plugin"); + properties.hasAbout = true; + properties.hasSettings = false; + properties.shortName = "directsound"; + return properties; +} + +Output* OutputDirectSoundFactory::create() +{ + return new OutputDirectSound(); +} + +Volume *OutputDirectSoundFactory::createVolume() +{ + return new VolumeDirectSound(); +} + +void OutputDirectSoundFactory::showSettings(QWidget* parent) +{ + Q_UNUSED(parent); +} + +void OutputDirectSoundFactory::showAbout(QWidget *parent) +{ + QMessageBox::about (parent, tr("About DirectSound Output Plugin"), + tr("Qmmp DirectSound Output Plugin")+"\n"+ + tr("Written by: Ilya Kotov ")); +} + +QTranslator *OutputDirectSoundFactory::createTranslator(QObject *parent) +{ + QTranslator *translator = new QTranslator(parent); + QString locale = Qmmp::systemLanguageID(); + translator->load(QString(":/directsound_plugin_") + locale); + return translator; +} + +Q_EXPORT_PLUGIN2(directsound,OutputDirectSoundFactory) diff --git a/src/plugins/Output/directsound/outputdirectsoundfactory.h b/src/plugins/Output/directsound/outputdirectsoundfactory.h new file mode 100644 index 000000000..57fef18b3 --- /dev/null +++ b/src/plugins/Output/directsound/outputdirectsoundfactory.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (C) 2014 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#ifndef OUTPUTDIRECTSOUNDFACTORY_H +#define OUTPUTDIRECTSOUNDFACTORY_H + +#include +#include +#include +#include +#include +#include + + +class OutputDirectSoundFactory : public QObject, OutputFactory +{ +Q_OBJECT +Q_INTERFACES(OutputFactory) + +public: + const OutputProperties properties() const; + Output* create(); + Volume *createVolume(); + void showSettings(QWidget* parent); + void showAbout(QWidget *parent); + QTranslator *createTranslator(QObject *parent); +}; + +#endif -- cgit v1.2.3-13-gbd6f