diff --git a/TODO b/TODO index c239555f09ce80e1ff97910ca906c9a2a3b58f9c..f853406cb20354928a9827c193c90d82a04eed3a 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 6b2d1439891c186db352f883c802cb11795f3386..4503fb8340f3485bea566ec83a1516c14e18da97 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 9ebf0cceda585c6c10569cdd6c83c938bda635db..831bd0006a8fd22738df3aaf89f24fe65f6274ab 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 f8d70b6133cee97382dc0a9678d55cb64630f6c0..c19aea4dfbbee81ccfc950ac84922817726e8404 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 49a0dc12b4dc2977277fd189d5b9dfaa518c0cef..137654afec05c084b9a540a5ced1beed7bf0ffd3 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 7ea7a87600f626033e971fa7e9c5d436ba233c67..f36c5531defa2f87a4f75a36db2a18ed94015c09 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;