diff --git a/CMakeLists.txt b/CMakeLists.txt index bc8566a993198c085221b6d76ace0e688017e3f3..ceff739b023179b703968472af25892e038eb28b 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ project(nootka) set(Nootka_VERSION_MAJOR "1") set(Nootka_VERSION_MINOR "5") -set(Nootka_VERSION_PATCH "0-alpha") +set(Nootka_VERSION_PATCH "1-alpha2") set(Nootka_VERSION "${Nootka_VERSION_MAJOR}.${Nootka_VERSION_MINOR}") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f2d76514bc2df9050cec05a3d6d282813b501cf9..344d673d92a5c212a988e98af60d39e4e00a9673 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -60,15 +60,11 @@ if (CMAKE_BUILD_TYPE MATCHES Debug) add_definitions(-DQT_QML_DEBUG) endif () -# add_subdirectory( libs/scorek ) add_subdirectory( libs/core ) # libNootkaCore -# add_subdirectory( libs/score ) # libNootkaScore -# add_subdirectory( libs/widgets ) # libNootkaWidgets -# add_subdirectory( libs/sound ) # libNootkaSound -# add_subdirectory( libs/misc ) # libNootkaMisc -# add_subdirectory( libs/main ) # libNootkaMain +add_subdirectory( libs/sound ) # libNootkaSound +# add_subdirectory( libs/main ) # libNootkaMain TODO: it rather will go to main executable -include_directories( libs/core libs/score libs/widgets libs/sound libs/misc libs/main ) +include_directories( libs/core libs/sound ) # libs/main # nootka executable set(NOOTKA_SRC diff --git a/src/libs/core/nootkaconfig.h b/src/libs/core/nootkaconfig.h index 8886773f16d0b933cf2b3cac4f0e785071d5270b..4532e6775c3ba524c170d57eebe23c760f37d176 100644 --- a/src/libs/core/nootkaconfig.h +++ b/src/libs/core/nootkaconfig.h @@ -1,3 +1,3 @@ -#define NOOTKA_VERSION "1.5.0-alpha" +#define NOOTKA_VERSION "1.5.1-alpha2" diff --git a/src/libs/sound/CMakeLists.txt b/src/libs/sound/CMakeLists.txt index 3820282d2810c10d4209f4faee4ac40144c3e9fc..4b43e763b864605ad6256ad006d2a91fdf63df86 100755 --- a/src/libs/sound/CMakeLists.txt +++ b/src/libs/sound/CMakeLists.txt @@ -121,7 +121,7 @@ ELSE(VORBIS_LIBRARIES AND OGG_INCLUDE_DIRS AND VORBIS_INCLUDE_DIRS) set(VORBIS_INCLUDE_DIRS ${VORBIS_INCLUDE_DIR} ) set(OGG_INCLUDE_DIRS ${OGG_INCLUDE_DIR}) - set(VORBIS_LIBRARIES ${VORBIS_LIBRARY} CACHE STRING "Ogg vorbis library path") + set(VORBIS_LIBRARIES ${VORBIS_LIBRARY} CACHE STRING "Ogg vorbis library path") IF(VORBIS_INCLUDE_DIRS AND OGG_INCLUDE_DIRS AND VORBIS_LIBRARIES) set(OGG_FOUND TRUE) @@ -155,7 +155,7 @@ if (UNIX) ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_BINARY_DIR}/../soundtouch ) - + find_library(SOUNDTOUCH_LIBRARY NAMES SoundTouch @@ -200,29 +200,29 @@ endif (APPLE) IF(UNIX AND NOT APPLE) find_library(ALSA_LIBRARY - NAMES - asound - PATHS - /usr/lib - /usr/lib/x86_64-linux-gnu - /usr/local/lib - /opt/local/lib + NAMES + asound + PATHS + /usr/lib + /usr/lib/x86_64-linux-gnu + /usr/local/lib + /opt/local/lib ) find_library(PTHREAD_LIBRARY - NAMES - pthread - PATHS - /usr/lib - /usr/lib/x86_64-linux-gnu - /usr/local/lib - /opt/local/lib + NAMES + pthread + PATHS + /usr/lib + /usr/lib/x86_64-linux-gnu + /usr/local/lib + /opt/local/lib ) mark_as_advanced(ALSA_LIBRARY PTHREAD_LIBRARY) ENDIF(UNIX AND NOT APPLE) IF(WIN32) -# add_definitions(-D__WINDOWS_WASAPI__) +# add_definitions(-D__WINDOWS_WASAPI__) # add_definitions(-D__WINDOWS_DS__) # add_definitions(-D__WINDOWS_ASIO__) # add_definitions(-D__WINDOWS_MM__) @@ -235,7 +235,7 @@ endif(APPLE) IF(UNIX AND NOT APPLE) - ##### PulseAudio ########################################### + ##### PulseAudio ########################################### find_path(PULSE_INCLUDE_DIR NAMES pulseaudio.h @@ -245,7 +245,7 @@ IF(UNIX AND NOT APPLE) /usr/local/include /opt/local/include /sw/include - + ) if (PULSE_INCLUDE_DIR) find_library(PULSESIMPLE_LIBRARY @@ -267,16 +267,16 @@ IF(UNIX AND NOT APPLE) /opt/local/lib ) endif (PULSE_INCLUDE_DIR) - if (PULSE_INCLUDE_DIR) + if (PULSE_INCLUDE_DIR) option(ENABLE_PULSEAUDIO "Enable support for PulseAudio" ON) else(PULSE_INCLUDE_DIR) option(ENABLE_PULSEAUDIO "Enable support for PulseAudio" OFF) set(PULSEERROR_LIBRARY_FOUND TRUE) set(PULSESIMPLE_LIBRARY_FOUND TRUE) endif (PULSE_INCLUDE_DIR) - - - ##### JACK - Jack Audio Connection Kit ############## + + + ##### JACK - Jack Audio Connection Kit ############## find_path(JACK_INCLUDE_DIR NAMES jack.h @@ -286,7 +286,7 @@ IF(UNIX AND NOT APPLE) /usr/local/include /opt/local/include /sw/include - + ) if (JACK_INCLUDE_DIR) find_library(JACK_LIBRARY @@ -299,14 +299,14 @@ IF(UNIX AND NOT APPLE) /opt/local/lib ) endif (JACK_INCLUDE_DIR) - + if (JACK_INCLUDE_DIR) option(ENABLE_JACK "Enable support for JACK (Jack Audio Connection Kit)" ON) - else (JACK_INCLUDE_DIR) + else (JACK_INCLUDE_DIR) option(ENABLE_JACK "Enable support for JACK (Jack Audio Connection Kit)" OFF) set(JACK_LIBRARY_FOUND TRUE) endif (JACK_INCLUDE_DIR) - + if(ALSA_LIBRARY) add_definitions(-D__LINUX_ALSA__) message(STATUS "support for ALSA\t\t TRUE") @@ -327,54 +327,48 @@ IF(UNIX AND NOT APPLE) else(ENABLE_PULSEAUDIO AND PULSE_INCLUDE_DIR) message(STATUS "support for PulseAudio\t FALSE") endif(ENABLE_PULSEAUDIO AND PULSE_INCLUDE_DIR) - + endif(UNIX AND NOT APPLE) add_definitions(-DNOOTKASOUND_LIBRARY) -include_directories( . ../core ../score ) +include_directories( . ../core ) if (WIN32) - include_directories( rt ) + include_directories( rt ) endif(WIN32) set(LIB_NOOTKASOUND_SRC - tabstractplayer.cpp - tartiniparams.h - tmidiout.cpp - toggscale.cpp - tpitchfinder.cpp - taudioobject.h - trtaudio.cpp - tcommonlistener.cpp - trtaudioin.cpp - trtaudioout.cpp - tsound.cpp - - tartini/analysisdata.cpp - tartini/array1d.h - tartini/bspline.cpp - tartini/channel.cpp - tartini/conversions.cpp - tartini/fast_smooth.cpp - tartini/large_vector.h - tartini/mytransforms.cpp - tartini/notedata.cpp - tartini/SmartPtr.h - tartini/useful.cpp - tartini/filters/FastSmoothedAveragingFilter.cpp - tartini/filters/Filter.h - tartini/filters/FixedAveragingFilter.cpp - tartini/filters/GrowingAveragingFilter.cpp - tartini/filters/IIR_Filter.cpp - - widgets/tabstractsoundview.cpp - widgets/tintonationview.cpp - widgets/tpitchview.cpp - widgets/tvolumeview.cpp -# widgets/tpcmview.cpp + tabstractplayer.cpp + tartiniparams.h + tmidiout.cpp + toggscale.cpp + tpitchfinder.cpp + taudioobject.h + trtaudio.cpp + tcommonlistener.cpp + trtaudioin.cpp + trtaudioout.cpp + tsound.cpp + + tartini/analysisdata.cpp + tartini/array1d.h + tartini/bspline.cpp + tartini/channel.cpp + tartini/conversions.cpp + tartini/fast_smooth.cpp + tartini/large_vector.h + tartini/mytransforms.cpp + tartini/notedata.cpp + tartini/SmartPtr.h + tartini/useful.cpp + tartini/filters/FastSmoothedAveragingFilter.cpp + tartini/filters/Filter.h + tartini/filters/FixedAveragingFilter.cpp + tartini/filters/GrowingAveragingFilter.cpp + tartini/filters/IIR_Filter.cpp ) IF(WIN32) @@ -382,21 +376,15 @@ IF(WIN32) link_directories( ${CMAKE_BINARY_DIR}/src ) set(WIN_LIBS RtAudio) - list(APPEND LIB_NOOTKASOUND_SRC - tasioemitter.h -# rt/asio.cpp -# rt/asiodrivers.cpp -# rt/asiolist.cpp -# rt/iasiothiscallresolver.cpp - ) - list(APPEND LIB_NOOTKASOUND_SRC + list(APPEND LIB_NOOTKASOUND_SRC tasioemitter.h ) + list(APPEND LIB_NOOTKASOUND_SRC stouch/SoundTouch.cpp stouch/TDStretch.cpp stouch/RateTransposer.cpp stouch/AAFilter.cpp - stouch/FIRFilter.cpp - stouch/FIFOSampleBuffer.cpp - stouch/cpu_detect_x86.cpp + stouch/FIRFilter.cpp + stouch/FIFOSampleBuffer.cpp + stouch/cpu_detect_x86.cpp stouch/sse_optimized.cpp stouch/InterpolateCubic.cpp stouch/InterpolateLinear.cpp @@ -411,27 +399,26 @@ endif(WIN32) add_library(NootkaSound SHARED ${LIB_NOOTKASOUND_SRC} ) target_link_libraries(NootkaSound - Qt5::Widgets - NootkaCore - NootkaScore - ${WIN_LIBS} - ${FFTW3_LIBRARIES} - ${ALSA_LIBRARY} ${PTHREAD_LIBRARY} - ${PULSESIMPLE_LIBRARY} ${PULSEERROR_LIBRARY} - ${JACK_LIBRARY} - ${VORBIS_LIBRARIES} - ${SOUNDTOUCH_LIBRARY} + Qt5::Core + NootkaCore + ${WIN_LIBS} + ${FFTW3_LIBRARIES} + ${ALSA_LIBRARY} ${PTHREAD_LIBRARY} + ${PULSESIMPLE_LIBRARY} ${PULSEERROR_LIBRARY} + ${JACK_LIBRARY} + ${VORBIS_LIBRARIES} + ${SOUNDTOUCH_LIBRARY} ${CoreAudio_LIB} ${CoreMidi_LIB} ${CoreFoundation_LIB} ) -if(UNIX AND NOT APPLE) # Linux path for Nootka binary +if(UNIX AND NOT APPLE) # Linux path for Nootka binary install(TARGETS NootkaSound DESTINATION lib/nootka) else(UNIX AND NOT APPLE) - if(WIN32) # Windows + if(WIN32) # Windows install(TARGETS NootkaSound DESTINATION .) - else(WIN32) # MacOs + else(WIN32) # MacOs install(TARGETS NootkaSound DESTINATION "${CMAKE_INSTALL_PREFIX}/nootka.app/Contents/Frameworks") endif(WIN32) endif(UNIX AND NOT APPLE) diff --git a/src/libs/sound/nootkasoundglobal.h b/src/libs/sound/nootkasoundglobal.h index 61366bdf9f721b9aa78e02c1d9d8b6702ae0f610..3da4582ffae4a748dd42f6f30272ddc34d9d6478 100644 --- a/src/libs/sound/nootkasoundglobal.h +++ b/src/libs/sound/nootkasoundglobal.h @@ -12,7 +12,7 @@ * 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 * + * You should have received a copy of the GNU General Public License * * along with this program. If not, see <http://www.gnu.org/licenses/>. * ***************************************************************************/ @@ -23,4 +23,4 @@ #else # define NOOTKASOUND_EXPORT Q_DECL_IMPORT #endif - + diff --git a/src/libs/sound/tabstractplayer.h b/src/libs/sound/tabstractplayer.h index fc6d95775d917d758c43043e9ba830337323ca9c..123227c7b4c8d8b12b356b9cbcbb3816164ef1cc 100644 --- a/src/libs/sound/tabstractplayer.h +++ b/src/libs/sound/tabstractplayer.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2013-2014 by Tomasz Bojczuk * + * Copyright (C) 2013-2017 by Tomasz Bojczuk * * seelook@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -20,49 +20,65 @@ #ifndef TABSTRACTPLAYER_H #define TABSTRACTPLAYER_H -#include <QObject> +#include <QtCore/qobject.h> #include <nootkasoundglobal.h> class QTimer; -/** - * Base abstract class for sound output (playing scale). +/** + * Base abstract class for sound output (playing scale). */ class NOOTKASOUND_EXPORT TabstractPlayer : public QObject { Q_OBJECT - + public: - TabstractPlayer(QObject *parent = 0); - - bool isPlayable() { return playable; } - - /** Starts playing given note and then returns true, otherwise gets false. */ - virtual bool play(int noteNr); - virtual void stop(); /** Immediately stops playing. Emits nothing */ - virtual void deleteMidi(); /**Does nothing in audio player subclass. */ - virtual void setMidiParams(); - - enum EplayerType { e_audio, e_midi }; - - EplayerType type() { return playerType; } - + TabstractPlayer(QObject *parent = 0); + + bool isPlayable() { return playable; } + + /** + * Starts playing given note and then returns true, otherwise gets false. + */ + virtual bool play(int noteNr); + + /** + * Immediately stops playing. Emits nothing + */ + + virtual void stop(); + /** + * Does nothing in audio player subclass. + */ + virtual void deleteMidi(); + virtual void setMidiParams(); + + enum EplayerType { e_audio, e_midi }; + + EplayerType type() { return playerType; } + signals: - void noteFinished(); /** This signal is emitted when playing of a note is finished. */ - - + /** + * This signal is emitted when playing of a note is finished. + */ + void noteFinished(); + + protected: void setType(EplayerType type) { playerType = type; } - bool playable; - - /** Determines whether noteFinished() signal is emited in offTimer timeOut() slot. - * Slot is also called by stop() method and then signal can't be emited. */ - bool doEmit; - QTimer *offTimer; - EplayerType playerType; - + + bool playable; + + /** + * Determines whether noteFinished() signal is emited in offTimer timeOut() slot. + * Slot is also called by stop() method and then signal can't be emited. + */ + bool doEmit; + QTimer *offTimer; + EplayerType playerType; + }; #endif // TABSTRACTPLAYER_H diff --git a/src/libs/sound/tartiniparams.h b/src/libs/sound/tartiniparams.h index 95ef2e08db9d45c21f6bab57173c84ca0d049c96..4b3fe9c451a82f535c5fe992f64c7b093932eb4c 100644 --- a/src/libs/sound/tartiniparams.h +++ b/src/libs/sound/tartiniparams.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2012-2014 by Tomasz Bojczuk * + * Copyright (C) 2012-2017 by Tomasz Bojczuk * * seelook@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -23,18 +23,22 @@ #include <QString> #include "nootkasoundglobal.h" - /** Types of detection methods. */ + /** + * Types of detection methods. + */ enum EanalysisModes { e_MPM = 0, e_AUTOCORRELATION = 1, e_MPM_MODIFIED_CEPSTRUM = 2 }; - /** Audio input & pitch recognition settings for Tartini core. */ +/** + * Audio input & pitch recognition settings for Tartini core. + */ class NOOTKASOUND_EXPORT TartiniParams { public: quint32 rate; quint8 chanells; quint32 windowSize; - quint32 framesPerChunk; // in mono signal frames are the same as samples + quint32 framesPerChunk; /** in mono signal frames are the same as samples */ double dBFloor; bool equalLoudness; bool doingFreqAnalysis; @@ -42,12 +46,12 @@ public: bool doingHarmonicAnalysis; bool firstTimeThrough; bool doingDetailedPitch; - int threshold; // threshold of lowest loudness in [dB] + int threshold; /** threshold of lowest loudness in [dB] */ EanalysisModes analysisType; - double topPitch; // The highest possible note pitch allowed (lowest possible is 0 in Tartini) - qint16 loPitch; // The lowest possible note. Filtered in searchIn() method + double topPitch; /** The highest possible note pitch allowed (lowest possible is 0 in Tartini) */ + qint16 loPitch; /** The lowest possible note. Filtered in searchIn() method */ double ampThresholds[7][2]; - + }; #endif // TARTINIPARAMS_H diff --git a/src/libs/sound/tasioemitter.h b/src/libs/sound/tasioemitter.h index 4608b8f29f98804d229fac7eacd8a49f05b8fd0a..c6bf45e985e09a68eae49ee279a4319afd2125d0 100644 --- a/src/libs/sound/tasioemitter.h +++ b/src/libs/sound/tasioemitter.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2015-2016 by Tomasz Bojczuk * + * Copyright (C) 2015-2017 by Tomasz Bojczuk * * seelook@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -21,26 +21,31 @@ #ifndef TASIOEMITTER_H #define TASIOEMITTER_H -#include <QObject> +#include <QtCore/qobject.h> -/** - * This is QObject that emits @p resetASIO() signal + +/** + * This is @p QObject that emits @p resetASIO() signal * @p RtApiAsio has static instance of it * end emits this signal when ASIO requires restart. */ class TASIOEmitter : public QObject { - Q_OBJECT - + Q_OBJECT + public: - explicit TASIOEmitter(QObject* parent = 0) : QObject(parent) {} - - void emitResetASIO() { emit resetASIO(); } + explicit TASIOEmitter(QObject* parent = 0) : QObject(parent) {} + + void emitResetASIO() { emit resetASIO(); } signals: - void resetASIO(); /** Emitted when user changes devices or parameters in ASIO console - stream have to be stopped and started again */ - + + /** + * Emitted when user changes devices or parameters in ASIO console - stream have to be stopped and started again + */ + void resetASIO(); + }; #endif // TASIOEMITTER_H diff --git a/src/libs/sound/taudiobuffer.h b/src/libs/sound/taudiobuffer.h index 0dd2e430ecc9620bc709fb71b21d21632774201c..640f08eb96b46b7bded997f6af3f9f97f4314172 100644 --- a/src/libs/sound/taudiobuffer.h +++ b/src/libs/sound/taudiobuffer.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2015-2016 by Tomasz Bojczuk * + * Copyright (C) 2015-2017 by Tomasz Bojczuk * * seelook@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -40,7 +40,7 @@ class TaudioBuffer : public QIODevice Q_OBJECT public: - TaudioBuffer(QObject* parent = 0) : QIODevice(parent), m_bufferSize(2048) {} + TaudioBuffer(QObject* parent = nullptr) : QIODevice(parent), m_bufferSize(2048) {} /** * In fact, there is no any buffer! @@ -65,7 +65,9 @@ protected: } - /** When @p m_bufferSize is set to 0 @p len parameter is respected */ + /** + * When @p m_bufferSize is set to 0 @p len parameter is respected + */ virtual qint64 writeData(const char *data, qint64 len) { qint64 dataLenght = m_bufferSize ? m_bufferSize : len; emit readAudio(data, dataLenght); diff --git a/src/libs/sound/taudioobject.h b/src/libs/sound/taudioobject.h index 100a9a5561b7cbaeba38ce3b304ef35823bd0261..dceda629faca8d0d0c7823230ebf2323086c8d54 100644 --- a/src/libs/sound/taudioobject.h +++ b/src/libs/sound/taudioobject.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2014-2015 by Tomasz Bojczuk * + * Copyright (C) 2014-2017 by Tomasz Bojczuk * * seelook@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -17,33 +17,42 @@ ***************************************************************************/ - #ifndef TAUDIOOBJECT_H #define TAUDIOOBJECT_H -#include <QObject> + +#include <QtCore/qobject.h> #include "nootkasoundglobal.h" -/** + +/** * This class is like 'emitter' of signals for TrtAudio class - * which can not derive directly from QObject + * which can not derive directly from @p QObject */ class NOOTKASOUND_EXPORT TaudioObject : public QObject { - Q_OBJECT - + Q_OBJECT + public: - explicit TaudioObject(QObject* parent = 0) : QObject(parent) {} - - void emitStreamOpened() { emit streamOpened(); } - void emitParamsUpdated() { emit paramsUpdated(); } - void emitPlayingFinished() { emit playingFinished(); } - + explicit TaudioObject(QObject* parent = nullptr) : QObject(parent) {} + + void emitStreamOpened() { emit streamOpened(); } + void emitParamsUpdated() { emit paramsUpdated(); } + void emitPlayingFinished() { emit playingFinished(); } + signals: - void streamOpened(); - void paramsUpdated(); /** Emitted after @p TrtAudio::updateAudioParams() */ - void playingFinished(); /** Emitted when all note data were send */ - + void streamOpened(); + + /** + * Emitted after @p TrtAudio::updateAudioParams() + */ + void paramsUpdated(); + + /** + * Emitted when all note data were send + */ + void playingFinished(); + }; #endif // TAUDIOOBJECT_H diff --git a/src/libs/sound/tcommonlistener.cpp b/src/libs/sound/tcommonlistener.cpp index c4b6d3aebab2db245211f4638d29f4f79c1d3d07..727d98b103f5d7c04a1449eb518d1d123a9bdd5c 100644 --- a/src/libs/sound/tcommonlistener.cpp +++ b/src/libs/sound/tcommonlistener.cpp @@ -26,7 +26,7 @@ #include <QtCore/qdebug.h> -#define LOWEST_PCM (0.2f) // lowest raw PCM volume to start counting +#define LOWEST_PCM (0.2f) // lowest raw PCM volume to start counting #define HIGHEST_PCM (0.8f) #define MAX_OUT_NUM (10) @@ -188,7 +188,7 @@ void TcommonListener::noteFinishedSlot(TnoteStruct* lastNote) { m_noteWasStarted = false; if (!isPaused()) { qreal midiPitch = lastNote->getAverage(3, // non guitar pitch is average of all pitches - Tcore::gl()->instrument == e_noInstrument ? lastNote->pitches()->size() : finder()->minChunksNumber()); + GLOB->instrument().type() == Tinstrument::NoInstrument ? lastNote->pitches()->size() : finder()->minChunksNumber()); m_lastNote.set(midiPitch - m_audioParams->a440diff, pitch2freq(midiPitch), lastNote->duration); if (inRange(m_lastNote.pitchF)) emit noteFinished(m_lastNote); diff --git a/src/libs/sound/tcommonlistener.h b/src/libs/sound/tcommonlistener.h index 9b74296b702dbe80226f5fc1b4971927459baa1c..45e500d445fdcbd74c457897236aab4c944dbb7f 100644 --- a/src/libs/sound/tcommonlistener.h +++ b/src/libs/sound/tcommonlistener.h @@ -46,7 +46,7 @@ class NOOTKASOUND_EXPORT TcommonListener : public QObject { Q_OBJECT public: - explicit TcommonListener(TaudioParams* params, QObject* parent = 0); + explicit TcommonListener(TaudioParams* params, QObject* parent = nullptr); ~TcommonListener(); @@ -167,7 +167,7 @@ private: bool m_stoppedByUser; qreal m_loPitch, m_hiPitch; bool m_noteWasStarted; - int m_currentRange; /**< Current range of detected note - see @class TaudioParams */ + int m_currentRange; /**< Current range of detected note - see @p TaudioParams */ Estate m_state; int m_loPCMnumber = 0, m_hiPCMnumber = 0; /**< Counts number of PCM volumes out of range, to emit warning note */ }; diff --git a/src/libs/sound/tmidiout.cpp b/src/libs/sound/tmidiout.cpp index b9adf9c33a877afe6db84d0afda6a0e6f657e788..d76d493cf630f77d06b71fc9917b46f05a9aa3a3 100755 --- a/src/libs/sound/tmidiout.cpp +++ b/src/libs/sound/tmidiout.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2013=2014 by Tomasz Bojczuk * + * Copyright (C) 2013=2017 by Tomasz Bojczuk * * seelook@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -38,7 +38,7 @@ QStringList TmidiOut::getMidiPortsList() for (int i = 0; i < midiOut->getPortCount(); i++) portList << QString::fromStdString(midiOut->getPortName(i)); delete midiOut; - return portList; + return portList; } @@ -76,7 +76,7 @@ void TmidiOut::setMidiParams() { playable = false; return; } - + if (m_midiOut && m_midiOut->getPortCount() > 0) { m_portNr = 0; #if defined(Q_OS_LINUX) @@ -127,7 +127,7 @@ bool TmidiOut::play(int noteNr) { int semiToneOff = 0; // "whole" semitone offset quint16 midiBend = 0; if (m_params->a440diff != 0.0) { - semiToneOff = (int)m_params->a440diff; + semiToneOff = (int)m_params->a440diff; float fineOff = qAbs(m_params->a440diff) - qAbs((float)semiToneOff); // float part of offset if (fineOff) { // if exist midi bend message is needed if (m_params->a440diff < 0) // restore bend direction @@ -152,7 +152,7 @@ bool TmidiOut::play(int noteNr) { if (offTimer->isActive()) offTimer->stop(); offTimer->start(1500); - return true; + return true; } @@ -187,7 +187,7 @@ void TmidiOut::openMidiPort() { m_message[0] = 241; m_message[1] = 60; m_midiOut->sendMessage(&m_message); - + m_message.push_back(0); // third message param m_message[0] = 176; @@ -214,7 +214,7 @@ void TmidiOut::midiNoteOff() { qDebug() << "can't send MIDI message to fade sound out"; } m_prevMidiNote = 0; -// if (m_portOpened) { +// if (m_portOpened) { // try { // m_midiOut->closePort(); // } catch (RtMidiError &error){ diff --git a/src/libs/sound/tmidiout.h b/src/libs/sound/tmidiout.h index 446b1a7facc07326ccf9233468a421e2a960dbda..df7098dbfee6c1bcc14f3e6c47c93d1cf02920dd 100644 --- a/src/libs/sound/tmidiout.h +++ b/src/libs/sound/tmidiout.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2013-2014 by Tomasz Bojczuk * + * Copyright (C) 2013-2017 by Tomasz Bojczuk * * seelook@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -20,10 +20,10 @@ #ifndef TMIDIOUT_H #define TMIDIOUT_H -#include <QStringList> +#include <QtCore/qstringlist.h> #include <vector> #include "tabstractplayer.h" -#include "nootkacoreglobal.h" +#include "nootkasoundglobal.h" class RtMidiOut; @@ -34,47 +34,55 @@ class TaudioParams; */ class NOOTKASOUND_EXPORT TmidiOut : public TabstractPlayer { - + Q_OBJECT - + public: - TmidiOut(TaudioParams *params, QObject *parent = 0); - virtual ~TmidiOut(); - - static QStringList getMidiPortsList(); - - bool play(int noteNr); - - /** Sets midi parameters: - * @param portName, if empty system prefered is set (Timidity under Linux) - * @param instrNr for instrument number in midi nomenclature. */ - void setMidiParams(); - - /** Deletes midi device if exists. - * Midi device usually blocks audio devices, - * so when it exists getAudioDevicesList() doesn't work */ - void deleteMidi(); - - /** Immediately stops playing. Emits nothing */ - void stop(); - - + TmidiOut(TaudioParams *params, QObject *parent = nullptr); + virtual ~TmidiOut(); + + static QStringList getMidiPortsList(); + + bool play(int noteNr); + + /** + * Sets midi parameters: + * @param portName, if empty system prefered is set (Timidity under Linux) + * @param instrNr for instrument number in midi nomenclature. + */ + void setMidiParams(); + + /** + * Deletes midi device if exists. + * Midi device usually blocks audio devices, + * so when it exists getAudioDevicesList() doesn't work + */ + void deleteMidi(); + + /** + * Immediately stops playing. Emits nothing + */ + void stop(); + + private: - TaudioParams *m_params; - - RtMidiOut *m_midiOut; - unsigned char m_prevMidiNote; - std::vector<unsigned char> m_message; - unsigned int m_portNr; - bool m_portOpened; - + TaudioParams *m_params; + + RtMidiOut *m_midiOut; + unsigned char m_prevMidiNote; + std::vector<unsigned char> m_message; + unsigned int m_portNr; + bool m_portOpened; + private: - void openMidiPort(); - + void openMidiPort(); + private slots: - /** Turns off played @param m_prevMidiNote - * If @param m_doEmit is true emits noteFinished() signal. */ - void midiNoteOff(); + /** + * Turns off played @param m_prevMidiNote + * If @param m_doEmit is true emits noteFinished() signal. + */ + void midiNoteOff(); }; #endif // TMIDIOUT_H diff --git a/src/libs/sound/toggscale.cpp b/src/libs/sound/toggscale.cpp index 9e0395a73be554e7779ed57b9f7238f729506fa4..09a6656ff451acfd2d20282018e3f813d271e1e1 100644 --- a/src/libs/sound/toggscale.cpp +++ b/src/libs/sound/toggscale.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2013-2016 by Tomasz Bojczuk * + * Copyright (C) 2013-2017 by Tomasz Bojczuk * * seelook@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -192,16 +192,16 @@ void ToggScale::setPitchOffset(float pitchOff) { bool ToggScale::loadAudioData(int instrument) { QString fileName; if (instrument != m_instrument) { - switch ((Einstrument)instrument) { - case e_classicalGuitar: + switch (static_cast<Tinstrument::Etype>(instrument)) { + case Tinstrument::ClassicalGuitar: fileName = Tpath::sound("classical-guitar"); m_firstNote = -11; m_lastNote = 41; break; - case e_electricGuitar: + case Tinstrument::ElectricGuitar: fileName = Tpath::sound("electric-guitar"); m_firstNote = -11; m_lastNote = 41; break; - case BassGuitar: + case Tinstrument::BassGuitar: fileName = Tpath::sound("bass-guitar"); m_firstNote = -24; m_lastNote = 21; break; diff --git a/src/libs/sound/toggscale.h b/src/libs/sound/toggscale.h index 91d12e2f84fa27c04e306b7c635fa3a6f19a2403..cdc2fc5f7413e1fb8307a68d72a5e13f9983588a 100644 --- a/src/libs/sound/toggscale.h +++ b/src/libs/sound/toggscale.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2013-2016 by Tomasz Bojczuk * + * Copyright (C) 2013-2017 by Tomasz Bojczuk * * seelook@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -21,8 +21,7 @@ #define TOGGSCALE_H #include "nootkasoundglobal.h" -#include <QString> -#include <QObject> +#include <QtCore/qobject.h> #include "vorbis/codec.h" #include "vorbis/vorbisfile.h" #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) @@ -60,37 +59,49 @@ 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. */ + /** + * 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(); + /** + * Unloads audio data from buffer. + */ + void deleteData(); - /** To read ogg data from RAM */ + /** + * 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. */ + /** + * 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. */ + /** + * @p 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 */ + /** + * Sets decimal offset of a pitch -0.99 to +0.99 + */ void setPitchOffset(float pitchOff); int alreadyDecoded() { return m_alreadyDecoded; } /**< Number of already decoded bytes */ diff --git a/src/libs/sound/tpitchfinder.cpp b/src/libs/sound/tpitchfinder.cpp index 60d56223e686c526256afc4ea12573b7730a1c74..a37ece1241080e5220ddd17dde1918d582088276 100644 --- a/src/libs/sound/tpitchfinder.cpp +++ b/src/libs/sound/tpitchfinder.cpp @@ -68,40 +68,40 @@ TpitchFinder::TpitchFinder(QObject* parent) : m_splitByVol(true), m_minVolToSplit(0.1), m_skipStillerVal(0.0), m_averVolume(0.0) { - m_aGl = new TartiniParams(); - m_aGl->chanells = 1; - m_aGl->rate = 44100; - m_aGl->windowSize = 2048; - m_aGl->framesPerChunk = 1; // A trick - setSampleRate() will set it soon - m_aGl->dBFloor = -150.0; // it is unchanged but if it will in conversions.cpp it is hard coded - m_aGl->equalLoudness = true; - m_aGl->doingFreqAnalysis = true; - m_aGl->doingAutoNoiseFloor = true; - m_aGl->doingHarmonicAnalysis = false; - m_aGl->firstTimeThrough = true; - m_aGl->doingDetailedPitch = true; - m_aGl->threshold = 93; - m_aGl->analysisType = e_AUTOCORRELATION; - m_aGl->topPitch = 140.0; - m_aGl->loPitch = 15; - - m_aGl->ampThresholds[AMPLITUDE_RMS][0] = -85.0; m_aGl->ampThresholds[AMPLITUDE_RMS][1] = -0.0; - m_aGl->ampThresholds[AMPLITUDE_MAX_INTENSITY][0] = -30.0; m_aGl->ampThresholds[AMPLITUDE_MAX_INTENSITY][1] = -20.0; - m_aGl->ampThresholds[AMPLITUDE_CORRELATION][0] = 0.40; m_aGl->ampThresholds[AMPLITUDE_CORRELATION][1] = 1.00; - m_aGl->ampThresholds[FREQ_CHANGENESS][0] = 0.50; m_aGl->ampThresholds[FREQ_CHANGENESS][1] = 0.02; - m_aGl->ampThresholds[DELTA_FREQ_CENTROID][0] = 0.00; m_aGl->ampThresholds[DELTA_FREQ_CENTROID][1] = 0.10; - m_aGl->ampThresholds[NOTE_SCORE][0] = 0.03; m_aGl->ampThresholds[NOTE_SCORE][1] = 0.20; - m_aGl->ampThresholds[NOTE_CHANGE_SCORE][0] = 0.12; m_aGl->ampThresholds[NOTE_CHANGE_SCORE][1] = 0.30; - + m_aGl = new TartiniParams(); + m_aGl->chanells = 1; + m_aGl->rate = 44100; + m_aGl->windowSize = 2048; + m_aGl->framesPerChunk = 1; // A trick - setSampleRate() will set it soon + m_aGl->dBFloor = -150.0; // it is unchanged but if it will in conversions.cpp it is hard coded + m_aGl->equalLoudness = true; + m_aGl->doingFreqAnalysis = true; + m_aGl->doingAutoNoiseFloor = true; + m_aGl->doingHarmonicAnalysis = false; + m_aGl->firstTimeThrough = true; + m_aGl->doingDetailedPitch = true; + m_aGl->threshold = 93; + m_aGl->analysisType = e_AUTOCORRELATION; + m_aGl->topPitch = 140.0; + m_aGl->loPitch = 15; + + m_aGl->ampThresholds[AMPLITUDE_RMS][0] = -85.0; m_aGl->ampThresholds[AMPLITUDE_RMS][1] = -0.0; + m_aGl->ampThresholds[AMPLITUDE_MAX_INTENSITY][0] = -30.0; m_aGl->ampThresholds[AMPLITUDE_MAX_INTENSITY][1] = -20.0; + m_aGl->ampThresholds[AMPLITUDE_CORRELATION][0] = 0.40; m_aGl->ampThresholds[AMPLITUDE_CORRELATION][1] = 1.00; + m_aGl->ampThresholds[FREQ_CHANGENESS][0] = 0.50; m_aGl->ampThresholds[FREQ_CHANGENESS][1] = 0.02; + m_aGl->ampThresholds[DELTA_FREQ_CENTROID][0] = 0.00; m_aGl->ampThresholds[DELTA_FREQ_CENTROID][1] = 0.10; + m_aGl->ampThresholds[NOTE_SCORE][0] = 0.03; m_aGl->ampThresholds[NOTE_SCORE][1] = 0.20; + m_aGl->ampThresholds[NOTE_CHANGE_SCORE][0] = 0.12; m_aGl->ampThresholds[NOTE_CHANGE_SCORE][1] = 0.30; + m_framesReady = 0; - m_averVolume = 0.0; + m_averVolume = 0.0; m_currentNote.init(0, 0, 0); - setSampleRate(m_aGl->rate); - m_channel = new Channel(this, aGl()->windowSize); + setSampleRate(m_aGl->rate); + m_channel = new Channel(this, aGl()->windowSize); m_transforms = new MyTransforms(); m_transforms->init(m_aGl, aGl()->windowSize, 0, aGl()->rate); - moveToThread(m_thread); - connect(m_thread, &QThread::started, this, &TpitchFinder::detectingThread); + moveToThread(m_thread); + connect(m_thread, &QThread::started, this, &TpitchFinder::detectingThread); // connect(m_thread, &QThread::finished, this, &TpitchFinder::threadFinished); m_ringBuffer = new qint16[BUFF_SIZE]; // big enough for any circumstances @@ -121,13 +121,13 @@ TpitchFinder::~TpitchFinder() #if !defined (Q_OS_ANDROID) destroyDumpFile(); #endif - if (m_filteredChunk) - delete m_filteredChunk; - delete m_floatBuffer; + if (m_filteredChunk) + delete m_filteredChunk; + delete m_floatBuffer; delete m_transforms; - if (m_channel) - delete m_channel; - delete m_aGl; + if (m_channel) + delete m_channel; + delete m_aGl; delete m_thread; delete m_ringBuffer; } @@ -154,7 +154,7 @@ void TpitchFinder::setSampleRate(unsigned int sRate, int range) { } unsigned int oldRate = m_aGl->rate, oldFramesPerChunk = m_aGl->framesPerChunk; - m_aGl->rate = sRate; + m_aGl->rate = sRate; m_rateRatio = range == 2 ? 2.0 : 1.0; // e_low for 2, for other cases e_middle // switch (range) { // case 0: @@ -164,31 +164,31 @@ void TpitchFinder::setSampleRate(unsigned int sRate, int range) { // default: // m_rateRatio = 1.0; break; // e_middle - lowest pitch is F contra // } -// qDebug() << "m_rateRatio is " << m_rateRatio; +// qDebug() << "m_rateRatio is " << m_rateRatio; if (sRate > 96000) m_aGl->framesPerChunk = static_cast<quint32>(4096 * m_rateRatio); else if (sRate > 48000) m_aGl->framesPerChunk = static_cast<quint32>(2048 * m_rateRatio); else m_aGl->framesPerChunk = static_cast<quint32>(1024 * m_rateRatio); - bool doReset = false; - if (oldRate != m_aGl->rate || oldFramesPerChunk != m_aGl->framesPerChunk) { - m_aGl->windowSize = 2 * m_aGl->framesPerChunk; - delete m_filteredChunk; + bool doReset = false; + if (oldRate != m_aGl->rate || oldFramesPerChunk != m_aGl->framesPerChunk) { + m_aGl->windowSize = 2 * m_aGl->framesPerChunk; + delete m_filteredChunk; m_filteredChunk = 0; - delete m_floatBuffer; - if (aGl()->equalLoudness) - m_filteredChunk = new float[aGl()->framesPerChunk]; - m_floatBuffer = new float[aGl()->framesPerChunk]; - doReset = true; + delete m_floatBuffer; + if (aGl()->equalLoudness) + m_filteredChunk = new float[aGl()->framesPerChunk]; + m_floatBuffer = new float[aGl()->framesPerChunk]; + doReset = true; m_chunkTime = static_cast<qreal>(aGl()->framesPerChunk) / static_cast<qreal>(aGl()->rate); setMinimalDuration(m_minDuration); // recalculate minimum chunks number // qDebug() << "range" << m_rateRatio // << "framesPerChunk" << m_aGl->framesPerChunk << "windowSize" << m_aGl->windowSize // << "min chunks" << m_minChunks << "chunk time" << m_chunkTime << m_framesReady; - } - if (doReset) - resetFinder(); + } + if (doReset) + resetFinder(); } @@ -330,14 +330,14 @@ void TpitchFinder::detectingThread() { void TpitchFinder::startPitchDetection() { m_isBussy = true; if (m_doReset) { // copy last chunk to keep capturing data continuous - resetFinder(); + resetFinder(); if (aGl()->equalLoudness) // initialize channel with previous data std::copy(m_filteredChunk, m_filteredChunk + aGl()->framesPerChunk, m_channel->end() - aGl()->framesPerChunk); else std::copy(m_floatBuffer, m_floatBuffer + aGl()->framesPerChunk, m_channel->end() - aGl()->framesPerChunk); } - m_channel->shift_left(aGl()->framesPerChunk); // make room in channel for new audio data - if (aGl()->equalLoudness) { // filter it and copy to channel + m_channel->shift_left(aGl()->framesPerChunk); // make room in channel for new audio data + if (aGl()->equalLoudness) { // filter it and copy to channel m_channel->highPassFilter->filter(m_floatBuffer, m_filteredChunk, aGl()->framesPerChunk); for(int i = 0; i < aGl()->framesPerChunk; i++) m_filteredChunk[i] = bound(m_filteredChunk[i], -1.0f, 1.0f); @@ -345,20 +345,20 @@ void TpitchFinder::startPitchDetection() { } else // copy without filtering std::copy(m_floatBuffer, m_floatBuffer + aGl()->framesPerChunk, m_channel->end() - aGl()->framesPerChunk); - detect(); + detect(); } void TpitchFinder::processed() { - emit pitchInChunk(m_chunkPitch); - if (m_state != m_prevState) { - if (m_prevState == e_noticed) { + emit pitchInChunk(m_chunkPitch); + if (m_state != m_prevState) { + if (m_prevState == e_noticed) { if (m_state == e_playing) { // qDebug() << "[TpitchFinder] started" << m_currentNote.index << "pitch:" << m_currentNote.pitchF // << "freq:" << m_currentNote.freq << "time:" << m_currentNote.duration * 1000; emit noteStarted(m_currentNote.getAverage(3, minChunksNumber()), m_currentNote.freq, m_currentNote.duration); // new note started - } - } else if (m_prevState == e_playing) { + } + } else if (m_prevState == e_playing) { if (m_state == e_silence || m_state == e_noticed) { // qDebug() << "[TpitchFinder] finished" << m_currentNote.index << "pitch:" << m_currentNote.pitchF // << "freq:" << m_currentNote.freq << "time:" << m_currentNote.duration * 1000; @@ -367,11 +367,11 @@ void TpitchFinder::processed() { m_averVolume = m_currentNote.maxVol; else m_averVolume = (m_averVolume + m_currentNote.maxVol) / 2.0; - } - } - } - m_prevState = m_state; - emit volume(m_volume); + } + } + } + m_prevState = m_state; + emit volume(m_volume); // qDebug() << "[TpitchFinder] processed, volume" << m_volume << "state" << (m_state == e_silence ? "silence" : (m_state == e_noticed ? "noticed" : "playing")); } diff --git a/src/libs/sound/tpitchfinder.h b/src/libs/sound/tpitchfinder.h index 97548ec100da2a366cfc47d63ea9704fadbde7c9..ee9cdb81d4ea1998aecaffdd0b6840dbee9e95c7 100644 --- a/src/libs/sound/tpitchfinder.h +++ b/src/libs/sound/tpitchfinder.h @@ -28,22 +28,22 @@ // This part of code id directly taken from Tartini musicnotes.h -------------------- - /** Converts the frequencies freq (in hertz) into their note number on the midi scale + /** Converts the frequencies freq (in hertz) into their note number on the midi scale i.e. the number of semi-tones above C0 Note: The note's pitch will contain its fractional part Reference = http://www.borg.com/~jglatt/tutr/notenum.htm - @param freq The frequency in Hz - @return The pitch in fractional part semitones from the midi scale. */ + @param freq The frequency in Hz + @return The pitch in fractional part semitones from the midi scale. */ inline qreal freq2pitch(qreal freq) { #ifdef log2 - return -36.3763165622959152488 + 12.0*log2(freq); + return -36.3763165622959152488 + 12.0*log2(freq); #else - return -36.3763165622959152488 + 39.8631371386483481*log10(freq); + return -36.3763165622959152488 + 39.8631371386483481*log10(freq); #endif } - /** Does the opposite of the function above */ + /** Does the opposite of the function above */ inline qreal pitch2freq(qreal note) { return TnoteStruct::pitchToFreq(note); } @@ -56,8 +56,8 @@ class MyTransforms; class QFile; -/** - * The main purpose of this class is to recognize pitch of audio data flowing through it. +/** + * The main purpose of this class is to recognize pitch of audio data flowing through it. * Finding pitch method(s) are taken from Tartini project written by Philip McLeod. * It collects audio data by calling @p copyToBuffer() method, * when buffer is full pitch detection is performed. @@ -70,40 +70,40 @@ class QFile; */ class NOOTKASOUND_EXPORT TpitchFinder : public QObject { - Q_OBJECT - + Q_OBJECT + public: - explicit TpitchFinder(QObject *parent = 0); - virtual ~TpitchFinder(); - - enum EnoteState { - e_silence, // nothing was noticed in processed chunk - probably silence - e_noticed, // note was noticed by Tartini and is loud enough but is too short for Nootka - e_playing // note is playing longer then minimal duration - }; - - /** Those are levels of pitch detection ranges. - * @p e_high - for violin, flute, piccolo - corresponds with treble clef. - * It starts form about F in small octave. - * @p e_middle - for guitars, cello and so - corresponds with treble dropped and bass clefs - * It starts form about F in contra octave. - * @p e_low - for bass guitar and double bass - corresponds with bass dropped clef - * It is sufficient to detect lowest notes. - */ + explicit TpitchFinder(QObject *parent = 0); + virtual ~TpitchFinder(); + + enum EnoteState { + e_silence, // nothing was noticed in processed chunk - probably silence + e_noticed, // note was noticed by Tartini and is loud enough but is too short for Nootka + e_playing // note is playing longer then minimal duration + }; + + /** Those are levels of pitch detection ranges. + * @p e_high - for violin, flute, piccolo - corresponds with treble clef. + * It starts form about F in small octave. + * @p e_middle - for guitars, cello and so - corresponds with treble dropped and bass clefs + * It starts form about F in contra octave. + * @p e_low - for bass guitar and double bass - corresponds with bass dropped clef + * It is sufficient to detect lowest notes. + */ enum Erange { - e_high = 0, - e_middle = 1, - e_low = 2 + e_high = 0, + e_middle = 1, + e_low = 2 }; - - TartiniParams* aGl() { return m_aGl; } /** global settings for pitch recognition. */ - - bool isBussy() { return m_isBussy; } - - int currentChunk() { return m_chunkNum; } - void setCurrentChunk(int curCh) { m_chunkNum = curCh; } - void incrementChunk() { m_chunkNum++; } - + + TartiniParams* aGl() { return m_aGl; } /** global settings for pitch recognition. */ + + bool isBussy() { return m_isBussy; } + + int currentChunk() { return m_chunkNum; } + void setCurrentChunk(int curCh) { m_chunkNum = curCh; } + void incrementChunk() { m_chunkNum++; } + /** * Copies @p nBufferFrames of @p data to buffer. * Parallel thread detects that appropriate amount of audio data is ready @@ -126,41 +126,41 @@ public: */ void stop(bool resetAfter = false); - /** Changes default 44100 sample rate to given value. It takes effect only after resetFinder(). - * @p range is TaudioParams::Erange cast. Default is e_middle - * Better don't call this during processing. */ - void setSampleRate(unsigned int sRate, int range = 1); - - /** Only notes with volume above this value are sending. - * If note has got such volume it is observed till its end - even below. */ - void setMinimalVolume(float vol) { m_minVolume = vol; } + /** Changes default 44100 sample rate to given value. It takes effect only after resetFinder(). + * @p range is TaudioParams::Erange cast. Default is e_middle + * Better don't call this during processing. */ + void setSampleRate(unsigned int sRate, int range = 1); - qreal chunkTime() { return m_chunkTime; } /** Duration time of chunk for current sample rate and frames per chunk. */ - void setMinimalDuration(float dur) { m_minDuration = dur; m_minChunks = qRound((qreal)m_minDuration / m_chunkTime); } - float minimalDuration() { return m_minDuration; } /** Minimum acceptable duration of a note to be pitch-detected. */ - int minChunksNumber() { return m_minChunks; } /** Minimal number of chunks in note to be pitch-detected. */ + /** Only notes with volume above this value are sending. + * If note has got such volume it is observed till its end - even below. */ + void setMinimalVolume(float vol) { m_minVolume = vol; } + + qreal chunkTime() { return m_chunkTime; } /** Duration time of chunk for current sample rate and frames per chunk. */ + void setMinimalDuration(float dur) { m_minDuration = dur; m_minChunks = qRound((qreal)m_minDuration / m_chunkTime); } + float minimalDuration() { return m_minDuration; } /** Minimum acceptable duration of a note to be pitch-detected. */ + int minChunksNumber() { return m_minChunks; } /** Minimal number of chunks in note to be pitch-detected. */ /** Determines whether increased volume of played note split it. * Tartini doesn't detect this so extra checking will be done if @p TRUE. * Volume threshold can be set through @p setSplitValue() */ - void setSplitByVolChange(bool sp) { m_splitByVol = sp; } - bool isSplitByVolume() { return m_splitByVol; } + void setSplitByVolChange(bool sp) { m_splitByVol = sp; } + bool isSplitByVolume() { return m_splitByVol; } - void setSplitVolume(qreal volToSplit) { m_minVolToSplit = qMax<qreal>(volToSplit, 0.05); } - qreal minVolumeToSplit() { return m_minVolToSplit; } + void setSplitVolume(qreal volToSplit) { m_minVolToSplit = qMax<qreal>(volToSplit, 0.05); } + qreal minVolumeToSplit() { return m_minVolToSplit; } /** multiplexer of sound volume (aka %) that determines minimum volume of next note to be pitch-detected. * i.e. - value of 0.8 determines that note has to have at least 80% volume of average volume */ - void setSkipStillerVal(qreal skipStill) { m_skipStillerVal = skipStill; } - qreal skipStillerValue() { return m_skipStillerVal; } - - TnoteStruct* lastNote() { return &m_currentNote; } + void setSkipStillerVal(qreal skipStill) { m_skipStillerVal = skipStill; } + qreal skipStillerValue() { return m_skipStillerVal; } + + TnoteStruct* lastNote() { return &m_currentNote; } /** In offline mode pitch detecting isn't performed in separate thread. * After collecting audio data in buffer, detection is performed * and no data is retrieving until detection in current chunk is finished. */ - bool isOffline() { return m_isOffline; } - void setOffLine(bool off); + bool isOffline() { return m_isOffline; } + void setOffLine(bool off); /** * Pointer to detection processing @p Channel. @@ -168,8 +168,8 @@ public: * In online mode it is reset every 1000 chunks, * only in offline mode all detected data exists. */ - Channel* ch() { return m_channel; } - MyTransforms* transforms() { return m_transforms; } + Channel* ch() { return m_channel; } + MyTransforms* transforms() { return m_transforms; } /** Returns current range of pitch detection */ Erange pitchRange() { if (m_rateRatio == 0.5f) return e_high; else if (m_rateRatio == 2.0f) return e_low; else return e_middle; } @@ -191,25 +191,25 @@ public: signals: void pitchInChunk(float); /** Pitch in chunk that has been just processed */ void volume(float); - void noteStarted(qreal pitch, qreal freq, qreal duration); - void noteFinished(TnoteStruct*); /** Emitting parameters of finished note (pitch, freq, duration) */ - + void noteStarted(qreal pitch, qreal freq, qreal duration); + void noteFinished(TnoteStruct*); /** Emitting parameters of finished note (pitch, freq, duration) */ + protected slots: - void startPitchDetection(); /** Starts searching thread */ - void processed(); /** Performs signal emitting after chunk was done but out of processing thread */ + void startPitchDetection(); /** Starts searching thread */ + void processed(); /** Performs signal emitting after chunk was done but out of processing thread */ void detectingThread(); void threadFinished(); - - + + private: - void detect(); + void detect(); /** Cleans all buffers, sets m_chunkNum to 0. */ void resetFinder(); void createDumpFile(); void destroyDumpFile(); - - + + private: QThread *m_thread; MyTransforms *m_transforms; diff --git a/src/libs/sound/tqtaudioin.h b/src/libs/sound/tqtaudioin.h index 3b9776ba026b8dde92359545d7d4c3cf3f2f61b7..9fd98cd79b7698b0e1076fb15347e4d9f5599add 100644 --- a/src/libs/sound/tqtaudioin.h +++ b/src/libs/sound/tqtaudioin.h @@ -23,7 +23,6 @@ #include "tcommonlistener.h" #include <QtMultimedia/qaudiodeviceinfo.h> -#include <QtCore/qmutex.h> #include <QtCore/qtimer.h> #include <QtCore/qiodevice.h> @@ -78,7 +77,7 @@ public: /** * Returns list of audio input devices filtered by template audio format. */ - static QStringList getAudioDevicesList(); + static QStringList getAudioDevicesList(); void updateAudioParams(); diff --git a/src/libs/sound/trtaudio.cpp b/src/libs/sound/trtaudio.cpp index d18d25603c60419a8ea49b3e5f162d47c7f8d079..0a5fd54bd227ba1a619f16a593e68196849c686e 100755 --- a/src/libs/sound/trtaudio.cpp +++ b/src/libs/sound/trtaudio.cpp @@ -24,44 +24,44 @@ /*static*/ -RtAudio* TrtAudio::m_rtAduio = 0; -RtAudio::StreamParameters* TrtAudio::m_inParams = 0; -RtAudio::StreamParameters* TrtAudio::m_outParams = 0; -RtAudio::StreamOptions* TrtAudio::streamOptions = 0; -quint32 TrtAudio::m_sampleRate = 44100; -quint32 TrtAudio::m_inSR = 48000; -quint32 TrtAudio::m_outSR = 44100; -unsigned int TrtAudio::m_bufferFrames = 1024; -bool TrtAudio::m_isAlsaDefault = false; -QString TrtAudio::m_inDevName = "anything"; -QString TrtAudio::m_outDevName = "anything"; -TrtAudio::callBackType TrtAudio::m_cbIn = 0; -TrtAudio::callBackType TrtAudio::m_cbOut = 0; -TaudioObject* TrtAudio::m_ao = 0; -RtAudioCallback TrtAudio::m_callBack = TrtAudio::duplexCallBack; -bool TrtAudio::m_JACKorASIO = false; -bool TrtAudio::forceUpdate = false; -bool TrtAudio::m_sendPlayingFinished = false; -TrtAudio::EaudioState TrtAudio::m_state = TrtAudio::e_idle; -bool TrtAudio::m_areSplit = true; - -int m_preferredBF = 512; -bool m_audioUpdated = false; +RtAudio* TrtAudio::m_rtAduio = 0; +RtAudio::StreamParameters* TrtAudio::m_inParams = 0; +RtAudio::StreamParameters* TrtAudio::m_outParams = 0; +RtAudio::StreamOptions* TrtAudio::streamOptions = 0; +quint32 TrtAudio::m_sampleRate = 44100; +quint32 TrtAudio::m_inSR = 48000; +quint32 TrtAudio::m_outSR = 44100; +unsigned int TrtAudio::m_bufferFrames = 1024; +bool TrtAudio::m_isAlsaDefault = false; +QString TrtAudio::m_inDevName = "anything"; +QString TrtAudio::m_outDevName = "anything"; +TrtAudio::callBackType TrtAudio::m_cbIn = 0; +TrtAudio::callBackType TrtAudio::m_cbOut = 0; +TaudioObject* TrtAudio::m_ao = 0; +RtAudioCallback TrtAudio::m_callBack = TrtAudio::duplexCallBack; +bool TrtAudio::m_JACKorASIO = false; +bool TrtAudio::forceUpdate = false; +bool TrtAudio::m_sendPlayingFinished = false; +TrtAudio::EaudioState TrtAudio::m_state = TrtAudio::e_idle; +bool TrtAudio::m_areSplit = true; + +int m_preferredBF = 512; +bool m_audioUpdated = false; void TrtAudio::createRtAudio() { - if (m_rtAduio == 0) { // Create RtAudio instance if doesn't exist + if (m_rtAduio == 0) { // Create RtAudio instance if doesn't exist #if defined(Q_OS_WIN) - RtAudio::Api rtAPI; - if ((int)QSysInfo::windowsVersion() < (int)QSysInfo::WV_VISTA) - rtAPI = RtAudio::WINDOWS_DS; // Direct sound for older versions - else // WASAPI since Vista - rtAPI = RtAudio::WINDOWS_WASAPI; - if (m_JACKorASIO) - rtAPI = RtAudio::UNSPECIFIED; // ASIO has a priority + RtAudio::Api rtAPI; + if ((int)QSysInfo::windowsVersion() < (int)QSysInfo::WV_VISTA) + rtAPI = RtAudio::WINDOWS_DS; // Direct sound for older versions + else // WASAPI since Vista + rtAPI = RtAudio::WINDOWS_WASAPI; + if (m_JACKorASIO) + rtAPI = RtAudio::UNSPECIFIED; // ASIO has a priority #elif defined(Q_OS_LINUX) - RtAudio::Api rtAPI; - if (m_JACKorASIO) + RtAudio::Api rtAPI; + if (m_JACKorASIO) rtAPI = RtAudio::UNSPECIFIED; // check is JACK possible and allow it else rtAPI = RtAudio::LINUX_ALSA; // force ALSA @@ -75,62 +75,62 @@ void TrtAudio::createRtAudio() { #endif try { - m_rtAduio = new RtAudio(rtAPI); + m_rtAduio = new RtAudio(rtAPI); m_rtAduio->showWarnings(false); } catch (RtAudioError& e) { qDebug() << "[TrtAudio] Cannot create RtAudio instance" << QString::fromStdString(e.getMessage()); m_rtAduio = 0; } - } + } } QString TrtAudio::currentRtAPI() { - QString rtApiTxt; - if (m_rtAduio) { - switch (getCurrentApi()) { - case RtAudio::WINDOWS_DS: - rtApiTxt = "Direct Sound"; - break; - case RtAudio::WINDOWS_WASAPI: - rtApiTxt = "WAS API"; - break; - case RtAudio::WINDOWS_ASIO: - rtApiTxt = "ASIO"; - break; - case RtAudio::LINUX_ALSA: - rtApiTxt = "ALSA"; - break; - case RtAudio::UNIX_JACK: - rtApiTxt = "JACK"; - break; - case RtAudio::LINUX_PULSE: - rtApiTxt = "pulseaudio"; - break; - case RtAudio::RtAudio::MACOSX_CORE: - rtApiTxt = "CoreAudio"; - break; - default: - rtApiTxt = "Undefined"; - break; - } - } else - rtApiTxt = "RtAudio API doesn't exist"; - return rtApiTxt; + QString rtApiTxt; + if (m_rtAduio) { + switch (getCurrentApi()) { + case RtAudio::WINDOWS_DS: + rtApiTxt = "Direct Sound"; + break; + case RtAudio::WINDOWS_WASAPI: + rtApiTxt = "WAS API"; + break; + case RtAudio::WINDOWS_ASIO: + rtApiTxt = "ASIO"; + break; + case RtAudio::LINUX_ALSA: + rtApiTxt = "ALSA"; + break; + case RtAudio::UNIX_JACK: + rtApiTxt = "JACK"; + break; + case RtAudio::LINUX_PULSE: + rtApiTxt = "pulseaudio"; + break; + case RtAudio::RtAudio::MACOSX_CORE: + rtApiTxt = "CoreAudio"; + break; + default: + rtApiTxt = "Undefined"; + break; + } + } else + rtApiTxt = "RtAudio API doesn't exist"; + return rtApiTxt; } #if !defined (Q_OS_MAC) void TrtAudio::setJACKorASIO(bool jack) { - if (jack != m_JACKorASIO) { - abortStream(); + if (jack != m_JACKorASIO) { + abortStream(); closeStream(); - delete m_rtAduio; - m_rtAduio = 0; - m_JACKorASIO = jack; - createRtAudio(); - } + delete m_rtAduio; + m_rtAduio = 0; + m_JACKorASIO = jack; + createRtAudio(); + } } @@ -171,42 +171,42 @@ void TrtAudio::printSupportedSampleRates(RtAudio::DeviceInfo& devInfo) { TrtAudio::TrtAudio(TaudioParams* audioP, TrtAudio::EdevType type, TrtAudio::callBackType cb) : - m_audioParams(audioP), - m_type(type) + m_audioParams(audioP), + m_type(type) { - if (m_type == e_input) { - m_cbIn = cb; - if (!m_inParams) - m_inParams = new RtAudio::StreamParameters; - } else { - m_cbOut = cb; - if (!m_outParams) - m_outParams = new RtAudio::StreamParameters; - } - if (!streamOptions) { - streamOptions = new RtAudio::StreamOptions; - streamOptions->streamName = "Nootka"; - m_ao = new TaudioObject(); - } - ao()->blockSignals(true); - createRtAudio(); - updateAudioParams(); - ao()->blockSignals(false); + if (m_type == e_input) { + m_cbIn = cb; + if (!m_inParams) + m_inParams = new RtAudio::StreamParameters; + } else { + m_cbOut = cb; + if (!m_outParams) + m_outParams = new RtAudio::StreamParameters; + } + if (!streamOptions) { + streamOptions = new RtAudio::StreamOptions; + streamOptions->streamName = "Nootka"; + m_ao = new TaudioObject(); + } + ao()->blockSignals(true); + createRtAudio(); + updateAudioParams(); + ao()->blockSignals(false); } TrtAudio::~TrtAudio() { -// closeStream(); - if (m_outParams == 0 && m_inParams == 0) { - delete m_rtAduio; - m_rtAduio = 0; - delete streamOptions; - streamOptions = 0; - delete m_ao; - m_ao = 0; - } - +// closeStream(); + if (m_outParams == 0 && m_inParams == 0) { + delete m_rtAduio; + m_rtAduio = 0; + delete streamOptions; + streamOptions = 0; + delete m_ao; + m_ao = 0; + } + } @@ -218,9 +218,9 @@ void TrtAudio::updateAudioParams() { #if defined (Q_OS_LINUX) || defined (Q_OS_WIN) setJACKorASIO(audioParams()->JACKorASIO); #endif - forceUpdate = false; // no more - m_audioUpdated = true; - if (audioParams()->forwardInput || getCurrentApi() == RtAudio::WINDOWS_ASIO) { + forceUpdate = false; // no more + m_audioUpdated = true; + if (audioParams()->forwardInput || getCurrentApi() == RtAudio::WINDOWS_ASIO) { m_areSplit = false; } else { m_areSplit = true; @@ -323,7 +323,7 @@ void TrtAudio::updateAudioParams() { else m_callBack = &duplexCallBack; } - ao()->emitParamsUpdated(); + ao()->emitParamsUpdated(); } @@ -361,7 +361,7 @@ bool TrtAudio::play() { bool TrtAudio::openStream() { - try { + try { if (rtDevice()) { m_bufferFrames = m_preferredBF; // reset when it was overridden by another rt API if (m_areSplit) { @@ -421,15 +421,15 @@ void TrtAudio::apiStopOrClose() { bool TrtAudio::startStream() { - if (!isOpened()) { - if (!openStream()) - return false; + if (!isOpened()) { + if (!openStream()) + return false; } try { if (rtDevice() && !rtDevice()->isStreamRunning()) { rtDevice()->startStream(); // qDebug("stream started"); - } + } } catch (RtAudioError& e) { qDebug() << "[TrtAudio] can't start stream"; return false; @@ -466,7 +466,7 @@ void TrtAudio::closeStream() { void TrtAudio::abortStream() { - try { + try { if (rtDevice() && rtDevice()->isStreamRunning()) { rtDevice()->abortStream(); // qDebug("[TrtAudio] stream aborted"); @@ -582,10 +582,10 @@ quint32 TrtAudio::determineSampleRate(RtAudio::DeviceInfo& devInfo) { if ( sr == 44100 || sr == 48000 || sr == 88200 || sr == 96000 || sr == 176400 || sr == 192000) return sr; } - if (devInfo.sampleRates.size() > 0) - return devInfo.sampleRates.at(devInfo.sampleRates.size() - 1); - else - return 44100; + if (devInfo.sampleRates.size() > 0) + return devInfo.sampleRates.at(devInfo.sampleRates.size() - 1); + else + return 44100; } #if defined(Q_OS_WIN) diff --git a/src/libs/sound/trtaudio.h b/src/libs/sound/trtaudio.h index 3b83c6424b1b5eb17a2a0754f13296b4b6ddc7ea..0d240fd3a112945facbf599c5be9862e0b675131 100755 --- a/src/libs/sound/trtaudio.h +++ b/src/libs/sound/trtaudio.h @@ -16,6 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ***************************************************************************/ + #ifndef TRTAUDIOABSTRACT_H #define TRTAUDIOABSTRACT_H @@ -29,7 +30,7 @@ class TaudioParams; -/** +/** * Common class for RtAudio input/outputs classes. * To get it working, a subclass has to set static call back method of type @p callBackType * where audio data will be send. @@ -48,136 +49,148 @@ class NOOTKASOUND_EXPORT TrtAudio { public: - enum EdevType { e_input, e_output }; - typedef bool (*callBackType)(void*, unsigned int, const RtAudioStreamStatus&); + enum EdevType { e_input, e_output }; + typedef bool (*callBackType)(void*, unsigned int, const RtAudioStreamStatus&); - TrtAudio(TaudioParams *audioP, TrtAudio::EdevType type, TrtAudio::callBackType cb); - ~TrtAudio(); + TrtAudio(TaudioParams *audioP, TrtAudio::EdevType type, TrtAudio::callBackType cb); + ~TrtAudio(); enum EaudioState { e_duplex, e_playing, e_listening, e_idle }; - - QString deviceName() { if (m_type == e_input) return m_inDevName; else return m_outDevName; } - - void open() { openStream(); } - void startAudio() { startStream(); } - void stopAudio() { stopStream(); } - void terminate() { closeStream(); } - static void apiStopOrClose(); /**< This method stops or closes audio stream depends on current API. */ + + QString deviceName() { if (m_type == e_input) return m_inDevName; else return m_outDevName; } + + void open() { openStream(); } + void startAudio() { startStream(); } + void stopAudio() { stopStream(); } + void terminate() { closeStream(); } + static void apiStopOrClose(); /**< This method stops or closes audio stream depends on current API. */ static bool areStreamsSplit() { return m_areSplit; } - + #if defined (Q_OS_LINUX) || defined (Q_OS_WIN) - static void setJACKorASIO(bool jack); - static bool isJACKorASIO() { return m_JACKorASIO; } + static void setJACKorASIO(bool jack); + static bool isJACKorASIO() { return m_JACKorASIO; } - /** Initializes only @p m_JACKorASIO, use it only before any RtAudio instance is created. */ - static void initJACKorASIO(bool useIt) { m_JACKorASIO = useIt; } - - static bool switchAPI(RtAudio::Api rtApi); /**< Deletes current instance and creates a new one with given API. Returns @p TRUE on success. */ + /** + * Initializes only @p m_JACKorASIO, use it only before any RtAudio instance is created. + */ + static void initJACKorASIO(bool useIt) { m_JACKorASIO = useIt; } + + static bool switchAPI(RtAudio::Api rtApi); /**< Deletes current instance and creates a new one with given API. Returns @p TRUE on success. */ #endif - - static void createRtAudio(); /**< Creates RtAudio instance. Once for whole application */ - - static QString& inputName() { return m_inDevName; } - static QString& outputName() { return m_outDevName; } - - void updateAudioParams(); - TaudioParams* audioParams() { return m_audioParams; } - - static void printSupportedFormats(RtAudio::DeviceInfo &devInfo); /**< Prints in console supported audio formats. */ - static void printSupportedSampleRates(RtAudio::DeviceInfo &devInfo); /**< Prints in console supported sample rates. */ - static QString currentRtAPI(); /**< Returns current API of rtAudio device. */ - static unsigned int bufferFrames() { return m_bufferFrames; } /** Number of frames (samples) in single callback */ - - /** Returns instance of RtAudio device. - * It is single instance for entire application */ - static RtAudio* rtDevice() { return m_rtAduio; } - - static quint32 sampleRate() { return m_sampleRate; } /** Common sample rate for duplex callback */ - static quint32 inRate() { return m_inSR; } /** Sample rate of input stream when split */ - static quint32 outRate() { return m_outSR; } /** Sample rate of output stream when split */ - static EaudioState state() { return m_state; } /** Current state of audio device */ - -protected: - static RtAudio::StreamOptions *streamOptions; - RtAudio::StreamParameters* streamParams() { if (m_type == e_input) return m_inParams; else return m_outParams; } - - /** switch that forces updating procedure of audio devices. - * Used when in device is created a few times during run-time. - * Device name is unchanged and it is only case to perform update. */ - static bool forceUpdate; - - void deleteOutParams() { delete m_outParams; m_outParams = 0; } - void deleteInParams() { delete m_inParams; m_inParams = 0; } - - /** Sets pointer to appropriate callback method to 0. */ - void resetCallBack() { if (m_type == e_input) m_cbIn = 0; else m_cbOut = 0; } - - /** Examines available sample rates to check more appropriate. - * 44100 48000 88200 ... 192000. If not the latest from the list is taken. - * @param sampleRate is setting. */ - quint32 determineSampleRate(RtAudio::DeviceInfo& devInfo); - - bool openStream(); - bool startStream(); + + static void createRtAudio(); /**< Creates RtAudio instance. Once for whole application */ + + static QString& inputName() { return m_inDevName; } + static QString& outputName() { return m_outDevName; } + + void updateAudioParams(); + TaudioParams* audioParams() { return m_audioParams; } + + static void printSupportedFormats(RtAudio::DeviceInfo &devInfo); /**< Prints in console supported audio formats. */ + static void printSupportedSampleRates(RtAudio::DeviceInfo &devInfo); /**< Prints in console supported sample rates. */ + static QString currentRtAPI(); /**< Returns current API of rtAudio device. */ + static unsigned int bufferFrames() { return m_bufferFrames; } /**< Number of frames (samples) in single callback */ + + /** + * Returns instance of RtAudio device. + * It is single instance for entire application + */ + static RtAudio* rtDevice() { return m_rtAduio; } + + static quint32 sampleRate() { return m_sampleRate; } /**< Common sample rate for duplex callback */ + static quint32 inRate() { return m_inSR; } /**< Sample rate of input stream when split */ + static quint32 outRate() { return m_outSR; } /**< Sample rate of output stream when split */ + static EaudioState state() { return m_state; } /**< Current state of audio device */ + +protected: + static RtAudio::StreamOptions *streamOptions; + RtAudio::StreamParameters* streamParams() { if (m_type == e_input) return m_inParams; else return m_outParams; } + + /** + * switch that forces updating procedure of audio devices. + * Used when in device is created a few times during run-time. + * Device name is unchanged and it is only case to perform update. + */ + static bool forceUpdate; + + void deleteOutParams() { delete m_outParams; m_outParams = 0; } + void deleteInParams() { delete m_inParams; m_inParams = 0; } + + /** + * Sets pointer to appropriate callback method to 0. + */ + void resetCallBack() { if (m_type == e_input) m_cbIn = 0; else m_cbOut = 0; } + + /** + * Examines available sample rates to check more appropriate. + * 44100 48000 88200 ... 192000. If not the latest from the list is taken. + * @param sampleRate is setting. + */ + quint32 determineSampleRate(RtAudio::DeviceInfo& devInfo); + + bool openStream(); + bool startStream(); bool play(); bool listen(); - static void stopStream(); - static void closeStream(); - static void abortStream(); - static bool isOpened(); /**< Checks rtAudio instance and returns @p TRUE when it is opened. */ - static bool isRunning(); /**< Checks rtAudio instance and returns @p TRUE when it is running. */ - - /** Static instance of 'signal emitter' - * It emits following signals: - * @p streamOpened() - when stream is opening - */ - static TaudioObject* ao() { return m_ao; } - - static bool hasCallBackIn() { return (bool)m_cbIn; } - static bool hasCallBackOut() { return (bool)m_cbOut; } - - static bool getDeviceInfo(RtAudio::DeviceInfo &devInfo, int id); - static RtAudio::Api getCurrentApi(); /**< Returns current RtAudio API is instance exists or @p RtAudio::UNSPECIFIED */ - static unsigned int getDeviceCount(); /**< Returns number of available audio devices or 0 if none or error occurred. */ - static int getDefaultIn(); /**< Returns default input device for current API or -1 if error. */ - static int getDefaultOut(); /**< Returns default output device for current API or -1 if error. */ - - /** Converts device name of @p devInf determining proper encoding which depends on current API. */ - static QString convDevName(RtAudio::DeviceInfo& devInf) { - if (getCurrentApi() == RtAudio::WINDOWS_WASAPI) - return QString::fromUtf8(devInf.name.data()); - else - return QString::fromLocal8Bit(devInf.name.data()); - } + static void stopStream(); + static void closeStream(); + static void abortStream(); + static bool isOpened(); /**< Checks rtAudio instance and returns @p TRUE when it is opened. */ + static bool isRunning(); /**< Checks rtAudio instance and returns @p TRUE when it is running. */ + + /** Static instance of 'signal emitter' + * It emits following signals: + * @p streamOpened() - when stream is opening + */ + static TaudioObject* ao() { return m_ao; } + + static bool hasCallBackIn() { return (bool)m_cbIn; } + static bool hasCallBackOut() { return (bool)m_cbOut; } + + static bool getDeviceInfo(RtAudio::DeviceInfo &devInfo, int id); + static RtAudio::Api getCurrentApi(); /**< Returns current RtAudio API is instance exists or @p RtAudio::UNSPECIFIED */ + static unsigned int getDeviceCount(); /**< Returns number of available audio devices or 0 if none or error occurred. */ + static int getDefaultIn(); /**< Returns default input device for current API or -1 if error. */ + static int getDefaultOut(); /**< Returns default output device for current API or -1 if error. */ + + /** + * Converts device name of @p devInf determining proper encoding which depends on current API. + */ + static QString convDevName(RtAudio::DeviceInfo& devInf) { + if (getCurrentApi() == RtAudio::WINDOWS_WASAPI) + return QString::fromUtf8(devInf.name.data()); + else + return QString::fromLocal8Bit(devInf.name.data()); + } #if defined(Q_OS_WIN) - void restartASIO(); + void restartASIO(); #endif private: - static int duplexCallBack(void *outBuffer, void *inBuffer, unsigned int nBufferFrames, double, RtAudioStreamStatus status, void*); - static int passInputCallBack(void *outBuffer, void *inBuffer, unsigned int nBufferFrames, double, RtAudioStreamStatus status, void*); + static int duplexCallBack(void *outBuffer, void *inBuffer, unsigned int nBufferFrames, double, RtAudioStreamStatus status, void*); + static int passInputCallBack(void *outBuffer, void *inBuffer, unsigned int nBufferFrames, double, RtAudioStreamStatus status, void*); static int playCallBack(void *outBuffer, void*, unsigned int nBufferFrames, double, RtAudioStreamStatus status, void*); static int listenCallBack(void*, void *inBuffer, unsigned int nBufferFrames, double, RtAudioStreamStatus status, void*); - + private: - TaudioParams *m_audioParams; - static RtAudio *m_rtAduio; - EdevType m_type; - static bool m_sendPlayingFinished; - static bool m_areSplit; - static EaudioState m_state; - static QString m_inDevName, m_outDevName; - static RtAudio::StreamParameters *m_inParams; - static RtAudio::StreamParameters *m_outParams; - static quint32 m_sampleRate; /**< Common sample rate (for duplex callback) */ - static quint32 m_inSR, m_outSR; - static unsigned int m_bufferFrames; - static bool m_isAlsaDefault; - static callBackType m_cbIn, m_cbOut; - static TaudioObject *m_ao; - static RtAudioCallback m_callBack; - static bool m_JACKorASIO; + TaudioParams *m_audioParams; + static RtAudio *m_rtAduio; + EdevType m_type; + static bool m_sendPlayingFinished; + static bool m_areSplit; + static EaudioState m_state; + static QString m_inDevName, m_outDevName; + static RtAudio::StreamParameters *m_inParams; + static RtAudio::StreamParameters *m_outParams; + static quint32 m_sampleRate; /**< Common sample rate (for duplex callback) */ + static quint32 m_inSR, m_outSR; + static unsigned int m_bufferFrames; + static bool m_isAlsaDefault; + static callBackType m_cbIn, m_cbOut; + static TaudioObject *m_ao; + static RtAudioCallback m_callBack; + static bool m_JACKorASIO; }; #endif // TRTAUDIOABSTRACT_H diff --git a/src/libs/sound/trtaudioin.cpp b/src/libs/sound/trtaudioin.cpp index f9d71368fe481613683d4eed8070407b5edf28ca..e150148cd2485879ca19545233b783ef413f9bf0 100755 --- a/src/libs/sound/trtaudioin.cpp +++ b/src/libs/sound/trtaudioin.cpp @@ -28,23 +28,23 @@ /*static */ QStringList TaudioIN::getAudioDevicesList() { - QStringList devList; - createRtAudio(); + QStringList devList; + createRtAudio(); if (getCurrentApi() == RtAudio::LINUX_ALSA) closeStream(); // close ALSA stream to get full list of devices - int devCnt = getDeviceCount(); - if (devCnt < 1) - return devList; - for (int i = 0; i < devCnt; i++) { - RtAudio::DeviceInfo devInfo; - if (!getDeviceInfo(devInfo, i)) - continue; - if (devInfo.probed && devInfo.inputChannels > 0) - devList << convDevName(devInfo); - } - if (getCurrentApi() == RtAudio::LINUX_ALSA && !devList.isEmpty()) - devList.prepend("ALSA default"); - return devList; + int devCnt = getDeviceCount(); + if (devCnt < 1) + return devList; + for (int i = 0; i < devCnt; i++) { + RtAudio::DeviceInfo devInfo; + if (!getDeviceInfo(devInfo, i)) + continue; + if (devInfo.probed && devInfo.inputChannels > 0) + devList << convDevName(devInfo); + } + if (getCurrentApi() == RtAudio::LINUX_ALSA && !devList.isEmpty()) + devList.prepend("ALSA default"); + return devList; } @@ -60,7 +60,7 @@ bool TaudioIN::inCallBack(void* inBuff, unsigned int nBufferFrames, const RtAudi -TaudioIN* TaudioIN::m_instance = 0; +TaudioIN* TaudioIN::m_instance = 0; bool TaudioIN::m_goingDelete = false; //################################################################################################# @@ -77,18 +77,18 @@ TaudioIN::TaudioIN(TaudioParams* params, QObject* parent) : } m_instance = this; setAudioInParams(); - m_goingDelete = false; - forceUpdate = true; - - connect(ao(), &TaudioObject::paramsUpdated, this, &TaudioIN::updateSlot); + m_goingDelete = false; + forceUpdate = true; + + connect(ao(), &TaudioObject::paramsUpdated, this, &TaudioIN::updateSlot); connect(ao(), &TaudioObject::playingFinished, this, &TaudioIN::playingFinishedSlot); } TaudioIN::~TaudioIN() { - m_goingDelete = true; + m_goingDelete = true; closeStream(); - finder()->blockSignals(true); + finder()->blockSignals(true); m_instance = 0; deleteInParams(); resetCallBack(); @@ -117,19 +117,19 @@ void TaudioIN::setAudioInParams() { //################################################################################################# void TaudioIN::startListening() { - if (!streamParams()) { - qDebug() << "Can not start listening due to uninitialized input"; - return; - } - if (detectingState() != e_detecting) { + if (!streamParams()) { + qDebug() << "Can not start listening due to uninitialized input"; + return; + } + if (detectingState() != e_detecting) { resetVolume(); if (!stoppedByUser()) { if (areStreamsSplit() && detectingState() != e_detecting) openStream(); if (startStream()) setState(e_detecting); -// qDebug() << "start listening"; - } +// qDebug() << "start listening"; + } } } @@ -139,8 +139,8 @@ void TaudioIN::stopListening() { // qDebug() << "stop listening"; resetVolume(); resetChunkPitch(); - if (areStreamsSplit() || rtDevice()->getCurrentApi() != RtAudio::LINUX_PULSE) - abortStream(); + if (areStreamsSplit() || rtDevice()->getCurrentApi() != RtAudio::LINUX_PULSE) + abortStream(); setState(e_stopped); finder()->stop(true); } diff --git a/src/libs/sound/trtaudioin.h b/src/libs/sound/trtaudioin.h index 86f2ed461ac28b3ca11457aa542dda3e6cf6a3ad..8f3b6d7ec7874e275b9dd9b0f496d4d52f5ba51c 100755 --- a/src/libs/sound/trtaudioin.h +++ b/src/libs/sound/trtaudioin.h @@ -16,6 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ***************************************************************************/ + #ifndef TRTAUDIOIN_H #define TRTAUDIOIN_H @@ -25,7 +26,7 @@ #include "tcommonlistener.h" -/** +/** * This class manages audio input in desktop versions of Nootka. * It works through RtAudio framework */ @@ -39,18 +40,22 @@ public: static TaudioIN* instance() { return m_instance; } - /** Returns list of audio input devices filtered by template audio format */ - static QStringList getAudioDevicesList(); - + /** + * Returns list of audio input devices filtered by template audio format + */ + static QStringList getAudioDevicesList(); + - /** Sets device parameters stores in structure SaudioInParams. - * SaudioInParams::deviceName is ignored. It have to be set separately by setAudioDevice() method. */ - void setAudioInParams(); + /** + * Sets device parameters stores in structure SaudioInParams. + * SaudioInParams::deviceName is ignored. It have to be set separately by setAudioDevice() method. + */ + void setAudioInParams(); public slots: - virtual void startListening(); - virtual void stopListening(); + virtual void startListening(); + virtual void stopListening(); protected: static bool inCallBack(void* inBuff, unsigned int nBufferFrames, const RtAudioStreamStatus& st); @@ -62,13 +67,11 @@ protected: protected slots: void playingFinishedSlot(); - -private: - /** Keeps static pointer of TaudioIN instance. static inCallBack uses it to has access. */ - static TaudioIN* m_instance; - /** is set to @p FALSE when destructor starts. It prevents to performs callbacks routines then. */ - static bool m_goingDelete; - + +private: + static TaudioIN* m_instance; /**< Keeps static pointer of TaudioIN instance. static inCallBack uses it to has access. */ + static bool m_goingDelete; /**< is set to @p FALSE when destructor starts. It prevents to performs callbacks routines then. */ + }; #endif // TRTAUDIOIN_H diff --git a/src/libs/sound/trtaudioout.cpp b/src/libs/sound/trtaudioout.cpp index 5c2b04b094eaeef44a836fae68000d39f2758809..c929f07e1b8ba3c5fc00d2de5b450168c3b43112 100755 --- a/src/libs/sound/trtaudioout.cpp +++ b/src/libs/sound/trtaudioout.cpp @@ -32,8 +32,10 @@ #define SLEEP(msecs) usleep(msecs * 1000) #endif -/** Value of CROSS_STEP = 0.00023 (100ms) cases reverb effect with sound -* Shorter cross-fade duration works better. */ +/** + * Value of CROSS_STEP = 0.00023 (100ms) cases reverb effect with sound + * Shorter cross-fade duration works better. + */ #define CROSS_STEP (0.001f) // cross-fade will take about 23 [ms] - 1000 samples (it determines m_crossBuffer size) @@ -54,46 +56,46 @@ QStringList TaudioOUT::getAudioDevicesList() { devList << convDevName(devInfo); } if (getCurrentApi() == RtAudio::LINUX_ALSA && !devList.isEmpty()) - devList.prepend(QStringLiteral("ALSA default")); + devList.prepend(QStringLiteral("ALSA default")); return devList; } -int TaudioOUT::m_samplesCnt = 0; -int TaudioOUT::m_maxCBloops = 44100 / TrtAudio::bufferFrames() * 2 - 10; -TaudioOUT* TaudioOUT::instance = 0; -qint16* TaudioOUT::m_crossBuffer = 0; -bool TaudioOUT::m_doCrossFade = false; -float TaudioOUT::m_cross = 0.0f; +int TaudioOUT::m_samplesCnt = 0; +int TaudioOUT::m_maxCBloops = 44100 / TrtAudio::bufferFrames() * 2 - 10; +TaudioOUT* TaudioOUT::instance = 0; +qint16* TaudioOUT::m_crossBuffer = 0; +bool TaudioOUT::m_doCrossFade = false; +float TaudioOUT::m_cross = 0.0f; bool TaudioOUT::outCallBack(void* outBuff, unsigned int nBufferFrames, const RtAudioStreamStatus& status) { - instance->m_callBackIsBussy = true; + instance->m_callBackIsBussy = true; // if (status) // It doesn't harm if occurs -// qDebug() << "Stream underflow detected!"; - if (m_doCrossFade) { // Cross-fading avoids cracking during transition of notes. - m_doCrossFade = false; - m_cross = 1.0f; - instance->m_crossCount = 0; - } +// qDebug() << "Stream underflow detected!"; + if (m_doCrossFade) { // Cross-fading avoids cracking during transition of notes. + m_doCrossFade = false; + m_cross = 1.0f; + instance->m_crossCount = 0; + } if (m_samplesCnt < m_maxCBloops) { - m_samplesCnt++; + m_samplesCnt++; qint16 *out = (qint16*)outBuff; int off = m_samplesCnt * (nBufferFrames / instance->ratioOfRate); qint16 sample; for (int i = 0; i < nBufferFrames / instance->ratioOfRate; i++) { - if (m_cross > 0.0 && instance->m_crossCount < 1000) { // mix current and previous samples when cross-fading - sample = (qint16)qRound((1.0 - m_cross) * (float)instance->oggScale->getSample(off + i) + - m_cross * (float)m_crossBuffer[instance->m_crossCount]); - m_cross -= CROSS_STEP; - instance->m_crossCount++; - } else { - sample = instance->oggScale->getSample(off + i); - } - for (int r = 0; r < instance->ratioOfRate; r++) { - *out++ = sample; // left channel - *out++ = sample; // right channel - } + if (m_cross > 0.0 && instance->m_crossCount < 1000) { // mix current and previous samples when cross-fading + sample = (qint16)qRound((1.0 - m_cross) * (float)instance->oggScale->getSample(off + i) + + m_cross * (float)m_crossBuffer[instance->m_crossCount]); + m_cross -= CROSS_STEP; + instance->m_crossCount++; + } else { + sample = instance->oggScale->getSample(off + i); + } + for (int r = 0; r < instance->ratioOfRate; r++) { + *out++ = sample; // left channel + *out++ = sample; // right channel + } } instance->m_callBackIsBussy = false; if (m_samplesCnt == m_maxCBloops) @@ -101,9 +103,9 @@ bool TaudioOUT::outCallBack(void* outBuff, unsigned int nBufferFrames, const RtA else return false; } else { - instance->m_callBackIsBussy = false; + instance->m_callBackIsBussy = false; return true; - } + } } /*end static*/ @@ -124,48 +126,48 @@ TaudioOUT::TaudioOUT(TaudioParams *_params, QObject *parent) : } setType(e_audio); setAudioOutParams(); - m_samplesCnt = 10000; + m_samplesCnt = 10000; instance = this; forceUpdate = true; - m_crossBuffer = new qint16[1000]; + m_crossBuffer = new qint16[1000]; connect(ao(), &TaudioObject::streamOpened, this, &TaudioOUT::streamOpenedSlot); - connect(ao(), &TaudioObject::paramsUpdated, this, &TaudioOUT::updateSlot); + connect(ao(), &TaudioObject::paramsUpdated, this, &TaudioOUT::updateSlot); connect(ao(), &TaudioObject::playingFinished, this, &TaudioOUT::playingFinishedSlot); } -TaudioOUT::~TaudioOUT() +TaudioOUT::~TaudioOUT() { closeStream(); deleteOutParams(); resetCallBack(); delete oggScale; - if (m_crossBuffer) - delete m_crossBuffer; + if (m_crossBuffer) + delete m_crossBuffer; instance = 0; } void TaudioOUT::setAudioOutParams() { -// qDebug() << "setAudioOutParams"; - playable = oggScale->loadAudioData(audioParams()->audioInstrNr); - if (playable && streamParams()) { - ratioOfRate = outRate() / 44100; - quint32 oggSR = outRate(); - if (ratioOfRate > 1) { // - if (outRate() == 88200 || outRate() == 176400) - oggSR = 44100; - else if (outRate() == 96000 || outRate() == 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)); +// qDebug() << "setAudioOutParams"; + playable = oggScale->loadAudioData(audioParams()->audioInstrNr); + if (playable && streamParams()) { + ratioOfRate = outRate() / 44100; + quint32 oggSR = outRate(); + if (ratioOfRate > 1) { // + if (outRate() == 88200 || outRate() == 176400) + oggSR = 44100; + else if (outRate() == 96000 || outRate() == 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)); #if defined(Q_OS_WIN) if (getCurrentApi() == RtAudio::WINDOWS_ASIO) connect(rtDevice()->emitter(), &TASIOEmitter::resetASIO, this, &TaudioOUT::ASIORestartSlot, Qt::UniqueConnection); #endif - } else + } else playable = false; } @@ -178,22 +180,22 @@ void TaudioOUT::streamOpenedSlot() { bool TaudioOUT::play(int noteNr) { if (!playable /*|| audioParams()->forwardInput*/) // if forwarding is enabled play() makes no sense 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); +// qDebug() << "Oops! Call back method is in progress when a new note wants to be played!"; + } + if (m_samplesCnt < m_maxCBloops) { - int off = (m_samplesCnt + 1) * (bufferFrames() / ratioOfRate); // 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) * (bufferFrames() / ratioOfRate); // 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; @@ -217,8 +219,8 @@ void TaudioOUT::playingFinishedSlot() { void TaudioOUT::stop() { - if (areStreamsSplit() || getCurrentApi() == RtAudio::LINUX_PULSE) - closeStream(); + if (areStreamsSplit() || getCurrentApi() == RtAudio::LINUX_PULSE) + closeStream(); else abortStream(); } diff --git a/src/libs/sound/trtaudioout.h b/src/libs/sound/trtaudioout.h index 5dfbcf6fa3742638557936b59c40e6e84f832d01..fee8d81cd813a7f4d50c3e2336e9d72f6c2b605a 100755 --- a/src/libs/sound/trtaudioout.h +++ b/src/libs/sound/trtaudioout.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2013-2014 by Tomasz Bojczuk * + * Copyright (C) 2013-2017 by Tomasz Bojczuk * * seelook@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -28,51 +28,58 @@ class ToggScale; -/** - * +/** + * Nootka audio output */ class NOOTKASOUND_EXPORT TaudioOUT : public TabstractPlayer, public TrtAudio { Q_OBJECT - + public: - TaudioOUT(TaudioParams* _params, QObject* parent = 0); - virtual ~TaudioOUT(); - - static QStringList getAudioDevicesList(); - - /** Starts playing given note and then returns true, otherwise gets false. */ - bool play(int noteNr); - void setAudioOutParams(); - void stop(); /** Immediately stops playing. */ - + TaudioOUT(TaudioParams* _params, QObject* parent = 0); + virtual ~TaudioOUT(); + + static QStringList getAudioDevicesList(); + + /** + * Starts playing given note and then returns true, otherwise gets false. + */ + bool play(int noteNr); + void setAudioOutParams(); + void stop(); + protected: - static bool outCallBack(void* outBuff, unsigned int nBufferFrames, const RtAudioStreamStatus& status); - - int crossCount() { return m_crossCount; } /** counts samples of crossing buffer */ - + static bool outCallBack(void* outBuff, unsigned int nBufferFrames, const RtAudioStreamStatus& status); + + /** + * Counts samples of crossing buffer + */ + int crossCount() { return m_crossCount; } + protected: - /** Static pointer of this class instance to emit signal from callBack method. */ - static TaudioOUT *instance; - ToggScale *oggScale; - int ratioOfRate; // ratio of current sample rate to 44100 + /** + * Static pointer of this class instance to emit signal from callback method. + */ + static TaudioOUT *instance; + ToggScale *oggScale; + int ratioOfRate; /**< ratio of current sample rate to 44100 */ private slots: - void streamOpenedSlot(); - void updateSlot() { setAudioOutParams(); } - void playingFinishedSlot(); + void streamOpenedSlot(); + void updateSlot() { setAudioOutParams(); } + void playingFinishedSlot(); #if defined(Q_OS_WIN) - void ASIORestartSlot(); + void ASIORestartSlot(); #endif - + private: - static int m_samplesCnt; /** Number of performed samples. */ - static int m_maxCBloops; /** Duration of a sound counted in callBack loops */ - static qint16 *m_crossBuffer; /** buffer with data of part of previous note to fade out */ - static bool m_doCrossFade; - static float m_cross; /** current volume factor of fading effect */ - int m_crossCount; - bool m_callBackIsBussy; + static int m_samplesCnt; /**< Number of performed samples. */ + static int m_maxCBloops; /**< Duration of a sound counted in callBack loops */ + static qint16 *m_crossBuffer; /**< buffer with data of part of previous note to fade out */ + static bool m_doCrossFade; + static float m_cross; /**< current volume factor of fading effect */ + int m_crossCount; + bool m_callBackIsBussy; }; diff --git a/src/libs/sound/tsound.cpp b/src/libs/sound/tsound.cpp index 48b165ab7f6b0a758710a55bf4c77a403cfd8eb9..5a706f4fffd6f001cf5ac90c920752057a97741b 100755 --- a/src/libs/sound/tsound.cpp +++ b/src/libs/sound/tsound.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2011-2016 by Tomasz Bojczuk * + * Copyright (C) 2011-2017 by Tomasz Bojczuk * * seelook@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -17,7 +17,6 @@ ***************************************************************************/ #include "tsound.h" -#include "widgets/tpitchview.h" #if defined (Q_OS_ANDROID) #include "tqtaudioin.h" #include "tqtaudioout.h" @@ -29,9 +28,9 @@ #include <tprecisetimer.h> #include <tinitcorelib.h> #include <taudioparams.h> -#include <music/tmelody.h> -#include <QtWidgets/qpushbutton.h> -#include <QtWidgets/qaction.h> +#include "music/tmelody.h" +#include "music/tchunk.h" + #include <QtCore/qdebug.h> /* static */ @@ -54,16 +53,16 @@ Tsound::Tsound(QObject* parent) : qRegisterMetaType<Tchunk>("Tchunk"); qRegisterMetaType<TnoteStruct>("TnoteStruct"); #if !defined (Q_OS_ANDROID) && (defined (Q_OS_LINUX) || defined (Q_OS_WIN)) - TrtAudio::initJACKorASIO(Tcore::gl()->A->JACKorASIO); + TrtAudio::initJACKorASIO(GLOB->A->JACKorASIO); #endif - if (Tcore::gl()->A->OUTenabled) + if (GLOB->A->OUTenabled) createPlayer(); else player = 0; - if (Tcore::gl()->A->INenabled) { - createSniffer(); + if (GLOB->A->INenabled) { + createSniffer(); } else { - sniffer = 0; + sniffer = 0; } } @@ -81,7 +80,7 @@ Tsound::~Tsound() void Tsound::play(Tnote& note) { bool playing = false; if (player && note.note) - playing = player->play(note.chromatic()); + playing = player->play(note.chromatic()); #if defined (Q_OS_ANDROID) if (playing) { if (sniffer) { // stop sniffer if midi output was started @@ -92,12 +91,12 @@ void Tsound::play(Tnote& note) { } } #else - if (playing && !Tcore::gl()->A->playDetected && player->type() == TabstractPlayer::e_midi) { + if (playing && !GLOB->A->playDetected && player->type() == TabstractPlayer::e_midi) { if (sniffer) { // stop sniffer if midi output was started - if (!m_stopSniffOnce) { // stop listening just once - sniffer->stopListening(); - m_stopSniffOnce = true; - } + if (!m_stopSniffOnce) { // stop listening just once + sniffer->stopListening(); + m_stopSniffOnce = true; + } } } #endif @@ -105,9 +104,9 @@ void Tsound::play(Tnote& note) { void Tsound::playMelody(Tmelody* mel) { - if (m_melodyNoteIndex > -1) + if (m_melodyNoteIndex > -1) m_melodyNoteIndex = m_playedMelody->length(); - else { + else { m_melodyNoteIndex = 0; m_playedMelody = mel; } @@ -116,14 +115,14 @@ void Tsound::playMelody(Tmelody* mel) { void Tsound::acceptSettings() { - bool doParamsUpdated = false; + bool doParamsUpdated = false; // for output - if (Tcore::gl()->A->OUTenabled) { + if (GLOB->A->OUTenabled) { if (!player) createPlayer(); else { #if !defined (Q_OS_ANDROID) - if (Tcore::gl()->A->midiEnabled) { + if (GLOB->A->midiEnabled) { deletePlayer(); // it is safe to delete midi createPlayer(); // and create it again } else @@ -139,23 +138,23 @@ void Tsound::acceptSettings() { if (player) { if (!player->isPlayable()) deletePlayer(); - } + } } } else { deletePlayer(); } // for input - if (Tcore::gl()->A->INenabled) { + if (GLOB->A->INenabled) { if (!sniffer) { createSniffer(); - m_pitchView->setAudioInput(sniffer); +// m_pitchView->setAudioInput(sniffer); } else { // m_userState = sniffer->stoppedByUser(); setDefaultAmbitus(); doParamsUpdated = true; } - m_pitchView->setMinimalVolume(Tcore::gl()->A->minimalVol); - m_pitchView->setIntonationAccuracy(Tcore::gl()->A->intonation); +// m_pitchView->setMinimalVolume(GLOB->A->minimalVol); +// m_pitchView->setIntonationAccuracy(GLOB->A->intonation); } else { if (sniffer) deleteSniffer(); @@ -167,46 +166,46 @@ void Tsound::acceptSettings() { sniffer->updateAudioParams(); #else if (doParamsUpdated) { - if (player && player->type() == TabstractPlayer::e_audio) { - static_cast<TaudioOUT*>(player)->updateAudioParams(); + if (player && player->type() == TabstractPlayer::e_audio) { + static_cast<TaudioOUT*>(player)->updateAudioParams(); } else if (sniffer) - sniffer->updateAudioParams(); - } + sniffer->updateAudioParams(); + } #endif - if (sniffer) { + if (sniffer) { restoreSniffer(); - } + } } -void Tsound::setPitchView(TpitchView* pView) { - m_pitchView = pView; - m_pitchView->setPitchColor(Tcore::gl()->EanswerColor); - m_pitchView->setMinimalVolume(Tcore::gl()->A->minimalVol); - m_pitchView->setIntonationAccuracy(Tcore::gl()->A->intonation); - m_pitchView->setAudioInput(sniffer); - - if (sniffer) { -#if defined (Q_OS_ANDROID) - QTimer::singleShot(750, [=]{ m_pitchView->pauseAction()->trigger(); }); -#else - QTimer::singleShot(750, [=]{ sniffer->startListening(); }); -#endif - } -} +// void Tsound::setPitchView(TpitchView* pView) { +// m_pitchView = pView; +// m_pitchView->setPitchColor(GLOB->EanswerColor); +// m_pitchView->setMinimalVolume(GLOB->A->minimalVol); +// m_pitchView->setIntonationAccuracy(GLOB->A->intonation); +// m_pitchView->setAudioInput(sniffer); +// +// if (sniffer) { +// #if defined (Q_OS_ANDROID) +// QTimer::singleShot(750, [=]{ m_pitchView->pauseAction()->trigger(); }); +// #else +// QTimer::singleShot(750, [=]{ sniffer->startListening(); }); +// #endif +// } +// } void Tsound::prepareToConf() { if (player) { - player->stop(); + player->stop(); #if !defined (Q_OS_ANDROID) player->deleteMidi(); #endif - } + } if (sniffer) { m_userState = sniffer->stoppedByUser(); // m_pitchView->isPaused(); sniffer->stopListening(); - m_pitchView->setDisabled(true); +// m_pitchView->setDisabled(true); blockSignals(true); sniffer->setStoppedByUser(false); } @@ -215,7 +214,7 @@ void Tsound::prepareToConf() { void Tsound::restoreAfterConf() { #if !defined (Q_OS_ANDROID) - if (Tcore::gl()->A->midiEnabled) { + if (GLOB->A->midiEnabled) { if (player) player->setMidiParams(); } @@ -226,10 +225,10 @@ void Tsound::restoreAfterConf() { float Tsound::pitch() { - if (sniffer) - return sniffer->lastNotePitch(); - else - return 0.0f; + if (sniffer) + return sniffer->lastNotePitch(); + else + return 0.0f; } @@ -251,8 +250,8 @@ void Tsound::go() { void Tsound::prepareAnswer() { - m_pitchView->setBgColor(Tcore::gl()->EanswerColor); - m_pitchView->setDisabled(false); +// m_pitchView->setBgColor(GLOB->EanswerColor); +// m_pitchView->setDisabled(false); } @@ -281,29 +280,29 @@ bool Tsound::isSniferStopped() { void Tsound::restoreAfterAnswer() { - m_pitchView->setBgColor(Qt::transparent); - m_pitchView->setDisabled(true); +// m_pitchView->setBgColor(Qt::transparent); +// m_pitchView->setDisabled(true); } void Tsound::prepareToExam(Tnote loNote, Tnote hiNote) { m_examMode = true; if (sniffer) { - m_pitchView->setDisabled(true); - m_prevLoNote = sniffer->loNote(); - m_prevHiNote = sniffer->hiNote(); - sniffer->setAmbitus(loNote, hiNote); - } +// m_pitchView->setDisabled(true); + m_prevLoNote = sniffer->loNote(); + m_prevHiNote = sniffer->hiNote(); + sniffer->setAmbitus(loNote, hiNote); + } } void Tsound::restoreAfterExam() { m_examMode = false; if (sniffer) { -// sniffer->setAmbitus(m_prevLoNote, m_prevHiNote); // acceptSettings() has already invoked setDefaultAmbitus() - m_pitchView->setDisabled(false); - unPauseSniffing(); - go(); +// sniffer->setAmbitus(m_prevLoNote, m_prevHiNote); // acceptSettings() has already invoked setDefaultAmbitus() +// m_pitchView->setDisabled(false); + unPauseSniffing(); + go(); } } @@ -311,7 +310,7 @@ void Tsound::restoreAfterExam() { void Tsound::stopPlaying() { if (player) player->stop(); - m_melodyNoteIndex = -1; + m_melodyNoteIndex = -1; } @@ -324,15 +323,15 @@ bool Tsound::isPlayable() { void Tsound::setDefaultAmbitus() { - if (sniffer) - sniffer->setAmbitus(Tnote(Tcore::gl()->loString().chromatic() - 5), // range extended about 4th up and down - Tnote(Tcore::gl()->hiString().chromatic() + Tcore::gl()->GfretsNumber + 5)); + if (sniffer) + sniffer->setAmbitus(Tnote(GLOB->loString().chromatic() - 5), // range extended about 4th up and down + Tnote(GLOB->hiString().chromatic() + GLOB->GfretsNumber + 5)); } #if !defined (Q_OS_ANDROID) void Tsound::setDumpFileName(const QString& fName) { - if (sniffer && !Tcore::gl()->A->dumpPath.isEmpty()) + if (sniffer && !GLOB->A->dumpPath.isEmpty()) sniffer->setDumpFileName(fName); } #endif @@ -345,14 +344,14 @@ void Tsound::setDumpFileName(const QString& fName) { void Tsound::createPlayer() { #if defined (Q_OS_ANDROID) - player = new TaudioOUT(Tcore::gl()->A); + player = new TaudioOUT(GLOB->A); connect(player, SIGNAL(noteFinished()), this, SLOT(playingFinishedSlot())); #else - if (Tcore::gl()->A->midiEnabled) { - player = new TmidiOut(Tcore::gl()->A); + if (GLOB->A->midiEnabled) { + player = new TmidiOut(GLOB->A); connect(player, SIGNAL(noteFinished()), this, SLOT(playingFinishedSlot())); - } else - player = new TaudioOUT(Tcore::gl()->A); + } else + player = new TaudioOUT(GLOB->A); #endif m_stopSniffOnce = false; } @@ -364,11 +363,11 @@ void Tsound::createSniffer() { sniffer = TaudioIN::instance(); else #endif - sniffer = new TaudioIN(Tcore::gl()->A); + sniffer = new TaudioIN(GLOB->A); setDefaultAmbitus(); -// sniffer->setAmbitus(Tnote(-31), Tnote(82)); // fixed ambitus bounded Tartini capacities - connect(sniffer, &TaudioIN::noteStarted, this, &Tsound::noteStartedSlot); - connect(sniffer, &TaudioIN::noteFinished, this, &Tsound::noteFinishedSlot); +// sniffer->setAmbitus(Tnote(-31), Tnote(82)); // fixed ambitus bounded Tartini capacities + connect(sniffer, &TaudioIN::noteStarted, this, &Tsound::noteStartedSlot); + connect(sniffer, &TaudioIN::noteFinished, this, &Tsound::noteFinishedSlot); m_userState = false; // user didn't stop sniffing yet } @@ -376,21 +375,21 @@ void Tsound::createSniffer() { void Tsound::deletePlayer() { if (player) { player->stop(); - delete player; + delete player; player = 0; } } void Tsound::deleteSniffer() { - delete sniffer; + delete sniffer; sniffer = 0; } void Tsound::restoreSniffer() { sniffer->setStoppedByUser(m_userState); - m_pitchView->setDisabled(false); +// m_pitchView->setDisabled(false); blockSignals(false); sniffer->startListening(); } @@ -415,36 +414,36 @@ void Tsound::playingFinishedSlot() { void Tsound::playMelodySlot() { - if (m_melodyNoteIndex > -1 && m_melodyNoteIndex < m_playedMelody->length()) { - play(m_playedMelody->note(m_melodyNoteIndex)->p()); - TpreciseTimer::singleShot(60000 / m_playedMelody->tempo(), this, SLOT(playMelodySlot())); - m_melodyNoteIndex++; - } else { - m_melodyNoteIndex = -1; - playingFinishedSlot(); - } + if (m_melodyNoteIndex > -1 && m_melodyNoteIndex < m_playedMelody->length()) { + play(m_playedMelody->note(m_melodyNoteIndex)->p()); + TpreciseTimer::singleShot(60000 / m_playedMelody->tempo(), this, SLOT(playMelodySlot())); + m_melodyNoteIndex++; + } else { + m_melodyNoteIndex = -1; + playingFinishedSlot(); + } } void Tsound::noteStartedSlot(const TnoteStruct& note) { - m_detectedPitch = note.pitch; - emit noteStarted(m_detectedPitch); + m_detectedPitch = note.pitch; + emit noteStarted(m_detectedPitch); emit noteStartedEntire(note); - if (player && Tcore::gl()->instrument != e_noInstrument && Tcore::gl()->A->playDetected) - play(m_detectedPitch); + if (player && GLOB->instrument().type() != Tinstrument::NoInstrument && GLOB->A->playDetected) + play(m_detectedPitch); } Tchunk m_lastChunk; void Tsound::noteFinishedSlot(const TnoteStruct& note) { - m_detectedPitch = note.pitch; -// Tchunk noteChunk(m_detectedPitch, Trhythm()); + m_detectedPitch = note.pitch; +// Tchunk noteChunk(m_detectedPitch, Trhythm()); m_lastChunk.p() = m_detectedPitch; // m_lastChunk.r() = ; // TODO not supported yet - emit noteFinished(&m_lastChunk); + emit noteFinished(&m_lastChunk); emit noteFinishedEntire(note); - if (player && Tcore::gl()->instrument == e_noInstrument && Tcore::gl()->A->playDetected) - play(m_detectedPitch); + if (player && GLOB->instrument().type() == Tinstrument::NoInstrument && GLOB->A->playDetected) + play(m_detectedPitch); } diff --git a/src/libs/sound/tsound.h b/src/libs/sound/tsound.h index cb6927116caf508df076cb7d4cf9333349f42160..0c5db527ee9eebbf2d27a6fa6baee39cc706065a 100644 --- a/src/libs/sound/tsound.h +++ b/src/libs/sound/tsound.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2011-2016 by Tomasz Bojczuk * + * Copyright (C) 2011-2017 by Tomasz Bojczuk * * seelook@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -30,7 +30,6 @@ class Tchunk; class TnoteStruct; class Tmelody; class TabstractPlayer; -class TpitchView; class TaudioIN; @@ -52,7 +51,7 @@ class NOOTKASOUND_EXPORT Tsound : public QObject Q_OBJECT public: - explicit Tsound(QObject *parent = 0); + explicit Tsound(QObject *parent = nullptr); virtual ~Tsound(); TabstractPlayer *player; @@ -60,49 +59,60 @@ public: static Tsound* instance() { return m_instance; } - void play(Tnote& note); - void playMelody(Tmelody* mel); + void play(Tnote& note); + void playMelody(Tmelody* mel); bool isPlayable(); bool isSniffable() { return (sniffer ? true : false) ; } bool melodyIsPlaying() { return m_melodyNoteIndex > -1; } - TpitchView* pitchView() { return m_pitchView; } /**< First instance existing in main window */ +// TpitchView* pitchView() { return m_pitchView; } /**< First instance existing in main window */ - /** Before Nootka config dialog is created a few things have to be done. + /** + * Before Nootka config dialog is created a few things have to be done. * stop sniffing, playing, delete midi, which blocks audio devices, - * delete audioIN, config creates its own to test. */ + * delete audioIN, config creates its own to test. + */ void prepareToConf(); - void restoreAfterConf(); /**< Also, when user will discard config, it has to restore its state. */ + + /** + * Also, when user will discard config, it has to restore its state. + */ + void restoreAfterConf(); void acceptSettings(); - void setPitchView(TpitchView *pView); +// void setPitchView(TpitchView *pView); void wait(); /**< Stops sniffing. It is called when en exam is starting. */ void go(); /**< Starts sniffing again. */ - Tnote& note() { return m_detectedPitch; } /** Returns recently detected note. */ + /** + * Returns recently detected note. + */ + Tnote& note() { return m_detectedPitch; } float pitch(); /**< Returns recently detected pitch of note. */ void pauseSinffing(); void unPauseSniffing(); bool isSnifferPaused(); bool isSniferStopped(); - /** Prepares sound to exam. - * Given notes in params are level range notes and are put to sniffer ambitus. */ + /** + * Prepares sound to exam. + * Given notes in params are level range notes and are put to sniffer ambitus. + */ void prepareToExam(Tnote loNote, Tnote hiNote); void restoreAfterExam(); void prepareAnswer(); /**< Sets bg color to question color and enables TpitchView. */ void restoreAfterAnswer(); /**< Clears bg color and disables TpitchView. */ void stopPlaying(); - void setDefaultAmbitus(); /**< Instrument scale extended of perfect 4th up and down. */ + void setDefaultAmbitus(); /**< Instrument scale extended of perfect 4th up and down. */ #if !defined (Q_OS_ANDROID) void setDumpFileName(const QString& fName); #endif signals: - void noteStarted(const Tnote&); + void noteStarted(const Tnote&); void noteStartedEntire(const TnoteStruct&); - void noteFinished(Tchunk*); + void noteFinished(Tchunk*); void noteFinishedEntire(const TnoteStruct&); void plaingFinished(); @@ -113,21 +123,20 @@ private: void deleteSniffer(); void restoreSniffer(); /**< Brings back sniffer & pitch view state as such as before settings dialog */ - TpitchView *m_pitchView; - Tnote m_detectedPitch; // detected note pitch - bool m_examMode; - Tnote m_prevLoNote, m_prevHiNote; // notes form sniffer ambitus stored during an exam - bool m_stopSniffOnce, m_userState;; - int m_melodyNoteIndex; - Tmelody *m_playedMelody; - static Tsound *m_instance; + Tnote m_detectedPitch; // detected note pitch + bool m_examMode; + Tnote m_prevLoNote, m_prevHiNote; // notes form sniffer ambitus stored during an exam + bool m_stopSniffOnce, m_userState;; + int m_melodyNoteIndex; + Tmelody *m_playedMelody; + static Tsound *m_instance; private slots: /** Is performed when note stops playing, then sniffing is unlocked */ void playingFinishedSlot(); - void playMelodySlot(); - void noteStartedSlot(const TnoteStruct& note); - void noteFinishedSlot(const TnoteStruct& note); + void playMelodySlot(); + void noteStartedSlot(const TnoteStruct& note); + void noteFinishedSlot(const TnoteStruct& note); }; diff --git a/src/libs/sound/tsoundevent.h b/src/libs/sound/tsoundevent.h deleted file mode 100644 index 42577b8b20c6911694d5d6cd845fe21222aab85b..0000000000000000000000000000000000000000 --- a/src/libs/sound/tsoundevent.h +++ /dev/null @@ -1,55 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2015 by Tomasz Bojczuk * - * seelook@gmail.com * - * * - * 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 3 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, see <http://www.gnu.org/licenses/>. * - ***************************************************************************/ - - -#ifndef TSOUNDEVENT_H -#define TSOUNDEVENT_H - -#include <QEvent> - -/** - * The @class TsoundEvent class is QEvent sends by TaudioIN or TaudioOUT - * to the main qApp instance. - * It informs about audio devices state changes. - * States are available through @p - */ -class TsoundEvent : public QEvent -{ - - Q_GADGET - -public: - enum EsoundEventType { e_playingEvent = User + 108, - e_listeningEvent = User + 109 }; - - TsoundEvent(EsoundEventType t, bool process) : QEvent((Type)t), m_type(t), m_processing(process) {} - - virtual ~TsoundEvent() {} - - bool processing() { return m_processing; } - void setProcessing(bool pl) { m_processing = pl; } - - Type type() const { return (Type)m_type; } - -private: - bool m_processing; - EsoundEventType m_type; - -}; - -#endif // TSOUNDEVENT_H