From cba90bc47f96e0c0b3808c40b475cc9c4522d298 Mon Sep 17 00:00:00 2001 From: SeeLook <945374+SeeLook@users.noreply.github.com> Date: Fri, 1 Apr 2016 11:14:20 +0200 Subject: [PATCH] Fixed glitches of playing sound: emitting signal when decoded ogg data is ready and starting playing then instead of blocking main thread with sleep and waiting for decoding. Code cleaned. --- TODO | 4 +- changes | 9 +- src/libs/sound/toggscale.cpp | 158 +++++++++++++++++--------------- src/libs/sound/toggscale.h | 163 +++++++++++++++++---------------- src/libs/sound/tqtaudioout.cpp | 88 +++++++++--------- src/libs/sound/tqtaudioout.h | 37 ++++---- 6 files changed, 234 insertions(+), 225 deletions(-) diff --git a/TODO b/TODO index c239555f0..f853406cb 100644 --- a/TODO +++ b/TODO @@ -22,19 +22,17 @@ ANDROID: - hide 'clear score' one when undesired (single mode, exam with playing): innerWidget->flyActions()->append(bar->scoreDeleteAll()); // TODO: idea is brilliant but needs more efforts - resetting options closes Nootka but does not launch it again - - played sound is sometimes distorted (when note starts playing) - no level/exam icon in file manager, not all file managers support opening Nootka files - when no guitar preview - staff lines are too big - keep scroll bar of score always off - it appears when switching single/multi -- Help QTextBrowser has QScroller but it works only with two-touch move, but TlevelPreview works good - HOME button would be switching available menus - handle BACK button to destroy visible menu and/or prevent to close exam - duration of animation of note correction was decreased to 200ms to work properly under Android, but it would be better to signal when it is finished and perform some routines in main score after that ============================================================================ - TexamExecutor has many, many un-wrapped strings, many "" -- Use int and enumerations between plugins and main window instead of text messages - especially updater +- Use int and enumerations between plugins and main window instead of text messages (level plugin to do) To consideration: - additional settings options: diff --git a/changes b/changes index 6b2d14398..4503fb834 100644 --- a/changes +++ b/changes @@ -1,10 +1,13 @@ -1.3.0 alpha1 - - removed roundness of widget/tips - - prepared code for further features +1.2A.5 testing + ANDROID + - fixed fluency of playing, no more glitches Under the hood - reorganized layout of libraries, score is in separate lib - exam execution moved to plugin +1.2.5 + Clef menu visibility fixes for Qt 5.6 compatibility + 1.2A.4 beta2 ANDROID - exam file can be sent directly through Android native services diff --git a/src/libs/sound/toggscale.cpp b/src/libs/sound/toggscale.cpp index 9ebf0cced..831bd0006 100644 --- a/src/libs/sound/toggscale.cpp +++ b/src/libs/sound/toggscale.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2013-2015 by Tomasz Bojczuk * + * Copyright (C) 2013-2016 by Tomasz Bojczuk * * seelook@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -20,11 +20,11 @@ #include "toggscale.h" #include <music/tinstrument.h> #include <tpath.h> -#include <QFile> -#include <QDataStream> -#include <QDebug> -#include <QThread> -#include <QFileInfo> +#include <QtCore/qfile.h> +#include <QtCore/qdatastream.h> +#include <QtCore/qdebug.h> +#include <QtCore/qthread.h> +#include <QtCore/qfileinfo.h> #include <stdlib.h> #include <unistd.h> @@ -98,12 +98,12 @@ ToggScale::ToggScale() : m_oggConnected(false), m_touchConnected(false), m_instrument(-1) { - m_touch = new soundtouch::SoundTouch(); - m_touch->setChannels(1); + m_touch = new soundtouch::SoundTouch(); + m_touch->setChannels(1); #if defined (Q_OS_UNIX) // increase minimal audio data must to be processed when system works with PulseAudio - QFileInfo pulseBin("/usr/bin/pulseaudio"); - if (pulseBin.exists()) // it is necessary both for Nootka with native PA and PA in ALSA bridge mode - minDataAmount = 15000; + QFileInfo pulseBin("/usr/bin/pulseaudio"); + if (pulseBin.exists()) // it is necessary both for Nootka with native PA and PA in ALSA bridge mode + minDataAmount = 15000; #endif moveToThread(m_thread); connect(m_thread, SIGNAL(started()), this, SLOT(decodeOgg())); @@ -121,7 +121,7 @@ void ToggScale::deleteData() { stopDecoding(); if (m_thread->isRunning()) { m_thread->terminate(); - m_thread->quit(); + m_thread->quit(); } if (m_oggInMemory) { delete m_oggInMemory; @@ -135,33 +135,36 @@ void ToggScale::deleteData() { qint16 ToggScale::getSample(int offset) { - return m_pcmBuffer[offset]; + return m_pcmBuffer[offset]; } void ToggScale::setNote(int noteNr) { - if (noteNr == m_prevNote) + if (noteNr == m_prevNote) { + emit oggReady(); return; - int baseNote = noteNr; + } + + int baseNote = noteNr; m_isReady = false; - if (noteNr < m_firstNote || noteNr > m_lastNote) { // prepare SoundTouch - if (noteNr < m_firstNote) { - baseNote = m_firstNote; - m_innerOffset = noteNr - m_firstNote; - } else if (noteNr > m_lastNote) { - baseNote = m_lastNote; - m_innerOffset = noteNr - m_lastNote; - } - } else - m_innerOffset = 0.0; - adjustSoundTouch(); + if (noteNr < m_firstNote || noteNr > m_lastNote) { // prepare SoundTouch + if (noteNr < m_firstNote) { + baseNote = m_firstNote; + m_innerOffset = noteNr - m_firstNote; + } else if (noteNr > m_lastNote) { + baseNote = m_lastNote; + m_innerOffset = noteNr - m_lastNote; + } + } else + m_innerOffset = 0.0; + adjustSoundTouch(); int fasterOffset = 1000; - if (baseNote - m_firstNote == 0) - fasterOffset = 0; + if (baseNote - m_firstNote == 0) + fasterOffset = 0; stopDecoding(); m_prevNote = noteNr; - int ret = ov_pcm_seek(&m_ogg, (baseNote - m_firstNote) * 44100 * 2 - fasterOffset); + int ret = ov_pcm_seek(&m_ogg, (baseNote - m_firstNote) * 44100 * 2 - fasterOffset); m_thread->start(); } @@ -183,60 +186,60 @@ void ToggScale::setPitchOffset(float pitchOff) { bool ToggScale::loadAudioData(int instrument) { - QString fileName; - if (instrument != m_instrument) { - switch ((Einstrument)instrument) { - case e_classicalGuitar: - fileName = Tpath::sound("classical-guitar"); - m_firstNote = -11; m_lastNote = 41; - break; - case e_electricGuitar: - fileName = Tpath::sound("electric-guitar"); - m_firstNote = -11; m_lastNote = 41; - break; - case e_bassGuitar: - fileName = Tpath::sound("bass-guitar"); - m_firstNote = -24; m_lastNote = 21; - break; - default: - return false; - } - } else - return false; + QString fileName; + if (instrument != m_instrument) { + switch ((Einstrument)instrument) { + case e_classicalGuitar: + fileName = Tpath::sound("classical-guitar"); + m_firstNote = -11; m_lastNote = 41; + break; + case e_electricGuitar: + fileName = Tpath::sound("electric-guitar"); + m_firstNote = -11; m_lastNote = 41; + break; + case e_bassGuitar: + fileName = Tpath::sound("bass-guitar"); + m_firstNote = -24; m_lastNote = 21; + break; + default: + return false; + } + } else + return false; QFile oggFile(fileName); if (!oggFile.exists()) return false; - + oggFile.open(QIODevice::ReadOnly); QDataStream oggStream(&oggFile); - if (m_oggInMemory) - delete m_oggInMemory; + if (m_oggInMemory) + delete m_oggInMemory; m_oggInMemory = new qint8[oggFile.size()]; oggStream.readRawData((char*)m_oggInMemory, oggFile.size()); - + ov_callbacks myCallBacks; m_oggWrap.curPtr = m_oggInMemory; m_oggWrap.filePtr = m_oggInMemory; m_oggWrap.fileSize = oggFile.size(); - + oggFile.close(); - - if (m_pcmBuffer) - delete m_pcmBuffer; + + if (m_pcmBuffer) + delete m_pcmBuffer; m_pcmBuffer = new qint16[2 * m_sampleRate]; myCallBacks.read_func = readOggStatic; myCallBacks.seek_func = seekOggStatic; myCallBacks.close_func = closeOggStatic; myCallBacks.tell_func = tellOggStatic; - + int ret = ov_open_callbacks((void*)&m_oggWrap, &m_ogg, NULL, 0, myCallBacks); - + if (ret < 0) { qDebug() << "cant open ogg stream"; return false; } - + // vorbis_info *oggInfo = ov_info(&m_ogg, -1); // qDebug() << oggInfo->rate << oggInfo->channels << (bool)ov_seekable(&m_ogg); // char **ptr=ov_comment(&m_ogg, -1)->user_comments; @@ -244,9 +247,9 @@ bool ToggScale::loadAudioData(int instrument) { // while(*ptr){ // fprintf(stderr,"%s\n",*ptr); // ++ptr; -// } - - return true; +// } + + return true; } @@ -276,8 +279,10 @@ void ToggScale::decodeOgg() { while (m_doDecode && loops < 500 && pos < maxSize) { read = ov_read(&m_ogg, (char*)m_pcmBuffer + pos, maxSize - pos, 0, 2, 1, &bitStream); pos += read; - if (pos > minDataAmount) // amount of data needed by single loop of rtAudio outCallBack + if (pos > minDataAmount && !m_isReady) { // amount of data needed by single loop of rtAudio outCallBack m_isReady = true; + emit oggReady(); + } loops++; } m_isDecoding = false; @@ -287,17 +292,16 @@ void ToggScale::decodeOgg() { void ToggScale::decodeAndResample() { - int bitStream; m_isDecoding = true; int maxSize = 44100 * 2 - 8192; // two sec. of audio minus some silence on the end long int tmpPos = 0, tmpRead = 0; uint pos = 0, read = 0; int samplesReady = 0; - + float **oggChannels; float *left ; float *tmpTouch = new float[8192]; - + while (m_doDecode && pos < maxSize) { /// 1. Grab audio data from ogg if (tmpPos < 172000) { // almost 2 sec. of a note @@ -310,13 +314,15 @@ void ToggScale::decodeAndResample() { } samplesReady = m_touch->numSamples(); if (samplesReady > 0) { /// 3. Get resampled/offsetted data from SoundTouch - read = m_touch->receiveSamples((SAMPLETYPE*)tmpTouch, samplesReady); + read = m_touch->receiveSamples((SAMPLETYPE*)tmpTouch, samplesReady); for (int i = 0; i < read; i++) /// 4. Convert samples to 16bit integer *(m_pcmBuffer + pos + i) = qint16(*(tmpTouch + i) * 32768); pos += read; } - if (pos > minDataAmount) // below this value SoundTouch is not able to prepare data + if (pos > minDataAmount && !m_isReady) { // below this value SoundTouch is not able to prepare data m_isReady = true; + emit oggReady(); + } } m_isDecoding = false; // qDebug() << "decodeAndResample finished" << pos; @@ -342,15 +348,15 @@ void ToggScale::adjustSoundTouch() { connect(m_thread, SIGNAL(started()), this, SLOT(decodeAndResample())); m_touchConnected = true; if (m_oggConnected) - disconnect(m_thread, SIGNAL(started()), this, SLOT(decodeOgg())); + disconnect(m_thread, SIGNAL(started()), this, SLOT(decodeOgg())); m_oggConnected = false; } else { - if (!m_oggConnected) - connect(m_thread, SIGNAL(started()), this, SLOT(decodeOgg())); - m_oggConnected = true; - if (m_touchConnected) - disconnect(m_thread, SIGNAL(started()), this, SLOT(decodeAndResample())); - m_touchConnected = false; + if (!m_oggConnected) + connect(m_thread, SIGNAL(started()), this, SLOT(decodeOgg())); + m_oggConnected = true; + if (m_touchConnected) + disconnect(m_thread, SIGNAL(started()), this, SLOT(decodeAndResample())); + m_touchConnected = false; } } diff --git a/src/libs/sound/toggscale.h b/src/libs/sound/toggscale.h index f8d70b613..c19aea4df 100644 --- a/src/libs/sound/toggscale.h +++ b/src/libs/sound/toggscale.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2013-2015 by Tomasz Bojczuk * + * Copyright (C) 2013-2016 by Tomasz Bojczuk * * seelook@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -37,99 +37,102 @@ using namespace soundtouch; -/** +/** * @class ToggScale manages audio data (musical scale) taken from ogg file. * It keeps it in m_oggInMemory array and decode it when setNote is called. -* Decompressed data are available through getSample() method. -* Data is decompressed in separate thread and some SLEEP calls are performed +* Decompressed data are available through getSample() method. +* Data is decompressed in separate thread and some SLEEP calls are performed * if data is not ready. -* -* @p setSampleRate() and @p setPitchOffset() control appropirate parameters of note. -* +* +* @p setSampleRate() and @p setPitchOffset() control appropriate parameters of note. +* * To get sample @p setNote has to be called first. * It starts decoding thread which prepares first portion of data. * Data is ready only when @p isReady() returns true. -* Preparing process takes around 1-10 ms (depends on CPU) +* Preparing process takes around 1-10 ms (depends on CPU) */ class NOOTKASOUND_EXPORT ToggScale : public QObject { Q_OBJECT - + public: - - ToggScale(); - virtual ~ToggScale(); - - /** Loads ogg file with scale of given instrument to RAM. - * If everything is OK, returns true. - * Also it is setting low and hi notes of a scale. - * Notes beyond scale are generated with SoundTouch. */ - bool loadAudioData(int instrument); - /** Unloads audio data from buffer. */ - void deleteData(); - - - /** To read ogg data from RAM */ - struct SoggFile { - qint8* curPtr; - qint8* filePtr; - size_t fileSize; - }; - - /** Prepares m_pcmBuffer: - * - determines is pitch offset necessary - * - seek ogg - * - starts decoding (re-sampling). - * - stops previous decoding if performed. */ - void setNote(int noteNr); - qint16 getSample(int offset); - unsigned int sampleRate() { return m_sampleRate; } - - /** TRUE when appropirate data amount in a buffer is ready. */ - bool isReady() { return m_isReady; } - - void setSampleRate(unsigned int rate); - - /** Sets decimal offset of a pitch -0.99 to +0.99 */ - void setPitchOffset(float pitchOff); - - + + ToggScale(); + virtual ~ToggScale(); + + /** Loads ogg file with scale of given instrument to RAM. + * If everything is OK, returns true. + * Also it is setting low and hi notes of a scale. + * Notes beyond scale are generated with SoundTouch. */ + bool loadAudioData(int instrument); + /** Unloads audio data from buffer. */ + void deleteData(); + + + /** To read ogg data from RAM */ + struct SoggFile { + qint8* curPtr; + qint8* filePtr; + size_t fileSize; + }; + + /** Prepares m_pcmBuffer: + * - determines is pitch offset necessary + * - seek ogg + * - starts decoding (re-sampling). + * - stops previous decoding if performed. */ + void setNote(int noteNr); + qint16 getSample(int offset); + unsigned int sampleRate() { return m_sampleRate; } + + /** TRUE when appropriate data amount in a buffer is ready. */ + bool isReady() { return m_isReady; } + + void setSampleRate(unsigned int rate); + + /** Sets decimal offset of a pitch -0.99 to +0.99 */ + void setPitchOffset(float pitchOff); + +signals: + void oggReady(); /**< Emitted when appropriate amount of decoded data is ready */ + + protected slots: - /** Preforms decoding. Usually is invoked by m_thread.start() - * called from setNote() method. */ - void decodeOgg(); - /** Decoding and re-sampling or/and pitch shifting */ - void decodeAndResample(); - /** Checks is decoding performed and stops it - * by setting m_doDecode=false and waiting for stop. */ - void stopDecoding(); - + /** Preforms decoding. Usually is invoked by m_thread.start() + * called from setNote() method. */ + void decodeOgg(); + /** Decoding and re-sampling or/and pitch shifting */ + void decodeAndResample(); + /** Checks is decoding performed and stops it + * by setting m_doDecode=false and waiting for stop. */ + void stopDecoding(); + private: - /** Methods needed by vorbisfile library. */ - static size_t readOggStatic(void* dst, size_t size1, size_t size2, void* fh); - static int seekOggStatic(void *fh, ogg_int64_t to, int type ); - static int closeOggStatic(void* fh); - static long tellOggStatic(void *fh ); - - void adjustSoundTouch(); // sets SoundTouch parameters - + /** Methods needed by vorbisfile library. */ + static size_t readOggStatic(void* dst, size_t size1, size_t size2, void* fh); + static int seekOggStatic(void *fh, ogg_int64_t to, int type ); + static int closeOggStatic(void* fh); + static long tellOggStatic(void *fh ); + + void adjustSoundTouch(); // sets SoundTouch parameters + private: - qint8 *m_oggInMemory; - OggVorbis_File m_ogg; /** ogg vorbis handler */ - qint16 *m_pcmBuffer; /** buffer with decompressed data of selected note. */ - SoggFile m_oggWrap; /** Structure wrapped m_oggInMemory used by ogg vorbis. */ - QThread *m_thread; - unsigned int m_sampleRate; - int m_prevNote; - bool m_doDecode; /** If new note is going to be decoded it goes to FALSE - then stops decoding loop */ - bool m_isDecoding; /** TRUE during decoding/resampling process. */ - bool m_isReady; - SoundTouch *m_touch; - float m_pitchOffset; /** Offset set from outside (by user) */ - float m_innerOffset; /** Offset calculated in setNote when SoundTouch has to generate note. */ - bool m_oggConnected, m_touchConnected; - int m_firstNote, m_lastNote; /** Numbers of first and last notes in file with scale. */ - int m_instrument; /** current instrument which samples are loaded */ + qint8 *m_oggInMemory; + OggVorbis_File m_ogg; /**< ogg vorbis handler */ + qint16 *m_pcmBuffer; /**< buffer with decompressed data of selected note. */ + SoggFile m_oggWrap; /**< Structure wrapped m_oggInMemory used by ogg vorbis. */ + QThread *m_thread; + unsigned int m_sampleRate; + int m_prevNote; + bool m_doDecode; /**< If new note is going to be decoded it goes to FALSE - then stops decoding loop */ + bool m_isDecoding; /**< TRUE during decoding/resampling process. */ + bool m_isReady; + SoundTouch *m_touch; + float m_pitchOffset; /**< Offset set from outside (by user) */ + float m_innerOffset; /**< Offset calculated in setNote when SoundTouch has to generate note. */ + bool m_oggConnected, m_touchConnected; + int m_firstNote, m_lastNote; /**< Numbers of first and last notes in file with scale. */ + int m_instrument; /**< current instrument which samples are loaded */ }; diff --git a/src/libs/sound/tqtaudioout.cpp b/src/libs/sound/tqtaudioout.cpp index 49a0dc12b..137654afe 100755 --- a/src/libs/sound/tqtaudioout.cpp +++ b/src/libs/sound/tqtaudioout.cpp @@ -47,8 +47,8 @@ QStringList TaudioOUT::getAudioDevicesList() { return devNamesList; } -QString TaudioOUT::m_devName = QStringLiteral("anything"); -TaudioOUT* TaudioOUT::m_instance = 0; +QString TaudioOUT::m_devName = QStringLiteral("anything"); +TaudioOUT* TaudioOUT::m_instance = 0; /*end static*/ @@ -73,12 +73,13 @@ TaudioOUT::TaudioOUT(TaudioParams *_params, QObject *parent) : } m_instance = this; setType(e_audio); - m_crossBuffer = new qint16[1000]; + m_crossBuffer = new qint16[1000]; setAudioOutParams(); connect(this, &TaudioOUT::finishSignal, this, &TaudioOUT::playingFinishedSlot); - + connect(oggScale, &ToggScale::oggReady, this, &TaudioOUT::startPlayingSlot); + } @@ -98,23 +99,23 @@ TaudioOUT::~TaudioOUT() void TaudioOUT::setAudioOutParams() { - playable = oggScale->loadAudioData(audioParams()->audioInstrNr); + playable = oggScale->loadAudioData(audioParams()->audioInstrNr); if (m_audioParams->OUTdevName != m_devName) createOutputDevice(); - if (playable) { - ratioOfRate = m_sampleRate / 44100; - quint32 oggSR = m_sampleRate; - if (ratioOfRate > 1) { // - if (m_sampleRate == 88200 || m_sampleRate == 176400) - oggSR = 44100; - else if (m_sampleRate == 96000 || m_sampleRate == 192000) - oggSR = 48000; - } - oggScale->setSampleRate(oggSR); - // Shifts only float part of a440diff - integer part is shifted by play() method - oggScale->setPitchOffset(audioParams()->a440diff - (float)int(audioParams()->a440diff)); - - } else + if (playable) { + ratioOfRate = m_sampleRate / 44100; + quint32 oggSR = m_sampleRate; + if (ratioOfRate > 1) { // + if (m_sampleRate == 88200 || m_sampleRate == 176400) + oggSR = 44100; + else if (m_sampleRate == 96000 || m_sampleRate == 192000) + oggSR = 48000; + } + oggScale->setSampleRate(oggSR); + // Shifts only float part of a440diff - integer part is shifted by play() method + oggScale->setPitchOffset(audioParams()->a440diff - (float)int(audioParams()->a440diff)); + + } else playable = false; } @@ -159,44 +160,41 @@ void TaudioOUT::createOutputDevice() { qDebug() << "OUT:" << m_deviceInfo.deviceName() << m_audioOUT->format().sampleRate() << m_maxSamples; connect(m_buffer, &TaudioBuffer::feedAudio, this, &TaudioOUT::outCallBack, Qt::DirectConnection); - connect(m_audioOUT, &QAudioOutput::stateChanged, this, &TaudioOUT::stateChangedSlot); + connect(m_audioOUT, &QAudioOutput::stateChanged, this, &TaudioOUT::stateChangedSlot); } bool TaudioOUT::play(int noteNr) { if (!playable) return false; - - while (m_callBackIsBussy) { - SLEEP(1); -// qDebug() << "Oops! Call back method is in progress when a new note wants to be played!"; - } - + + while (m_callBackIsBussy) { + SLEEP(1); // TODO: seems like it never occurs in Qt Audio - remove it then + qDebug() << "Oops! Call back method is in progress when a new note wants to be played!"; + } + if (m_samplesCnt < m_maxSamples) { - int off = m_samplesCnt + 1; // next chunk of playing sound - for (int i = 0; i < 1000; i++) // copy data of current sound to perform crrosfading - m_crossBuffer[i] = oggScale->getSample(off + i); - m_doCrossFade = true; - } else - m_doCrossFade = false; - + int off = m_samplesCnt + 1; // next chunk of playing sound + for (int i = 0; i < 1000; i++) // copy data of current sound to perform crrosfading + m_crossBuffer[i] = oggScale->getSample(off + i); + m_doCrossFade = true; + } else + m_doCrossFade = false; + noteNr = noteNr + int(audioParams()->a440diff); - + doEmit = true; - oggScale->setNote(noteNr); - int loops = 0; - while (!oggScale->isReady() && loops < 40) { // 40ms - max latency - SLEEP(1); - loops++; - } + oggScale->setNote(noteNr); // oggScale will emit oggReady() and invoke startPlayingSlot() + + return true; +} + + +void TaudioOUT::startPlayingSlot() { m_samplesCnt = -1; -// if (loops) -// qDebug() << "latency:" << loops << "ms"; - + if (m_audioOUT->state() != QAudio::ActiveState) m_audioOUT->start(m_buffer); - - return true; } diff --git a/src/libs/sound/tqtaudioout.h b/src/libs/sound/tqtaudioout.h index 7ea7a8760..f36c5531d 100755 --- a/src/libs/sound/tqtaudioout.h +++ b/src/libs/sound/tqtaudioout.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2015 by Tomasz Bojczuk * + * Copyright (C) 2015-2016 by Tomasz Bojczuk * * seelook@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -33,13 +33,13 @@ class TaudioParams; class QAudioOutput; class TaudioBuffer; -/** +/** * Implementation of guitar sound player using Qt Multimedia */ class NOOTKASOUND_EXPORT TaudioOUT : public TabstractPlayer { Q_OBJECT - + public: TaudioOUT(TaudioParams* _params, QObject* parent = 0); virtual ~TaudioOUT(); @@ -51,39 +51,40 @@ public: /** Starts playing given note and then returns true, otherwise gets false. */ bool play(int noteNr); void setAudioOutParams(); - void stop(); /** Immediately stops playing. */ + void stop(); /**< Immediately stops playing. */ TaudioParams* audioParams() { return m_audioParams; } protected: - int crossCount() { return m_crossCount; } /** counts samples of crossing buffer */ + int crossCount() { return m_crossCount; } /**< counts samples of crossing buffer */ void createOutputDevice(); - + signals: void finishSignal(); protected: - ToggScale *oggScale; - int ratioOfRate; // ratio of current sample rate to 44100 + ToggScale *oggScale; + int ratioOfRate; // ratio of current sample rate to 44100 private slots: void outCallBack(char* data, qint64 maxLen, qint64& wasRead); -// void updateSlot() { setAudioOutParams(); } - void playingFinishedSlot(); - void stateChangedSlot(QAudio::State state); +// void updateSlot() { setAudioOutParams(); } + void playingFinishedSlot(); + void stateChangedSlot(QAudio::State state); + void startPlayingSlot(); private: static QString m_devName; static TaudioOUT *m_instance; - int m_samplesCnt; /** Number of performed samples. */ - int m_maxSamples; /** Duration of a sound counted in samples */ + int m_samplesCnt; /**< Number of performed samples. */ + int m_maxSamples; /**< Duration of a sound counted in samples */ int m_bufferFrames, m_sampleRate; - qint16 *m_crossBuffer; /** buffer with data of part of previous note to fade out */ - bool m_doCrossFade; - float m_cross; /** current volume factor of fading effect */ - int m_crossCount; - bool m_callBackIsBussy; + qint16 *m_crossBuffer; /**< buffer with data of part of previous note to fade out */ + bool m_doCrossFade; + float m_cross; /**< current volume factor of fading effect */ + int m_crossCount; + bool m_callBackIsBussy; TaudioParams *m_audioParams; QAudioOutput *m_audioOUT; TaudioBuffer *m_buffer; -- GitLab