From 20589f19e4e90513befe1c7e102013bcd542deea Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Sun, 29 Nov 2009 01:33:25 +0100 Subject: [PATCH] Mixer: rewrote processing chain of rendered audio buffers Until now, Mixer not only was responsible for rendering audio buffers but also managed writing them to audio backend (through a FIFO) and handled various quality related parameters. All this functionality has been moved into the new AudioOutputContext class. It glues together AudioBackend (formerly called AudioDevice), global quality settings and the Mixer. The AudioOutputContext class creates a FifoWriter which calls Mixer::renderNextBuffer() and writes the output into the BufferFifo of the AudioOutputContext it belongs to. The BufferFifo is read by the according AudioBackend which belongs to the AudioOutputContext as well. The AudioOutputContext also handles resampling in case the AudioBackend wants the buffers in a different samplerate. During this rewrite the Mixer class and the according source files have been renamed from "mixer" to "Mixer". This results in small changes all over LMMS' code base. --- include/AudioAlsa.h | 8 +- include/{AudioDevice.h => AudioBackend.h} | 93 +++-- include/AudioDummy.h | 26 +- include/AudioFileDevice.h | 8 +- include/AudioFileFlac.h | 7 +- include/AudioFileMp3.h | 7 +- include/AudioFileOgg.h | 7 +- include/AudioFileWave.h | 9 +- include/AudioJack.h | 12 +- include/AudioOss.h | 8 +- include/AudioOutputContext.h | 377 ++++++++++++++++++ include/AudioPort.h | 4 +- include/AudioPortAudio.h | 6 +- include/AudioPulseAudio.h | 8 +- include/AudioSampleRecorder.h | 10 +- include/AudioSdl.h | 10 +- include/Controller.h | 20 +- include/Effect.h | 2 +- include/EffectChain.h | 2 +- include/FxMixer.h | 2 +- include/Instrument.h | 2 +- include/InstrumentSoundShaping.h | 2 +- include/{mixer.h => Mixer.h} | 212 ++-------- include/ProjectRenderer.h | 10 +- include/basic_filters.h | 2 +- include/cpuload_widget.h | 2 +- include/engine.h | 11 +- include/fifo_buffer.h | 89 ----- include/note_play_handle.h | 2 +- include/pch.h | 2 +- include/sample_play_handle.h | 2 +- include/sample_record_handle.h | 2 +- include/setup_dialog.h | 4 +- include/surround_area.h | 2 +- include/visualization_widget.h | 2 +- plugins/ladspa_browser/ladspa_description.cpp | 10 +- plugins/ladspa_browser/ladspa_port_dialog.cpp | 10 +- plugins/ladspa_effect/LadspaEffect.cpp | 18 +- .../ladspa_effect/LadspaSubPluginFeatures.cpp | 7 +- plugins/lb302/lb302.h | 1 - plugins/sf2_player/sf2_player.cpp | 25 +- plugins/vibed/vibrating_string.cpp | 4 +- plugins/vst_base/VstPlugin.h | 1 - src/core/Controller.cpp | 2 +- src/core/ControllerConnection.cpp | 1 - src/core/Effect.cpp | 6 +- src/core/EnvelopeAndLfoParameters.cpp | 2 +- src/core/LfoController.cpp | 1 - src/core/{mixer.cpp => Mixer.cpp} | 345 ++++------------ src/core/Oscillator.cpp | 8 +- src/core/PeakController.cpp | 1 - src/core/Plugin.cpp | 1 - src/core/ProjectRenderer.cpp | 116 +++--- src/core/RemotePlugin.cpp | 2 +- src/core/audio/AudioAlsa.cpp | 25 +- src/core/audio/AudioBackend.cpp | 144 +++++++ src/core/audio/AudioDevice.cpp | 208 ---------- src/core/audio/AudioFileDevice.cpp | 4 +- src/core/audio/AudioFileFlac.cpp | 4 +- src/core/audio/AudioFileMp3.cpp | 4 +- src/core/audio/AudioFileOgg.cpp | 4 +- src/core/audio/AudioFileWave.cpp | 6 +- src/core/audio/AudioJack.cpp | 20 +- src/core/audio/AudioOss.cpp | 24 +- src/core/audio/AudioOutputContext.cpp | 311 +++++++++++++++ src/core/audio/AudioPort.cpp | 11 +- src/core/audio/AudioPortAudio.cpp | 4 +- src/core/audio/AudioPulseAudio.cpp | 29 +- src/core/audio/AudioSampleRecorder.cpp | 30 +- src/core/audio/AudioSdl.cpp | 18 +- src/core/engine.cpp | 10 +- src/core/main.cpp | 39 +- src/core/midi/MidiControlListener.cpp | 1 - src/core/midi/MidiController.cpp | 1 - src/core/sample_buffer.cpp | 2 +- src/gui/ExportProjectDialog.cpp | 11 +- src/gui/MainWindow.cpp | 8 +- src/gui/setup_dialog.cpp | 1 - src/gui/song_editor.cpp | 5 +- src/gui/widgets/EnvelopeAndLfoView.cpp | 4 +- src/gui/widgets/InstrumentMidiIOView.cpp | 4 +- src/gui/widgets/cpuload_widget.cpp | 8 +- src/gui/widgets/visualization_widget.cpp | 30 +- src/tracks/bb_track.cpp | 2 +- src/tracks/pattern.cpp | 25 +- 85 files changed, 1379 insertions(+), 1151 deletions(-) rename include/{AudioDevice.h => AudioBackend.h} (60%) create mode 100644 include/AudioOutputContext.h rename include/{mixer.h => Mixer.h} (58%) rename src/core/{mixer.cpp => Mixer.cpp} (76%) create mode 100644 src/core/audio/AudioBackend.cpp delete mode 100644 src/core/audio/AudioDevice.cpp create mode 100644 src/core/audio/AudioOutputContext.cpp diff --git a/include/AudioAlsa.h b/include/AudioAlsa.h index 6e194cf77..a2a645c9f 100644 --- a/include/AudioAlsa.h +++ b/include/AudioAlsa.h @@ -34,17 +34,17 @@ #include -#include "AudioDevice.h" +#include "AudioBackend.h" class lcdSpinBox; class QComboBox; -class AudioAlsa : public AudioDevice, public QThread +class AudioAlsa : public AudioBackend, public QThread { public: - AudioAlsa( bool & _success_ful, mixer * _mixer ); + AudioAlsa( bool & _success_ful, AudioOutputContext * context ); virtual ~AudioAlsa(); inline static QString name() @@ -56,7 +56,7 @@ public: static QString probeDevice(); - class setupWidget : public AudioDevice::setupWidget + class setupWidget : public AudioBackend::setupWidget { public: setupWidget( QWidget * _parent ); diff --git a/include/AudioDevice.h b/include/AudioBackend.h similarity index 60% rename from include/AudioDevice.h rename to include/AudioBackend.h index 660e2ca01..10d17c2da 100644 --- a/include/AudioDevice.h +++ b/include/AudioBackend.h @@ -1,5 +1,5 @@ /* - * AudioDevice.h - base-class for audio-devices, used by LMMS-mixer + * AudioBackend.h - base-class for audio-devices, used by LMMS-mixer * * Copyright (c) 2004-2009 Tobias Doerffel * @@ -26,37 +26,31 @@ #define _AUDIO_DEVICE_H #include -#include #include -#include "mixer.h" +#include "Mixer.h" #include "tab_widget.h" class AudioPort; - -class AudioDevice +/*! \brief The AudioBackend class is the base class for all kinds of AudioBackends. + * + * All classes derived from AudioBackend receive audio data so they can output + * it. + */ +class AudioBackend { public: - AudioDevice( const ch_cnt_t _channels, mixer * _mixer ); - virtual ~AudioDevice(); + /*! \brief Constructs an AudioBackend object for the given AudioOutputContext. */ + AudioBackend( const ch_cnt_t _channels, AudioOutputContext * context ); + virtual ~AudioBackend(); - inline void lock() - { - m_devMutex.lock(); - } - - inline void unlock() - { - m_devMutex.unlock(); - } - - - // if audio-driver supports ports, classes inherting AudioPort - // (e.g. channel-tracks) can register themselves for making - // audio-driver able to collect their individual output and provide - // them at a specific port - currently only supported by JACK + /*! If the audio backend supports ports, classes creating an AudioPort + * (e.g. InstrumentTrack) can register themselves for making + * audio backend able to collect their individual output and provide + * them at a specific port - currently only supported by JACK + */ virtual void registerPort( AudioPort * _port ); virtual void unregisterPort( AudioPort * _port ); virtual void renamePort( AudioPort * _port ); @@ -77,11 +71,14 @@ public: return m_channels; } - void processNextBuffer(); + /*! \brief Fetches one buffer and writes it to output device. + * + * \return Number of frames processed + */ + int processNextBuffer(); virtual void startProcessing() { - m_inProcess = true; } virtual void stopProcessing(); @@ -115,41 +112,47 @@ public: } ; + /*! \brief Returns const pointer to AudioOutputContext this AudioBackend acts for. */ + const AudioOutputContext * outputContext() const + { + return m_context; + } + + /*! \brief Returns const pointer to Mixer this AudioBackend acts for. */ + const Mixer * mixer() const; + protected: - // subclasses can re-implement this for being used in conjunction with - // processNextBuffer() + /*! \brief Writes given buffer to actual device. + * + * Subclasses can reimplement this for being used in conjunction with + * processNextBuffer() + */ virtual void writeBuffer( const sampleFrameA * /* _buf*/, const fpp_t /*_frames*/, const float /*_master_gain*/ ) { } - // called by according driver for fetching new sound-data - fpp_t getNextBuffer( sampleFrameA * _ab ); + /*! \brief Called by according backend for fetching new audio data. */ + int getNextBuffer( sampleFrameA * _ab ); - // clear given signed-int-16-buffer + /*! \brief Clears given signed-int-16-buffer. */ void clearS16Buffer( intSampleFrameA * _outbuf, const fpp_t _frames ); - // resample given buffer from samplerate _src_sr to samplerate _dst_sr - void resample( const sampleFrameA * _src, - const fpp_t _frames, - sampleFrameA * _dst, - const sample_rate_t _src_sr, - const sample_rate_t _dst_sr ); - inline void setSampleRate( const sample_rate_t _new_sr ) { m_sampleRate = _new_sr; } - mixer * getMixer() - { - return m_mixer; - } - bool hqAudio() const; + AudioOutputContext * outputContext() + { + return m_context; + } + + Mixer * mixer(); protected: @@ -157,15 +160,9 @@ protected: private: + AudioOutputContext * m_context; sample_rate_t m_sampleRate; ch_cnt_t m_channels; - mixer * m_mixer; - bool m_inProcess; - - QMutex m_devMutex; - - SRC_DATA m_srcData; - SRC_STATE * m_srcState; sampleFrameA * m_buffer; diff --git a/include/AudioDummy.h b/include/AudioDummy.h index 2a38bd622..324b08c85 100644 --- a/include/AudioDummy.h +++ b/include/AudioDummy.h @@ -25,16 +25,16 @@ #ifndef _AUDIO_DUMMY_H #define _AUDIO_DUMMY_H -#include "AudioDevice.h" +#include "AudioBackend.h" #include "Cpu.h" #include "MicroTimer.h" -class AudioDummy : public AudioDevice, public QThread +class AudioDummy : public AudioBackend, public QThread { public: - AudioDummy( bool & _success_ful, mixer * _mixer ) : - AudioDevice( DEFAULT_CHANNELS, _mixer ) + AudioDummy( bool & _success_ful, AudioOutputContext * context ) : + AudioBackend( DEFAULT_CHANNELS, context ) { _success_ful = true; } @@ -50,11 +50,11 @@ public: } - class setupWidget : public AudioDevice::setupWidget + class setupWidget : public AudioBackend::setupWidget { public: setupWidget( QWidget * _parent ) : - AudioDevice::setupWidget( AudioDummy::name(), _parent ) + AudioBackend::setupWidget( AudioDummy::name(), _parent ) { } @@ -93,27 +93,25 @@ private: virtual void run() { MicroTimer timer; + sampleFrameA * buf = CPU::allocFrames( mixer()->framesPerPeriod() ); while( true ) { timer.reset(); - surroundSampleFrame * b = - getMixer()->nextBuffer(); - if( !b ) + int frames = getNextBuffer( buf ); + if( frames == 0 ) { break; } - CPU::freeFrames( b ); const Sint32 microseconds = static_cast( - getMixer()->framesPerPeriod() * - 1000000.0f / - getMixer()->processingSampleRate() - - timer.elapsed() ); + mixer()->framesPerPeriod() * 1000000.0f / + mixer()->processingSampleRate() - timer.elapsed() ); if( microseconds > 0 ) { usleep( microseconds ); } } + CPU::freeFrames( buf ); } } ; diff --git a/include/AudioFileDevice.h b/include/AudioFileDevice.h index cbc30b28f..b3ea33968 100644 --- a/include/AudioFileDevice.h +++ b/include/AudioFileDevice.h @@ -28,10 +28,10 @@ #include -#include "AudioDevice.h" +#include "AudioBackend.h" -class AudioFileDevice : public AudioDevice +class AudioFileDevice : public AudioBackend { public: AudioFileDevice( const sample_rate_t _sample_rate, @@ -41,7 +41,7 @@ public: const bitrate_t _min_bitrate, const bitrate_t _max_bitrate, const int _depth, - mixer * _mixer ); + AudioOutputContext * context ); virtual ~AudioFileDevice(); QString outputFile() const @@ -108,7 +108,7 @@ typedef AudioFileDevice * ( * AudioFileDeviceInstantiaton ) const bitrate_t _min_bitrate, const bitrate_t _max_bitrate, const int _depth, - mixer * _mixer ); + AudioOutputContext * mixer ); #endif diff --git a/include/AudioFileFlac.h b/include/AudioFileFlac.h index dd8ec6643..aaa3b2eeb 100644 --- a/include/AudioFileFlac.h +++ b/include/AudioFileFlac.h @@ -48,7 +48,7 @@ public: const bitrate_t _min_bitrate, const bitrate_t _max_bitrate, const int _depth, - mixer * _mixer ); + AudioOutputContext * context ); virtual ~AudioFileFlac(); static AudioFileDevice * getInst( const sample_rate_t _sample_rate, @@ -60,13 +60,12 @@ public: const bitrate_t _min_bitrate, const bitrate_t _max_bitrate, const int _depth, - mixer * _mixer ) + AudioOutputContext * context ) { return new AudioFileFlac( _sample_rate, _channels, _success_ful, _file, _use_vbr, _nom_bitrate, _min_bitrate, - _max_bitrate, _depth, - _mixer ); + _max_bitrate, _depth, context ); } diff --git a/include/AudioFileMp3.h b/include/AudioFileMp3.h index 7379fa4fa..6b5b6d8ea 100644 --- a/include/AudioFileMp3.h +++ b/include/AudioFileMp3.h @@ -44,7 +44,7 @@ public: const bitrate_t _min_bitrate, const bitrate_t _max_bitrate, const int _depth, - mixer * _mixer ); + AudioOutputContext * context ); virtual ~AudioFileMp3(); static AudioFileDevice * getInst( const sample_rate_t _sample_rate, @@ -56,13 +56,12 @@ public: const bitrate_t _min_bitrate, const bitrate_t _max_bitrate, const int _depth, - mixer * _mixer ) + AudioOutputContext * context ) { return new AudioFileMp3( _sample_rate, _channels, _success_ful, _file, _use_vbr, _nom_bitrate, _min_bitrate, - _max_bitrate, _depth, - _mixer ); + _max_bitrate, _depth, context ); } diff --git a/include/AudioFileOgg.h b/include/AudioFileOgg.h index 8ea9b9d51..363fbf8ab 100644 --- a/include/AudioFileOgg.h +++ b/include/AudioFileOgg.h @@ -47,7 +47,7 @@ public: const bitrate_t _min_bitrate, const bitrate_t _max_bitrate, const int _depth, - mixer * _mixer ); + AudioOutputContext * context ); virtual ~AudioFileOgg(); static AudioFileDevice * getInst( const sample_rate_t _sample_rate, @@ -59,12 +59,11 @@ public: const bitrate_t _min_bitrate, const bitrate_t _max_bitrate, const int _depth, - mixer * _mixer ) + AudioOutputContext * context ) { return new AudioFileOgg( _sample_rate, _channels, _success_ful, _file, _use_vbr, _nom_bitrate, - _min_bitrate, _max_bitrate, - _depth, _mixer ); + _min_bitrate, _max_bitrate, _depth, context ); } diff --git a/include/AudioFileWave.h b/include/AudioFileWave.h index 6446e35f6..eabe56d4a 100644 --- a/include/AudioFileWave.h +++ b/include/AudioFileWave.h @@ -1,5 +1,5 @@ /* - * AudioFileWave.h - AudioDevice which encodes wave-stream and writes it + * AudioFileWave.h - AudioBackend which encodes wave-stream and writes it * into a WAVE-file. This is used for song-export. * * Copyright (c) 2004-2009 Tobias Doerffel @@ -44,7 +44,7 @@ public: const bitrate_t _min_bitrate, const bitrate_t _max_bitrate, const int _depth, - mixer * _mixer ); + AudioOutputContext * context ); virtual ~AudioFileWave(); static AudioFileDevice * getInst( const sample_rate_t _sample_rate, @@ -56,13 +56,12 @@ public: const bitrate_t _min_bitrate, const bitrate_t _max_bitrate, const int _depth, - mixer * _mixer ) + AudioOutputContext * context ) { return new AudioFileWave( _sample_rate, _channels, _success_ful, _file, _use_vbr, _nom_bitrate, _min_bitrate, - _max_bitrate, _depth, - _mixer ); + _max_bitrate, _depth, context ); } diff --git a/include/AudioJack.h b/include/AudioJack.h index e9c018a95..86217d1ae 100644 --- a/include/AudioJack.h +++ b/include/AudioJack.h @@ -31,22 +31,22 @@ #include #endif -#include -#include #include +#include +#include -#include "AudioDevice.h" +#include "AudioBackend.h" class QLineEdit; class lcdSpinBox; -class AudioJack : public QObject, public AudioDevice +class AudioJack : public QObject, public AudioBackend { Q_OBJECT public: - AudioJack( bool & _success_ful, mixer * _mixer ); + AudioJack( bool & _success_ful, AudioOutputContext * context ); virtual ~AudioJack(); inline static QString name() @@ -56,7 +56,7 @@ public: } - class setupWidget : public AudioDevice::setupWidget + class setupWidget : public AudioBackend::setupWidget { public: setupWidget( QWidget * _parent ); diff --git a/include/AudioOss.h b/include/AudioOss.h index 293694fe4..997b60657 100644 --- a/include/AudioOss.h +++ b/include/AudioOss.h @@ -29,17 +29,17 @@ #ifdef LMMS_HAVE_OSS -#include "AudioDevice.h" +#include "AudioBackend.h" class lcdSpinBox; class QLineEdit; -class AudioOss : public AudioDevice, public QThread +class AudioOss : public AudioBackend, public QThread { public: - AudioOss( bool & _success_ful, mixer * _mixer ); + AudioOss( bool & _success_ful, AudioOutputContext * context ); virtual ~AudioOss(); inline static QString name() @@ -50,7 +50,7 @@ public: static QString probeDevice(); - class setupWidget : public AudioDevice::setupWidget + class setupWidget : public AudioBackend::setupWidget { public: setupWidget( QWidget * _parent ); diff --git a/include/AudioOutputContext.h b/include/AudioOutputContext.h new file mode 100644 index 000000000..8bd57ac38 --- /dev/null +++ b/include/AudioOutputContext.h @@ -0,0 +1,377 @@ +/* + * AudioOutputContext.h - centralize all audio output related functionality + * + * Copyright (c) 2009 Tobias Doerffel + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#ifndef _AUDIO_OUTPUT_CONTEXT_H +#define _AUDIO_OUTPUT_CONTEXT_H + +#include +#include + +#include "Mixer.h" + +class AudioBackend; + +/*! \brief The AudioOutputContext class centralizes all functionality + * and data related to output of audio data. + * + * The process of audio output is rather complicated due to different kinds of + * AudioBackend implementations, FIFO buffering and dedicated quality settings. + * The AudioOutputContext class handles all this so the Mixer class can just + * deal with actual audio rendering and processing. + */ +class AudioOutputContext +{ +public: + /*! \brief The QualitySettings class holds quality related settings. + * + * There's nothing special about it. It's just a data aggregration class. + */ + class QualitySettings + { + public: + /*! Lists all quality presets. */ + enum Preset + { + Preset_Draft, /*!< Draft quality - used for editing project */ + Preset_HighQuality, /*!< High quality - standard setting for project export */ + Preset_FinalMix, /*!< Final mix quality - very slow, best quality */ + NumPresets + } ; + + /*! Lists all supported interpolation types. */ + enum Interpolation + { + Interpolation_Linear, /*!< Linear interpolation - fast */ + Interpolation_SincFastest, /*!< Fastest Sinc interpolation - good quality */ + Interpolation_SincMedium, /*!< Medium Sinc interpolation - better quality */ + Interpolation_SincBest /*!< High quality interpolation */ + } ; + + /*! Lists all supported oversampling ratios. */ + enum Oversampling + { + Oversampling_None, /*!< No oversampling - fast */ + Oversampling_2x, /*!< 2x oversampling - good quality */ + Oversampling_4x, /*!< 4x oversampling - better quality */ + Oversampling_8x /*!< 8x oversampling - best quality but might break some filters */ + } ; + + /*! \brief Constructs a QualitySettings object based on a given preset. */ + QualitySettings( Preset m ) + { + switch( m ) + { + case Preset_Draft: + m_interpolation = Interpolation_Linear; + m_oversampling = Oversampling_None; + m_sampleExactControllers = false; + m_aliasFreeOscillators = false; + break; + case Preset_HighQuality: + m_interpolation = Interpolation_SincFastest; + m_oversampling = Oversampling_2x; + m_sampleExactControllers = true; + m_aliasFreeOscillators = false; + break; + case Preset_FinalMix: + m_interpolation = Interpolation_SincBest; + m_oversampling = Oversampling_8x; + m_sampleExactControllers = true; + m_aliasFreeOscillators = true; + break; + default: + break; + } + } + + /*! \brief Constructs a QualitySettings object based on specific quality settings. */ + QualitySettings( Interpolation _i, Oversampling _o, bool _sec, + bool _afo ) : + m_interpolation( _i ), + m_oversampling( _o ), + m_sampleExactControllers( _sec ), + m_aliasFreeOscillators( _afo ) + { + } + + /*! \brief Returns multiplier for sample rate based on oversampling settings. */ + int sampleRateMultiplier() const + { + switch( oversampling() ) + { + case Oversampling_None: return 1; + case Oversampling_2x: return 2; + case Oversampling_4x: return 4; + case Oversampling_8x: return 8; + } + return 1; + } + + /*! \brief Maps interpolation setting to libsamplerate constants. */ + int libsrcInterpolation() const + { + switch( interpolation() ) + { + case Interpolation_Linear: + return SRC_ZERO_ORDER_HOLD; + case Interpolation_SincFastest: + return SRC_SINC_FASTEST; + case Interpolation_SincMedium: + return SRC_SINC_MEDIUM_QUALITY; + case Interpolation_SincBest: + return SRC_SINC_BEST_QUALITY; + } + return SRC_LINEAR; + } + + /*! \brief Returns current interpolation setting. */ + Interpolation interpolation() const + { + return m_interpolation; + } + + /*! \brief Sets a new interpolation method. */ + void setInterpolation( Interpolation interpolation ) + { + m_interpolation = interpolation; + } + + /*! \brief Returns current oversampling setting. */ + Oversampling oversampling() const + { + return m_oversampling; + } + + /*! \brief Sets a new oversampling factor. */ + void setOversampling( Oversampling oversampling ) + { + m_oversampling = oversampling; + } + + /*! \brief Returns whether to use sample exact controllers. */ + bool sampleExactControllers() const + { + return m_sampleExactControllers; + } + + /*! \brief Returns whether to use alias free oscillators. */ + bool aliasFreeOscillators() const + { + return m_aliasFreeOscillators; + } + + private: + Interpolation m_interpolation; + Oversampling m_oversampling; + bool m_sampleExactControllers; + bool m_aliasFreeOscillators; + + } ; + + /*! \brief The BufferFifo class provides an internal FIFO for rendered buffers. + * + * When working with buffer sizes greater than the default buffer size, one + * big output buffer is still splitted into smaller chunks. This is + * especially neccessary for automation which takes place once a buffer + * period. Transitions would be anything else but smooth when adjusting a + * control just 20 times per second. BufferFifo handles the queueing of + * rendered buffers. */ + class BufferFifo + { + public: + /*! Each buffer in the FIFO can have a special state. This is used + * by FifoWriter to inject NULL buffers to indicate, the FIFO has + * been emptied after FifoWriter was told to finish. */ + enum BufferStates + { + Running, /*!< Regular buffer */ + NullBuffer /*!< Even if the buffer returned by currentReadBuffer() + * is not NULL, the FIFO input was NULL. FIFO reader can + * use this information for own purposes. */ + } ; + typedef BufferStates BufferState; + + /*! \brief Constructs a new BufferFifo object. + * + * \param size The number of buffers in the FIFO + * \param bufferSize The size of each buffer in the FIFO + */ + BufferFifo( int size, int bufferSize ); + ~BufferFifo(); + + /*! \brief Pushes a new buffer into the FIFO. + * + * You can also push NULL which will set the according buffer state + * to HasNullBuffer. */ + void write( sampleFrameA * buffer ); + + /*! \brief Prepares for reading next buffer (might block until one is available). */ + void startRead(); + + /*! \brief Returns current front buffer for reading. */ + sampleFrameA * currentReadBuffer() const + { + return m_buffers[m_readerIndex]; + } + + /*! \brief Returns state of current front buffer. */ + BufferState currentReadBufferState() const + { + return m_bufferStates[m_readerIndex]; + } + + /*! \brief Finish the current buffer read operation. + * + * The buffer returned by currentReadBuffer() is not guaranteed to + * be valid anymore after calling this function. */ + void finishRead(); + + /*! \brief Returns whether FIFO is empty. */ + bool isEmpty() const + { + return m_readerSem.available() == false; + } + + + private: + QSemaphore m_readerSem; + QSemaphore m_writerSem; + int m_readerIndex; + int m_writerIndex; + int m_size; + int m_bufferSize; + sampleFrameA * * m_buffers; + BufferState * m_bufferStates; + + } ; + + /*! \brief The FifoWriter class provides an internal thread for feeding + * the FIFO read by the active AudioBackend */ + class FifoWriter : public QThread + { + public: + FifoWriter( AudioOutputContext * context ); + + void finish(); + + + private: + AudioOutputContext * m_context; + volatile bool m_writing; + + virtual void run(); + + } ; + + /*! \brief Constructs an AudioOutputContext object for given AudioBackend. + * + * \param mixer The Mixer instance to fetch audio data from + * \param audioBackend The AudioBackend to write audio data to + * \param qualitySettings A QualitySettings object describing desired quality + */ + AudioOutputContext( Mixer * mixer, + AudioBackend * audioBackend, + const QualitySettings & qualitySettings ); + ~AudioOutputContext(); + + /*! \brief Sets an AudioBackend for this context. */ + void setAudioBackend( AudioBackend * backend ) + { + m_audioBackend = backend; + } + + /*! \brief Returns AudioBackend used by this context. */ + AudioBackend * audioBackend() + { + return m_audioBackend; + } + + /*! \brief Returns const AudioBackend used by this context. */ + const AudioBackend * audioBackend() const + { + return m_audioBackend; + } + + /*! \brief Returns Mixer used by this context. */ + Mixer * mixer() + { + return m_mixer; + } + + /*! \brief Returns const Mixer used by this context. */ + const Mixer * mixer() const + { + return m_mixer; + } + + /*! \brief Returns BufferFifo object used by this context. */ + BufferFifo * fifo() + { + return m_fifo; + } + + /*! \brief Returns current quality settings. */ + const QualitySettings & qualitySettings() const + { + return m_qualitySettings; + } + + /*! \brief Starts audio processing in this context. */ + void startProcessing(); + + /*! \brief Stops audio processing in this context. */ + void stopProcessing(); + + /*! \brief Returns whether audio processing in this context is running. */ + bool isProcessing() const; + + /*! \brief Copies current output buffer to destination buffer and optionally + * does resampling. + * + * If the Mixer has a running FifoWriter, it will make the FifoWriter start + * rendering the next buffer so it can be read from the Fifo next period + * without any delay. If the desired sample rate does not match current + * processing sample rate, resampling will be done. + * \param destBuffer The (aligned) destination buffer + * \param destSampleRate The desired output sample rate */ + int getCurrentOutputBuffer( sampleFrameA * destBuffer, + sample_rate_t destSampleRate ); + + +private: + Mixer * m_mixer; + QualitySettings m_qualitySettings; + AudioBackend * m_audioBackend; + BufferFifo * m_fifo; + FifoWriter * m_fifoWriter; + + // resample data + SRC_DATA m_srcData; + SRC_STATE * m_srcState; + + +} ; + + +#endif diff --git a/include/AudioPort.h b/include/AudioPort.h index 7157f729b..c005a7e6c 100644 --- a/include/AudioPort.h +++ b/include/AudioPort.h @@ -29,7 +29,7 @@ #include #include -#include "mixer.h" +#include "Mixer.h" class EffectChain; @@ -134,7 +134,7 @@ private: EffectChain * m_effects; - friend class mixer; + friend class Mixer; friend class MixerWorkerThread; } ; diff --git a/include/AudioPortAudio.h b/include/AudioPortAudio.h index a3f968729..3b2083168 100644 --- a/include/AudioPortAudio.h +++ b/include/AudioPortAudio.h @@ -47,7 +47,7 @@ public: #include -#include "AudioDevice.h" +#include "AudioBackend.h" #if defined paNeverDropInput || defined paNonInterleaved # define PORTAUDIO_V19 @@ -60,7 +60,7 @@ class comboBox; class lcdSpinBox; -class AudioPortAudio : public AudioDevice +class AudioPortAudio : public AudioBackend { public: AudioPortAudio( bool & _success_ful, mixer * _mixer ); @@ -77,7 +77,7 @@ public: unsigned long _framesPerBuffer ); - class setupWidget : public AudioDevice::setupWidget + class setupWidget : public AudioBackend::setupWidget { public: setupWidget( QWidget * _parent ); diff --git a/include/AudioPulseAudio.h b/include/AudioPulseAudio.h index 33a11da1f..0a3a9513f 100644 --- a/include/AudioPulseAudio.h +++ b/include/AudioPulseAudio.h @@ -31,17 +31,17 @@ #include -#include "AudioDevice.h" +#include "AudioBackend.h" class lcdSpinBox; class QLineEdit; -class AudioPulseAudio : public AudioDevice, public QThread +class AudioPulseAudio : public AudioBackend, public QThread { public: - AudioPulseAudio( bool & _success_ful, mixer * _mixer ); + AudioPulseAudio( bool & _success_ful, AudioOutputContext * context ); virtual ~AudioPulseAudio(); inline static QString name() @@ -52,7 +52,7 @@ public: static QString probeDevice(); - class setupWidget : public AudioDevice::setupWidget + class setupWidget : public AudioBackend::setupWidget { public: setupWidget( QWidget * _parent ); diff --git a/include/AudioSampleRecorder.h b/include/AudioSampleRecorder.h index e1e732f80..94a30e180 100644 --- a/include/AudioSampleRecorder.h +++ b/include/AudioSampleRecorder.h @@ -29,16 +29,16 @@ #include #include -#include "AudioDevice.h" +#include "AudioBackend.h" class sampleBuffer; -class AudioSampleRecorder : public AudioDevice +class AudioSampleRecorder : public AudioBackend { public: AudioSampleRecorder( const ch_cnt_t _channels, bool & _success_ful, - mixer * _mixer ); + AudioOutputContext * context ); virtual ~AudioSampleRecorder(); f_cnt_t framesRecorded() const; @@ -46,11 +46,11 @@ public: private: - virtual void writeBuffer( const surroundSampleFrame * _ab, + virtual void writeBuffer( const sampleFrameA * _ab, const fpp_t _frames, const float _master_gain ); - typedef QList > BufferList; + typedef QList > BufferList; BufferList m_buffers; } ; diff --git a/include/AudioSdl.h b/include/AudioSdl.h index 19260829d..7826fcc69 100644 --- a/include/AudioSdl.h +++ b/include/AudioSdl.h @@ -29,18 +29,20 @@ #ifdef LMMS_HAVE_SDL +#include + #include #include -#include "AudioDevice.h" +#include "AudioBackend.h" class QLineEdit; -class AudioSdl : public AudioDevice +class AudioSdl : public AudioBackend { public: - AudioSdl( bool & _success_ful, mixer * _mixer ); + AudioSdl( bool & _success_ful, AudioOutputContext * context ); virtual ~AudioSdl(); inline static QString name() @@ -50,7 +52,7 @@ public: } - class setupWidget : public AudioDevice::setupWidget + class setupWidget : public AudioBackend::setupWidget { public: setupWidget( QWidget * _parent ); diff --git a/include/Controller.h b/include/Controller.h index 5ca110a53..129c44c18 100644 --- a/include/Controller.h +++ b/include/Controller.h @@ -23,13 +23,13 @@ * */ - #ifndef _CONTROLLER_H #define _CONTROLLER_H #include "engine.h" -#include "mixer.h" +#include "Mixer.h" #include "Model.h" +//#include "AudioOutputContext.h" #include "JournallingObject.h" class ControllerDialog; @@ -64,9 +64,9 @@ public: inline bool isSampleExact() const { - return m_sampleExact || - engine::getMixer()->currentQualitySettings(). - sampleExactControllers; + return m_sampleExact /*|| + engine::mixer()->audioOutputContext()-> + qualitySettings().sampleExactControllers()*/; } void setSampleExact( bool _exact ) @@ -76,7 +76,7 @@ public: inline ControllerTypes type() const { - return( m_type ); + return m_type; } // return whether this controller updates models frequently - used for @@ -85,17 +85,17 @@ public: { switch( m_type ) { - case LfoController: return( true ); - case PeakController: return( true ); + case LfoController: return true; + case PeakController: return true; default: break; } - return( false ); + return false; } virtual const QString & name() const { - return( m_name ); + return m_name; } diff --git a/include/Effect.h b/include/Effect.h index 4fff6b178..610d4f998 100644 --- a/include/Effect.h +++ b/include/Effect.h @@ -28,7 +28,7 @@ #include "Plugin.h" #include "engine.h" -#include "mixer.h" +#include "Mixer.h" #include "AutomatableModel.h" #include "TempoSyncKnobModel.h" diff --git a/include/EffectChain.h b/include/EffectChain.h index bf949f2bd..b09863896 100644 --- a/include/EffectChain.h +++ b/include/EffectChain.h @@ -28,7 +28,7 @@ #include "Model.h" #include "SerializingObject.h" -#include "mixer.h" +#include "Mixer.h" #include "AutomatableModel.h" class Effect; diff --git a/include/FxMixer.h b/include/FxMixer.h index 2a6bd84e0..9f7654bf5 100644 --- a/include/FxMixer.h +++ b/include/FxMixer.h @@ -26,7 +26,7 @@ #define _FX_MIXER_H #include "Model.h" -#include "mixer.h" +#include "Mixer.h" #include "EffectChain.h" #include "JournallingObject.h" diff --git a/include/Instrument.h b/include/Instrument.h index 09a60df38..8621dffa5 100644 --- a/include/Instrument.h +++ b/include/Instrument.h @@ -29,7 +29,7 @@ #include #include "Plugin.h" -#include "mixer.h" +#include "Mixer.h" // forward-declarations diff --git a/include/InstrumentSoundShaping.h b/include/InstrumentSoundShaping.h index 398df0688..eae4b9b69 100644 --- a/include/InstrumentSoundShaping.h +++ b/include/InstrumentSoundShaping.h @@ -25,7 +25,7 @@ #ifndef _INSTRUMENT_SOUND_SHAPING_H #define _INSTRUMENT_SOUND_SHAPING_H -#include "mixer.h" +#include "Mixer.h" #include "ComboBoxModel.h" diff --git a/include/mixer.h b/include/Mixer.h similarity index 58% rename from include/mixer.h rename to include/Mixer.h index 3562db3f1..16f5f4d3d 100644 --- a/include/mixer.h +++ b/include/Mixer.h @@ -1,5 +1,5 @@ /* - * mixer.h - audio-device-independent mixer for LMMS + * Mixer.h - Mixer for audio processing and rendering * * Copyright (c) 2004-2009 Tobias Doerffel * @@ -39,19 +39,18 @@ #include -#include #include #include #include "lmms_basics.h" #include "note.h" -#include "fifo_buffer.h" -class AudioDevice; -class MidiClient; +class AudioBackend; +class AudioOutputContext; class AudioPort; +class MidiClient; const fpp_t DEFAULT_BUFFER_SIZE = 256; @@ -67,105 +66,11 @@ const Octaves BaseOctave = DefaultOctave; class MixerWorkerThread; - -class EXPORT mixer : public QObject +/*! \brief The Mixer class is responsible for processing and rendering audio chunks. */ +class EXPORT Mixer : public QObject { Q_OBJECT public: - struct qualitySettings - { - enum Mode - { - Mode_Draft, - Mode_HighQuality, - Mode_FinalMix - } ; - - enum Interpolation - { - Interpolation_Linear, - Interpolation_SincFastest, - Interpolation_SincMedium, - Interpolation_SincBest - } ; - - enum Oversampling - { - Oversampling_None, - Oversampling_2x, - Oversampling_4x, - Oversampling_8x - } ; - - Interpolation interpolation; - Oversampling oversampling; - bool sampleExactControllers; - bool aliasFreeOscillators; - - qualitySettings( Mode _m ) - { - switch( _m ) - { - case Mode_Draft: - interpolation = Interpolation_Linear; - oversampling = Oversampling_None; - sampleExactControllers = false; - aliasFreeOscillators = false; - break; - case Mode_HighQuality: - interpolation = - Interpolation_SincFastest; - oversampling = Oversampling_2x; - sampleExactControllers = true; - aliasFreeOscillators = false; - break; - case Mode_FinalMix: - interpolation = Interpolation_SincBest; - oversampling = Oversampling_8x; - sampleExactControllers = true; - aliasFreeOscillators = true; - break; - } - } - - qualitySettings( Interpolation _i, Oversampling _o, bool _sec, - bool _afo ) : - interpolation( _i ), - oversampling( _o ), - sampleExactControllers( _sec ), - aliasFreeOscillators( _afo ) - { - } - - int sampleRateMultiplier() const - { - switch( oversampling ) - { - case Oversampling_None: return 1; - case Oversampling_2x: return 2; - case Oversampling_4x: return 4; - case Oversampling_8x: return 8; - } - return 1; - } - - int libsrcInterpolation() const - { - switch( interpolation ) - { - case Interpolation_Linear: - return SRC_ZERO_ORDER_HOLD; - case Interpolation_SincFastest: - return SRC_SINC_FASTEST; - case Interpolation_SincMedium: - return SRC_SINC_MEDIUM_QUALITY; - case Interpolation_SincBest: - return SRC_SINC_BEST_QUALITY; - } - return SRC_LINEAR; - } - } ; - void initDevices(); void clear(); @@ -176,16 +81,20 @@ public: return m_audioDevName; } - void setAudioDevice( AudioDevice * _dev ); - void setAudioDevice( AudioDevice * _dev, - const struct qualitySettings & _qs, - bool _needs_fifo ); - void restoreAudioDevice(); - inline AudioDevice * audioDev() + /*! \brief Sets a specific AudioOutputContext to be the active context. */ + void setAudioOutputContext( AudioOutputContext * context ); + const AudioOutputContext * audioOutputContext() const { - return m_audioDev; + return m_audioOutputContext; + } + AudioOutputContext * audioOutputContext() + { + return m_audioOutputContext; + } + AudioOutputContext * defaultAudioOutputContext() + { + return m_defaultAudioOutputContext; } - // audio-port-stuff inline void addAudioPort( AudioPort * _port ) @@ -246,7 +155,7 @@ public: return m_framesPerPeriod; } - inline const surroundSampleFrame * currentReadBuffer() const + inline const sampleFrameA * currentReadBuffer() const { return m_readBuf; } @@ -257,11 +166,6 @@ public: return m_cpuLoad; } - const qualitySettings & currentQualitySettings() const - { - return m_qualitySettings; - } - sample_rate_t baseSampleRate() const; sample_rate_t outputSampleRate() const; @@ -325,11 +229,6 @@ public: static void clearAudioBuffer( sampleFrame * _ab, const f_cnt_t _frames, const f_cnt_t _offset = 0 ); -#ifndef LMMS_DISABLE_SURROUND - static void clearAudioBuffer( surroundSampleFrame * _ab, - const f_cnt_t _frames, - const f_cnt_t _offset = 0 ); -#endif static float peakValueLeft( sampleFrame * _ab, const f_cnt_t _frames ); static float peakValueRight( sampleFrame * _ab, const f_cnt_t _frames ); @@ -337,13 +236,8 @@ public: bool criticalXRuns() const; - inline bool hasFifoWriter() const - { - return m_fifoWriter != NULL; - } - void pushInputFrames( sampleFrame * _ab, const f_cnt_t _frames ); - + inline const sampleFrame * inputBuffer() { return m_inputBuffer[ m_inputBufferRead ]; @@ -354,56 +248,27 @@ public: return m_inputBufferFrames[ m_inputBufferRead ]; } - inline surroundSampleFrame * nextBuffer() - { - return hasFifoWriter() ? m_fifo->read() : renderNextBuffer(); - } - - void changeQuality( const struct qualitySettings & _qs ); + /*! \brief Processes and renders next chunk of audio. */ + sampleFrameA * renderNextBuffer(); signals: - void qualitySettingsChanged(); void sampleRateChanged(); void nextAudioBuffer(); private: - typedef fifoBuffer fifo; + Mixer(); + virtual ~Mixer(); - class fifoWriter : public QThread - { - public: - fifoWriter( mixer * _mixer, fifo * _fifo ); - - void finish(); - - - private: - mixer * m_mixer; - fifo * m_fifo; - volatile bool m_writing; - - virtual void run(); - - } ; - - - mixer(); - virtual ~mixer(); - - void startProcessing( bool _needs_fifo = true ); + void startProcessing(); void stopProcessing(); - AudioDevice * tryAudioDevices(); + AudioBackend * tryAudioBackends(); MidiClient * tryMidiClients(); - surroundSampleFrame * renderNextBuffer(); - - - QVector m_audioPorts; fpp_t m_framesPerPeriod; @@ -415,21 +280,21 @@ private: f_cnt_t m_inputBufferSize[2]; int m_inputBufferRead; int m_inputBufferWrite; - - surroundSampleFrame * m_readBuf; - surroundSampleFrame * m_writeBuf; - - QVector m_bufferPool; + + sampleFrameA * m_readBuf; + sampleFrameA * m_writeBuf; + + QVector m_bufferPool; int m_readBuffer; int m_writeBuffer; int m_poolDepth; - surroundSampleFrame m_maxClip; - surroundSampleFrame m_previousSample; + sampleFrame m_maxClip; + sampleFrame m_previousSample; fpp_t m_halfStart[SURROUND_CHANNELS]; bool m_oldBuffer[SURROUND_CHANNELS]; bool m_newBuffer[SURROUND_CHANNELS]; - + int m_cpuLoad; QVector m_workers; int m_numWorkers; @@ -439,12 +304,11 @@ private: PlayHandleList m_playHandles; ConstPlayHandleList m_playHandlesToRemove; - struct qualitySettings m_qualitySettings; float m_masterGain; - AudioDevice * m_audioDev; - AudioDevice * m_oldAudioDev; + AudioOutputContext * m_audioOutputContext; + AudioOutputContext * m_defaultAudioOutputContext; QString m_audioDevName; @@ -456,10 +320,6 @@ private: QMutex m_inputFramesMutex; - fifo * m_fifo; - fifoWriter * m_fifoWriter; - - friend class engine; friend class MixerWorkerThread; diff --git a/include/ProjectRenderer.h b/include/ProjectRenderer.h index f72b55c9c..68bcf1b7c 100644 --- a/include/ProjectRenderer.h +++ b/include/ProjectRenderer.h @@ -26,6 +26,7 @@ #define _PROJECT_RENDERER_H #include "AudioFileDevice.h" +#include "AudioOutputContext.h" #include "lmmsconfig.h" class QTimer; @@ -71,7 +72,7 @@ public: } ; - ProjectRenderer( const mixer::qualitySettings & _qs, + ProjectRenderer( const AudioOutputContext::QualitySettings & _qs, const OutputSettings & _os, ExportFileFormats _file_format, const QString & _out_file ); @@ -101,12 +102,15 @@ signals: void progressChanged( int ); +private slots: + void finishProcessing(); + + private: virtual void run(); AudioFileDevice * m_fileDev; - mixer::qualitySettings m_qualitySettings; - mixer::qualitySettings m_oldQualitySettings; + AudioOutputContext * m_context; volatile int m_progress; volatile bool m_abort; diff --git a/include/basic_filters.h b/include/basic_filters.h index ee986b0e2..2462978ee 100644 --- a/include/basic_filters.h +++ b/include/basic_filters.h @@ -36,7 +36,7 @@ #include #include "lmms_basics.h" -#include "mixer.h" +#include "Mixer.h" #include "templates.h" #include "lmms_constants.h" diff --git a/include/cpuload_widget.h b/include/cpuload_widget.h index 7a2d27696..4653f300d 100644 --- a/include/cpuload_widget.h +++ b/include/cpuload_widget.h @@ -51,7 +51,7 @@ protected slots: private: - Uint8 m_currentLoad; + int m_currentLoad; QPixmap m_temp; QPixmap m_background; diff --git a/include/engine.h b/include/engine.h index 0f9d471c3..4a17cee6b 100644 --- a/include/engine.h +++ b/include/engine.h @@ -41,7 +41,7 @@ class FxMixer; class FxMixerView; class ProjectJournal; class MainWindow; -class mixer; +class Mixer; class pianoRoll; class projectNotes; class ResourceDB; @@ -75,7 +75,12 @@ public: } // core - static mixer * getMixer() + static Mixer * getMixer() + { + return s_mixer; + } + + static Mixer * mixer() { return s_mixer; } @@ -207,7 +212,7 @@ private: static float s_framesPerTick; // core - static mixer * s_mixer; + static Mixer * s_mixer; static FxMixer * s_fxMixer; static song * s_song; static ResourceDB * s_workingDirResourceDB; diff --git a/include/fifo_buffer.h b/include/fifo_buffer.h index 4bf908611..e69de29bb 100644 --- a/include/fifo_buffer.h +++ b/include/fifo_buffer.h @@ -1,89 +0,0 @@ -/* - * fifo_buffer.h - FIFO fixed-size buffer - * - * Copyright (c) 2007 Javier Serrano Polo - * Copyright (c) 2008 Tobias Doerffel - * - * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program (see COPYING); if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - * - */ - -#ifndef _FIFO_BUFFER_H -#define _FIFO_BUFFER_H - -#include - - -template -class fifoBuffer -{ -public: - fifoBuffer( int _size ) : - m_readerSem( _size ), - m_writerSem( _size ), - m_readerIndex( 0 ), - m_writerIndex( 0 ), - m_size( _size ) - { - m_buffer = new T[_size]; - m_readerSem.acquire( _size ); - } - - ~fifoBuffer() - { - delete[] m_buffer; - m_readerSem.release( m_size ); - } - - void write( T _element ) - { - m_writerSem.acquire(); - m_buffer[m_writerIndex++] = _element; - m_writerIndex %= m_size; - m_readerSem.release(); - } - - T read() - { - m_readerSem.acquire(); - T element = m_buffer[m_readerIndex++]; - m_readerIndex %= m_size; - m_writerSem.release(); - return element; - } - - bool available() - { - return m_readerSem.available(); - } - - -private: - QSemaphore m_readerSem; - QSemaphore m_writerSem; - int m_readerIndex; - int m_writerIndex; - int m_size; - T * m_buffer; - -} ; - - - - -#endif diff --git a/include/note_play_handle.h b/include/note_play_handle.h index 3341058dc..40b0c1d84 100644 --- a/include/note_play_handle.h +++ b/include/note_play_handle.h @@ -28,7 +28,7 @@ #define _NOTE_PLAY_HANDLE_H #include "lmmsconfig.h" -#include "mixer.h" +#include "Mixer.h" #include "note.h" #include "engine.h" #include "track.h" diff --git a/include/pch.h b/include/pch.h index 67aa73033..aa334c07d 100644 --- a/include/pch.h +++ b/include/pch.h @@ -31,6 +31,6 @@ #include -#include "mixer.h" +#include "Mixer.h" #endif diff --git a/include/sample_play_handle.h b/include/sample_play_handle.h index 2c1161737..2b590e892 100644 --- a/include/sample_play_handle.h +++ b/include/sample_play_handle.h @@ -26,7 +26,7 @@ #ifndef _SAMPLE_PLAY_HANDLE_H #define _SAMPLE_PLAY_HANDLE_H -#include "mixer.h" +#include "Mixer.h" #include "sample_buffer.h" #include "AutomatableModel.h" diff --git a/include/sample_record_handle.h b/include/sample_record_handle.h index f07cfd350..5afeb08f8 100644 --- a/include/sample_record_handle.h +++ b/include/sample_record_handle.h @@ -30,7 +30,7 @@ #include #include -#include "mixer.h" +#include "Mixer.h" #include "sample_buffer.h" class bbTrack; diff --git a/include/setup_dialog.h b/include/setup_dialog.h index 6f0dcb0ab..d0cd46b6b 100644 --- a/include/setup_dialog.h +++ b/include/setup_dialog.h @@ -29,7 +29,7 @@ #include #include "lmmsconfig.h" -#include "AudioDevice.h" +#include "AudioBackend.h" #include "MidiClient.h" #include "MidiPort.h" #include "MidiPortMenu.h" @@ -171,7 +171,7 @@ private: bool m_disableChActInd; bool m_manualChPiano; - typedef QMap AswMap; + typedef QMap AswMap; typedef QMap MswMap; typedef QMap trMap; diff --git a/include/surround_area.h b/include/surround_area.h index 6e1774728..986a1de49 100644 --- a/include/surround_area.h +++ b/include/surround_area.h @@ -31,7 +31,7 @@ #include #include "AutomatableModel.h" -#include "mixer.h" +#include "Mixer.h" class QPixmap; diff --git a/include/visualization_widget.h b/include/visualization_widget.h index 863a0ecca..8b8c3fd16 100644 --- a/include/visualization_widget.h +++ b/include/visualization_widget.h @@ -29,7 +29,7 @@ #include #include -#include "mixer.h" +#include "Mixer.h" class visualizationWidget : public QWidget diff --git a/plugins/ladspa_browser/ladspa_description.cpp b/plugins/ladspa_browser/ladspa_description.cpp index 209d0b89a..004a9996d 100644 --- a/plugins/ladspa_browser/ladspa_description.cpp +++ b/plugins/ladspa_browser/ladspa_description.cpp @@ -2,6 +2,7 @@ * ladspa_description.cpp - LADSPA plugin description * * Copyright (c) 2007 Javier Serrano Polo + * Copyright (c) 2009 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -30,10 +31,11 @@ #include #include -#include "AudioDevice.h" +#include "AudioBackend.h" +#include "AudioOutputContext.h" #include "engine.h" #include "ladspa_2_lmms.h" -#include "mixer.h" +#include "Mixer.h" @@ -73,8 +75,8 @@ ladspaDescription::ladspaDescription( QWidget * _parent, it != plugins.end(); it++ ) { if( _type != VALID || - manager->getDescription( ( *it ).second )->inputChannels - <= engine::getMixer()->audioDev()->channels() ) + manager->getDescription( ( *it ).second )->inputChannels <= + engine::mixer()->audioOutputContext()->audioBackend()->channels() ) { pluginNames.push_back( ( *it ).first ); m_pluginKeys.push_back( ( *it ).second ); diff --git a/plugins/ladspa_browser/ladspa_port_dialog.cpp b/plugins/ladspa_browser/ladspa_port_dialog.cpp index 3f324dbf4..0f2db8c28 100644 --- a/plugins/ladspa_browser/ladspa_port_dialog.cpp +++ b/plugins/ladspa_browser/ladspa_port_dialog.cpp @@ -2,7 +2,8 @@ * ladspa_port_dialog.cpp - dialog to test a LADSPA plugin * * Copyright (c) 2006-2008 Danny McRae - * + * Copyright (c) 2009 Tobias Doerffel + * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * * This program is free software; you can redistribute it and/or @@ -22,7 +23,6 @@ * */ - #include "ladspa_port_dialog.h" #include @@ -31,7 +31,7 @@ #include "embed.h" #include "engine.h" #include "ladspa_2_lmms.h" -#include "mixer.h" +#include "Mixer.h" ladspaPortDialog::ladspaPortDialog( const ladspa_key_t & _key ) @@ -95,11 +95,11 @@ ladspaPortDialog::ladspaPortDialog( const ladspa_key_t & _key ) { if( min != NOHINT ) { - min *= engine::getMixer()->processingSampleRate(); + min *= engine::mixer()->processingSampleRate(); } if( max != NOHINT ) { - max *= engine::getMixer()->processingSampleRate(); + max *= engine::mixer()->processingSampleRate(); } } diff --git a/plugins/ladspa_effect/LadspaEffect.cpp b/plugins/ladspa_effect/LadspaEffect.cpp index ea5d53e99..5dbff0ff6 100644 --- a/plugins/ladspa_effect/LadspaEffect.cpp +++ b/plugins/ladspa_effect/LadspaEffect.cpp @@ -25,14 +25,15 @@ #include +#include "AudioBackend.h" +#include "AudioOutputContext.h" #include "LadspaEffect.h" #include "mmp.h" -#include "AudioDevice.h" #include "config_mgr.h" #include "ladspa_2_lmms.h" #include "LadspaControl.h" #include "LadspaSubPluginFeatures.h" -#include "mixer.h" +#include "Mixer.h" #include "EffectChain.h" #include "Cpu.h" #include "automation_pattern.h" @@ -87,7 +88,7 @@ LadspaEffect::LadspaEffect( Model * _parent, pluginInstantiation(); - connect( engine::getMixer(), SIGNAL( sampleRateChanged() ), + connect( engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( changeSampleRate() ) ); } @@ -144,13 +145,13 @@ bool LadspaEffect::processAudioBuffer( sampleFrame * _buf, int frames = _frames; sampleFrame * o_buf = NULL; - if( m_maxSampleRate < engine::getMixer()->processingSampleRate() ) + if( m_maxSampleRate < engine::mixer()->processingSampleRate() ) { o_buf = _buf; _buf = CPU::allocFrames( _frames ); sampleDown( o_buf, _buf, m_maxSampleRate ); frames = _frames * m_maxSampleRate / - engine::getMixer()->processingSampleRate(); + engine::mixer()->processingSampleRate(); } // Copy the LMMS audio buffer to the LADSPA input buffer and initialize @@ -298,7 +299,8 @@ void LadspaEffect::pluginInstantiation() ladspa2LMMS * manager = engine::getLADSPAManager(); // Calculate how many processing units are needed. - const ch_cnt_t lmms_chnls = engine::getMixer()->audioDev()->channels(); + const ch_cnt_t lmms_chnls = engine::mixer()->audioOutputContext()-> + audioBackend()->channels(); int effect_channels = manager->getDescription( m_key )->inputChannels; setProcessorCount( lmms_chnls / effect_channels ); @@ -325,7 +327,7 @@ void LadspaEffect::pluginInstantiation() // during cleanup. It was easier to troubleshoot with the // memory management all taking place in one file. p->buffer = - new LADSPA_Data[engine::getMixer()->framesPerPeriod()]; + new LADSPA_Data[engine::mixer()->framesPerPeriod()]; if( p->name.toUpper().contains( "IN" ) && manager->isPortInput( m_key, port ) ) @@ -566,7 +568,7 @@ sample_rate_t LadspaEffect::maxSamplerate( const QString & _name ) { return __buggy_plugins[_name]; } - return engine::getMixer()->processingSampleRate(); + return engine::mixer()->processingSampleRate(); } diff --git a/plugins/ladspa_effect/LadspaSubPluginFeatures.cpp b/plugins/ladspa_effect/LadspaSubPluginFeatures.cpp index bb6cba447..35d49749e 100644 --- a/plugins/ladspa_effect/LadspaSubPluginFeatures.cpp +++ b/plugins/ladspa_effect/LadspaSubPluginFeatures.cpp @@ -28,12 +28,13 @@ #include #include +#include "AudioOutputContext.h" +#include "AudioBackend.h" #include "LadspaSubPluginFeatures.h" -#include "AudioDevice.h" #include "engine.h" #include "ladspa_2_lmms.h" #include "LadspaBase.h" -#include "mixer.h" +#include "Mixer.h" LadspaSubPluginFeatures::LadspaSubPluginFeatures( Plugin::PluginTypes _type ) : @@ -142,7 +143,7 @@ void LadspaSubPluginFeatures::listSubPluginKeys( it != plugins.end(); ++it ) { if( lm->getDescription( ( *it ).second )->inputChannels <= - engine::getMixer()->audioDev()->channels() ) + engine::mixer()->audioOutputContext()->audioBackend()->channels() ) { _kl.push_back( ladspaKeyToSubPluginKey( _desc, ( *it ).first, ( *it ).second ) ); } diff --git a/plugins/lb302/lb302.h b/plugins/lb302/lb302.h index 6094c4c53..7d4422769 100644 --- a/plugins/lb302/lb302.h +++ b/plugins/lb302/lb302.h @@ -37,7 +37,6 @@ #include "InstrumentView.h" #include "led_checkbox.h" #include "knob.h" -#include "mixer.h" class lb302SynthView; class notePlayHandle; diff --git a/plugins/sf2_player/sf2_player.cpp b/plugins/sf2_player/sf2_player.cpp index a93a125fd..56479236d 100644 --- a/plugins/sf2_player/sf2_player.cpp +++ b/plugins/sf2_player/sf2_player.cpp @@ -30,6 +30,8 @@ #include #include +#include "AudioBackend.h" +#include "AudioOutputContext.h" #include "ResourceFileMapper.h" #include "sf2_player.h" #include "engine.h" @@ -122,14 +124,14 @@ sf2Instrument::sf2Instrument( InstrumentTrack * _instrument_track ) : m_settings = new_fluid_settings(); fluid_settings_setint( m_settings, (char *) "audio.period-size", - engine::getMixer()->framesPerPeriod() ); + engine::mixer()->framesPerPeriod() ); // This is just our starting instance of synth. It is recreated // everytime we load a new soundfont. m_synth = new_fluid_synth( m_settings ); InstrumentPlayHandle * iph = new InstrumentPlayHandle( this ); - engine::getMixer()->addPlayHandle( iph ); + engine::mixer()->addPlayHandle( iph ); //loadFile( configManager::inst()->defaultSoundfont() ); @@ -147,7 +149,7 @@ sf2Instrument::sf2Instrument( InstrumentTrack * _instrument_track ) : connect( &m_patchNum, SIGNAL( dataChanged() ), this, SLOT( updatePatch() ) ); - connect( engine::getMixer(), SIGNAL( sampleRateChanged() ), + connect( engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( updateSampleRate() ) ); // Gain @@ -192,7 +194,7 @@ sf2Instrument::sf2Instrument( InstrumentTrack * _instrument_track ) : sf2Instrument::~sf2Instrument() { - engine::getMixer()->removePlayHandles( instrumentTrack() ); + engine::mixer()->removePlayHandles( instrumentTrack() ); freeFont(); delete_fluid_synth( m_synth ); delete_fluid_settings( m_settings ); @@ -498,7 +500,7 @@ void sf2Instrument::updateSampleRate() // Set & get, returns the true sample rate fluid_settings_setnum( m_settings, (char *) "synth.sample-rate", - engine::getMixer()->processingSampleRate() ); + engine::mixer()->processingSampleRate() ); fluid_settings_getnum( m_settings, (char *) "synth.sample-rate", &tempRate ); m_internalSampleRate = static_cast( tempRate ); @@ -529,8 +531,9 @@ void sf2Instrument::updateSampleRate() } m_synthMutex.lock(); - if( engine::getMixer()->currentQualitySettings().interpolation >= - mixer::qualitySettings::Interpolation_SincFastest ) + if( engine::mixer()->audioOutputContext()->qualitySettings(). + interpolation() >= + AudioOutputContext::QualitySettings::Interpolation_SincFastest ) { fluid_synth_set_interp_method( m_synth, -1, FLUID_INTERP_7THORDER ); @@ -541,7 +544,7 @@ void sf2Instrument::updateSampleRate() FLUID_INTERP_DEFAULT ); } m_synthMutex.unlock(); - if( m_internalSampleRate < engine::getMixer()->processingSampleRate() ) + if( m_internalSampleRate < engine::mixer()->processingSampleRate() ) { m_synthMutex.lock(); if( m_srcState != NULL ) @@ -549,9 +552,9 @@ void sf2Instrument::updateSampleRate() src_delete( m_srcState ); } int error; - m_srcState = src_new( engine::getMixer()-> - currentQualitySettings().libsrcInterpolation(), - DEFAULT_CHANNELS, &error ); + m_srcState = src_new( engine::mixer()->audioOutputContext()-> + qualitySettings().libsrcInterpolation(), + DEFAULT_CHANNELS, &error ); if( m_srcState == NULL || error ) { printf( "error while creating SRC-data-" diff --git a/plugins/vibed/vibrating_string.cpp b/plugins/vibed/vibrating_string.cpp index cdffd2caf..fc91a9036 100644 --- a/plugins/vibed/vibrating_string.cpp +++ b/plugins/vibed/vibrating_string.cpp @@ -26,7 +26,7 @@ #include "vibrating_string.h" #include "templates.h" #include "interpolation.h" -#include "mixer.h" +#include "Mixer.h" #include "engine.h" @@ -42,7 +42,7 @@ vibratingString::vibratingString( float _pitch, float _detune, bool _state ) : m_oversample( 2 * _oversample / (int)( _sample_rate / - engine::getMixer()->baseSampleRate() ) ), + engine::mixer()->baseSampleRate() ) ), m_randomize( _randomize ), m_stringLoss( 1.0f - _string_loss ), m_state( 0.1f ) diff --git a/plugins/vst_base/VstPlugin.h b/plugins/vst_base/VstPlugin.h index c365b9253..6d0fb7b10 100644 --- a/plugins/vst_base/VstPlugin.h +++ b/plugins/vst_base/VstPlugin.h @@ -29,7 +29,6 @@ #include #include -#include "mixer.h" #include "JournallingObject.h" #include "communication.h" diff --git a/src/core/Controller.cpp b/src/core/Controller.cpp index f65d9bee5..6bcde8f35 100644 --- a/src/core/Controller.cpp +++ b/src/core/Controller.cpp @@ -30,7 +30,7 @@ #include "song.h" #include "engine.h" -#include "mixer.h" +#include "Mixer.h" #include "Controller.h" #include "ControllerConnection.h" #include "ControllerDialog.h" diff --git a/src/core/ControllerConnection.cpp b/src/core/ControllerConnection.cpp index 0b346fd83..31c4ee4c5 100644 --- a/src/core/ControllerConnection.cpp +++ b/src/core/ControllerConnection.cpp @@ -30,7 +30,6 @@ #include "song.h" #include "engine.h" -#include "mixer.h" #include "ControllerConnection.h" diff --git a/src/core/Effect.cpp b/src/core/Effect.cpp index f848aacea..ebd595bbf 100644 --- a/src/core/Effect.cpp +++ b/src/core/Effect.cpp @@ -23,11 +23,11 @@ * */ - #include #include +#include "AudioOutputContext.h" #include "Effect.h" #include "engine.h" #include "DummyEffect.h" @@ -168,8 +168,8 @@ void Effect::reinitSRC() } int error; if( ( m_srcState[i] = src_new( - engine::getMixer()->currentQualitySettings(). - libsrcInterpolation(), + engine::mixer()->audioOutputContext()-> + qualitySettings().libsrcInterpolation(), DEFAULT_CHANNELS, &error ) ) == NULL ) { fprintf( stderr, "Error: src_new() failed in effect.cpp!\n" ); diff --git a/src/core/EnvelopeAndLfoParameters.cpp b/src/core/EnvelopeAndLfoParameters.cpp index dbf3c37d4..28209cb06 100644 --- a/src/core/EnvelopeAndLfoParameters.cpp +++ b/src/core/EnvelopeAndLfoParameters.cpp @@ -27,7 +27,7 @@ #include "EnvelopeAndLfoParameters.h" #include "debug.h" #include "engine.h" -#include "mixer.h" +#include "Mixer.h" #include "mmp.h" #include "Oscillator.h" diff --git a/src/core/LfoController.cpp b/src/core/LfoController.cpp index 94d6cc687..696a11b73 100644 --- a/src/core/LfoController.cpp +++ b/src/core/LfoController.cpp @@ -31,7 +31,6 @@ #include "song.h" #include "engine.h" -#include "mixer.h" #include "LfoController.h" #include "ControllerDialog.h" diff --git a/src/core/mixer.cpp b/src/core/Mixer.cpp similarity index 76% rename from src/core/mixer.cpp rename to src/core/Mixer.cpp index b82d6886f..14313505b 100644 --- a/src/core/mixer.cpp +++ b/src/core/Mixer.cpp @@ -1,5 +1,5 @@ /* - * mixer.cpp - audio-device-independent mixer for LMMS + * Mixer.cpp - Mixer for audio processing and rendering * * Copyright (c) 2004-2009 Tobias Doerffel * @@ -24,7 +24,8 @@ #include -#include "mixer.h" +#include "AudioOutputContext.h" +#include "Mixer.h" #include "FxMixer.h" #include "play_handle.h" #include "song.h" @@ -117,7 +118,7 @@ public: static JobQueue s_jobQueue; - MixerWorkerThread( int _worker_num, mixer * _mixer ) : + MixerWorkerThread( int _worker_num, Mixer * _mixer ) : QThread( _mixer ), m_workingBuf( CPU::allocFrames( _mixer->framesPerPeriod() ) ), m_workerNum( _worker_num ), @@ -166,7 +167,7 @@ private: sampleFrame * m_workingBuf; int m_workerNum; volatile bool m_quit; - mixer * m_mixer; + Mixer * m_mixer; QWaitCondition * m_queueReadyWaitCond; } ; @@ -268,8 +269,11 @@ void MixerWorkerThread::processJobQueue() -mixer::mixer() : - m_framesPerPeriod( DEFAULT_BUFFER_SIZE ), + +Mixer::Mixer() : + m_framesPerPeriod( qBound( 32, + configManager::inst()->value( "mixer", "framesperaudiobuffer" ).toInt(), + DEFAULT_BUFFER_SIZE ) ), m_workingBuf( NULL ), m_inputBufferRead( 0 ), m_inputBufferWrite( 1 ), @@ -279,17 +283,16 @@ mixer::mixer() : m_workers(), m_numWorkers( QThread::idealThreadCount()-1 ), m_queueReadyWaitCond(), - m_qualitySettings( qualitySettings::Mode_Draft ), m_masterGain( 1.0f ), - m_audioDev( NULL ), - m_oldAudioDev( NULL ), + m_audioOutputContext( NULL ), + m_defaultAudioOutputContext( NULL ), m_globalMutex( QMutex::Recursive ) { for( int i = 0; i < 2; ++i ) { m_inputBufferFrames[i] = 0; m_inputBufferSize[i] = DEFAULT_BUFFER_SIZE * 100; - m_inputBuffer[i] = CPU::allocFrames( + m_inputBuffer[i] = CPU::allocFrames( DEFAULT_BUFFER_SIZE * 100 ); clearAudioBuffer( m_inputBuffer[i], m_inputBufferSize[i] ); } @@ -299,38 +302,6 @@ mixer::mixer() : __fx_channel_jobs[i-1] = (fx_ch_t) i; } - // just rendering? - if( !engine::hasGUI() ) - { - m_framesPerPeriod = DEFAULT_BUFFER_SIZE; - m_fifo = new fifo( 1 ); - } - else if( configManager::inst()->value( "mixer", "framesperaudiobuffer" - ).toInt() >= 32 ) - { - m_framesPerPeriod = - (fpp_t) configManager::inst()->value( "mixer", - "framesperaudiobuffer" ).toInt(); - - if( m_framesPerPeriod > DEFAULT_BUFFER_SIZE ) - { - m_fifo = new fifo( m_framesPerPeriod - / DEFAULT_BUFFER_SIZE ); - m_framesPerPeriod = DEFAULT_BUFFER_SIZE; - } - else - { - m_fifo = new fifo( 1 ); - } - } - else - { - configManager::inst()->setValue( "mixer", - "framesperaudiobuffer", - QString::number( m_framesPerPeriod ) ); - m_fifo = new fifo( 1 ); - } - m_workingBuf = CPU::allocFrames( m_framesPerPeriod ); for( Uint8 i = 0; i < 3; i++ ) { @@ -352,12 +323,17 @@ mixer::mixer() : m_poolDepth = 2; m_readBuffer = 0; m_writeBuffer = 1; + + // initialize default AudioOutputContext + m_defaultAudioOutputContext = new AudioOutputContext( this, NULL, + AudioOutputContext::QualitySettings::Preset_Draft ); + m_audioOutputContext = m_defaultAudioOutputContext; } -mixer::~mixer() +Mixer::~Mixer() { // distribute an empty job-queue so that worker-threads // get out of their processing-loop @@ -372,13 +348,7 @@ mixer::~mixer() m_workers[w]->wait( 500 ); } - while( m_fifo->available() ) - { - delete[] m_fifo->read(); - } - delete m_fifo; - - delete m_audioDev; + delete m_audioOutputContext; delete m_midiClient; for( Uint8 i = 0; i < 3; i++ ) @@ -392,54 +362,54 @@ mixer::~mixer() -void mixer::initDevices() +void Mixer::initDevices() { - m_audioDev = tryAudioDevices(); + audioOutputContext()->setAudioBackend( tryAudioBackends() ); m_midiClient = tryMidiClients(); } -void mixer::startProcessing( bool _needs_fifo ) +void Mixer::setAudioOutputContext( AudioOutputContext * context ) { - if( _needs_fifo ) - { - m_fifoWriter = new fifoWriter( this, m_fifo ); - m_fifoWriter->start( QThread::HighPriority ); - } - else - { - m_fifoWriter = NULL; - } + stopProcessing(); - m_audioDev->startProcessing(); + m_audioOutputContext = context; + + //m_audioDev->applyQualitySettings(); + + emit sampleRateChanged(); + + startProcessing(); } -void mixer::stopProcessing() +void Mixer::startProcessing() { - if( m_fifoWriter != NULL ) + if( m_audioOutputContext ) { - m_fifoWriter->finish(); - m_audioDev->stopProcessing(); - m_fifoWriter->wait( 1000 ); - m_fifoWriter->terminate(); - delete m_fifoWriter; - m_fifoWriter = NULL; - } - else - { - m_audioDev->stopProcessing(); + m_audioOutputContext->startProcessing(); } } -sample_rate_t mixer::baseSampleRate() const +void Mixer::stopProcessing() +{ + if( m_audioOutputContext ) + { + m_audioOutputContext->stopProcessing(); + } +} + + + + +sample_rate_t Mixer::baseSampleRate() const { sample_rate_t sr = configManager::inst()->value( "mixer", "samplerate" ).toInt(); @@ -453,33 +423,36 @@ sample_rate_t mixer::baseSampleRate() const -sample_rate_t mixer::outputSampleRate() const +sample_rate_t Mixer::outputSampleRate() const { - return m_audioDev != NULL ? m_audioDev->sampleRate() : - baseSampleRate(); + if( audioOutputContext()->audioBackend() ) + { + return audioOutputContext()->audioBackend()->sampleRate(); + } + return baseSampleRate(); } -sample_rate_t mixer::inputSampleRate() const +sample_rate_t Mixer::inputSampleRate() const { - return m_audioDev != NULL ? m_audioDev->sampleRate() : - baseSampleRate(); + return outputSampleRate(); } -sample_rate_t mixer::processingSampleRate() const +sample_rate_t Mixer::processingSampleRate() const { - return outputSampleRate() * m_qualitySettings.sampleRateMultiplier(); + return outputSampleRate() * + audioOutputContext()->qualitySettings().sampleRateMultiplier(); } -bool mixer::criticalXRuns() const +bool Mixer::criticalXRuns() const { return m_cpuLoad >= 99 && engine::getSong()->realTimeTask() == true; } @@ -487,14 +460,14 @@ bool mixer::criticalXRuns() const -void mixer::pushInputFrames( sampleFrame * _ab, const f_cnt_t _frames ) +void Mixer::pushInputFrames( sampleFrame * _ab, const f_cnt_t _frames ) { lockInputFrames(); f_cnt_t frames = m_inputBufferFrames[ m_inputBufferWrite ]; int size = m_inputBufferSize[ m_inputBufferWrite ]; sampleFrame * buf = m_inputBuffer[ m_inputBufferWrite ]; - + if( frames + _frames > size ) { size = qMax( size * 2, frames + _frames ); @@ -507,17 +480,17 @@ void mixer::pushInputFrames( sampleFrame * _ab, const f_cnt_t _frames ) buf = ab; } - + CPU::memCpy( &buf[ frames ], _ab, _frames * sizeof( sampleFrame ) ); m_inputBufferFrames[ m_inputBufferWrite ] += _frames; - + unlockInputFrames(); } -sampleFrameA * mixer::renderNextBuffer() +sampleFrameA * Mixer::renderNextBuffer() { MicroTimer timer; static song::playPos last_metro_pos = -1; @@ -649,7 +622,7 @@ sampleFrameA * mixer::renderNextBuffer() // removes all play-handles. this is neccessary, when the song is stopped -> // all remaining notes etc. would be played until their end -void mixer::clear() +void Mixer::clear() { // TODO: m_midiClient->noteOffAll(); lock(); @@ -669,7 +642,7 @@ void mixer::clear() -void mixer::bufferToPort( const sampleFrame * _buf, +void Mixer::bufferToPort( const sampleFrame * _buf, const fpp_t _frames, const f_cnt_t _offset, stereoVolumeVector _vv, @@ -709,7 +682,7 @@ void mixer::bufferToPort( const sampleFrame * _buf, -void mixer::clearAudioBuffer( sampleFrame * _ab, const f_cnt_t _frames, +void Mixer::clearAudioBuffer( sampleFrame * _ab, const f_cnt_t _frames, const f_cnt_t _offset ) { if( likely( (size_t)( _ab+_offset ) % 16 == 0 && _frames % 8 == 0 ) ) @@ -724,18 +697,8 @@ void mixer::clearAudioBuffer( sampleFrame * _ab, const f_cnt_t _frames, -#ifndef LMMS_DISABLE_SURROUND -void mixer::clearAudioBuffer( surroundSampleFrame * _ab, const f_cnt_t _frames, - const f_cnt_t _offset ) -{ - memset( _ab+_offset, 0, sizeof( *_ab ) * _frames ); -} -#endif - - - -float mixer::peakValueLeft( sampleFrame * _ab, const f_cnt_t _frames ) +float Mixer::peakValueLeft( sampleFrame * _ab, const f_cnt_t _frames ) { float p = 0.0f; for( f_cnt_t f = 0; f < _frames; ++f ) @@ -755,7 +718,7 @@ float mixer::peakValueLeft( sampleFrame * _ab, const f_cnt_t _frames ) -float mixer::peakValueRight( sampleFrame * _ab, const f_cnt_t _frames ) +float Mixer::peakValueRight( sampleFrame * _ab, const f_cnt_t _frames ) { float p = 0.0f; for( f_cnt_t f = 0; f < _frames; ++f ) @@ -775,97 +738,7 @@ float mixer::peakValueRight( sampleFrame * _ab, const f_cnt_t _frames ) -void mixer::changeQuality( const struct qualitySettings & _qs ) -{ - // don't delete the audio-device - stopProcessing(); - - m_qualitySettings = _qs; - m_audioDev->applyQualitySettings(); - - emit sampleRateChanged(); - emit qualitySettingsChanged(); - - startProcessing(); -} - - - - -void mixer::setAudioDevice( AudioDevice * _dev ) -{ - stopProcessing(); - - m_oldAudioDev = m_audioDev; - - if( _dev == NULL ) - { - printf( "param _dev == NULL in mixer::setAudioDevice(...). " - "Trying any working audio-device\n" ); - m_audioDev = tryAudioDevices(); - } - else - { - m_audioDev = _dev; - } - - emit sampleRateChanged(); - - startProcessing(); -} - - - - -void mixer::setAudioDevice( AudioDevice * _dev, - const struct qualitySettings & _qs, - bool _needs_fifo ) -{ - // don't delete the audio-device - stopProcessing(); - - m_qualitySettings = _qs; - m_oldAudioDev = m_audioDev; - - if( _dev == NULL ) - { - printf( "param _dev == NULL in mixer::setAudioDevice(...). " - "Trying any working audio-device\n" ); - m_audioDev = tryAudioDevices(); - } - else - { - m_audioDev = _dev; - } - - emit qualitySettingsChanged(); - emit sampleRateChanged(); - - startProcessing( _needs_fifo ); -} - - - - -void mixer::restoreAudioDevice() -{ - if( m_oldAudioDev != NULL ) - { - stopProcessing(); - delete m_audioDev; - - m_audioDev = m_oldAudioDev; - emit sampleRateChanged(); - - m_oldAudioDev = NULL; - startProcessing(); - } -} - - - - -void mixer::removeAudioPort( AudioPort * _port ) +void Mixer::removeAudioPort( AudioPort * _port ) { QVector::Iterator it = qFind( m_audioPorts.begin(), m_audioPorts.end(), @@ -881,7 +754,7 @@ void mixer::removeAudioPort( AudioPort * _port ) -void mixer::removePlayHandle( playHandle * _ph ) +void Mixer::removePlayHandle( playHandle * _ph ) { lock(); // check thread affinity as we must not delete play-handles @@ -908,7 +781,7 @@ void mixer::removePlayHandle( playHandle * _ph ) -void mixer::removePlayHandles( track * _track, playHandle::Type _type ) +void Mixer::removePlayHandles( track * _track, playHandle::Type _type ) { lock(); PlayHandleList::Iterator it = m_playHandles.begin(); @@ -932,10 +805,10 @@ void mixer::removePlayHandles( track * _track, playHandle::Type _type ) -AudioDevice * mixer::tryAudioDevices() +AudioBackend * Mixer::tryAudioBackends() { bool success_ful = false; - AudioDevice * dev = NULL; + AudioBackend * dev = NULL; QString dev_name = configManager::inst()->value( "mixer", "audiodev" ); if( dev_name == AudioDummy::name() ) @@ -946,7 +819,7 @@ AudioDevice * mixer::tryAudioDevices() #ifdef LMMS_HAVE_ALSA if( dev_name == AudioAlsa::name() || dev_name == "" ) { - dev = new AudioAlsa( success_ful, this ); + dev = new AudioAlsa( success_ful, audioOutputContext() ); if( success_ful ) { m_audioDevName = AudioAlsa::name(); @@ -960,7 +833,7 @@ AudioDevice * mixer::tryAudioDevices() #ifdef LMMS_HAVE_PORTAUDIO if( dev_name == AudioPortAudio::name() || dev_name == "" ) { - dev = new AudioPortAudio( success_ful, this ); + dev = new AudioPortAudio( success_ful, audioOutputContext() ); if( success_ful ) { m_audioDevName = AudioPortAudio::name(); @@ -974,7 +847,7 @@ AudioDevice * mixer::tryAudioDevices() #ifdef LMMS_HAVE_PULSEAUDIO if( dev_name == AudioPulseAudio::name() || dev_name == "" ) { - dev = new AudioPulseAudio( success_ful, this ); + dev = new AudioPulseAudio( success_ful, audioOutputContext() ); if( success_ful ) { m_audioDevName = AudioPulseAudio::name(); @@ -988,7 +861,7 @@ AudioDevice * mixer::tryAudioDevices() #ifdef LMMS_HAVE_OSS if( dev_name == AudioOss::name() || dev_name == "" ) { - dev = new AudioOss( success_ful, this ); + dev = new AudioOss( success_ful, audioOutputContext() ); if( success_ful ) { m_audioDevName = AudioOss::name(); @@ -1002,7 +875,7 @@ AudioDevice * mixer::tryAudioDevices() #ifdef LMMS_HAVE_JACK if( dev_name == AudioJack::name() || dev_name == "" ) { - dev = new AudioJack( success_ful, this ); + dev = new AudioJack( success_ful, audioOutputContext() ); if( success_ful ) { m_audioDevName = AudioJack::name(); @@ -1016,7 +889,7 @@ AudioDevice * mixer::tryAudioDevices() #ifdef LMMS_HAVE_SDL if( dev_name == AudioSdl::name() || dev_name == "" ) { - dev = new AudioSdl( success_ful, this ); + dev = new AudioSdl( success_ful, audioOutputContext() ); if( success_ful ) { m_audioDevName = AudioSdl::name(); @@ -1027,7 +900,7 @@ AudioDevice * mixer::tryAudioDevices() #endif // add more device-classes here... - //dev = new audioXXXX( SAMPLE_RATES[m_qualityLevel], success_ful, this ); + //dev = new audioXXXX( SAMPLE_RATES[m_qualityLevel], success_ful, audioOutputContext() ); //if( sucess_ful ) //{ // return dev; @@ -1040,13 +913,13 @@ AudioDevice * mixer::tryAudioDevices() m_audioDevName = AudioDummy::name(); - return new AudioDummy( success_ful, this ); + return new AudioDummy( success_ful, audioOutputContext() ); } -MidiClient * mixer::tryMidiClients() +MidiClient * Mixer::tryMidiClients() { QString client_name = configManager::inst()->value( "mixer", "mididev" ); @@ -1111,57 +984,5 @@ MidiClient * mixer::tryMidiClients() - - - - - - -mixer::fifoWriter::fifoWriter( mixer * _mixer, fifo * _fifo ) : - m_mixer( _mixer ), - m_fifo( _fifo ), - m_writing( true ) -{ -} - - - - -void mixer::fifoWriter::finish() -{ - m_writing = false; -} - - - - -void mixer::fifoWriter::run() -{ -#if 0 -#ifdef LMMS_BUILD_LINUX -#ifdef LMMS_HAVE_PTHREAD_H - cpu_set_t mask; - CPU_ZERO( &mask ); - CPU_SET( 0, &mask ); - pthread_setaffinity_np( pthread_self(), sizeof( mask ), &mask ); -#endif -#endif -#endif - - const fpp_t frames = m_mixer->framesPerPeriod(); - while( m_writing ) - { - sampleFrameA * buffer = CPU::allocFrames( frames ); - const sampleFrameA * b = m_mixer->renderNextBuffer(); - CPU::memCpy( buffer, b, frames * sizeof( sampleFrameA ) ); - m_fifo->write( buffer ); - } - - m_fifo->write( NULL ); -} - - - - -#include "moc_mixer.cxx" +#include "moc_Mixer.cxx" diff --git a/src/core/Oscillator.cpp b/src/core/Oscillator.cpp index ed00ef643..7b5c8a60c 100644 --- a/src/core/Oscillator.cpp +++ b/src/core/Oscillator.cpp @@ -24,7 +24,7 @@ #include "Oscillator.h" #include "engine.h" -#include "mixer.h" +#include "Mixer.h" #include "AutomatableModel.h" @@ -55,9 +55,9 @@ Oscillator::Oscillator( const IntModel * _wave_shape_model, void Oscillator::update( sampleFrame * _ab, const fpp_t _frames, const ch_cnt_t _chnl ) { - if( m_freq >= engine::getMixer()->processingSampleRate() / 2 ) + if( m_freq >= engine::mixer()->processingSampleRate() / 2 ) { - mixer::clearAudioBuffer( _ab, _frames ); + Mixer::clearAudioBuffer( _ab, _frames ); return; } if( m_subOsc != NULL ) @@ -456,7 +456,7 @@ void Oscillator::updateFM( sampleFrame * _ab, const fpp_t _frames, recalcPhase(); const float osc_coeff = m_freq * m_detuning; const float sampleRateCorrection = 44100.0f / - engine::getMixer()->processingSampleRate(); + engine::mixer()->processingSampleRate(); for( fpp_t frame = 0; frame < _frames; ++frame ) { diff --git a/src/core/PeakController.cpp b/src/core/PeakController.cpp index 208304fb2..10ab65acb 100644 --- a/src/core/PeakController.cpp +++ b/src/core/PeakController.cpp @@ -32,7 +32,6 @@ #include "song.h" #include "engine.h" -#include "mixer.h" #include "PeakController.h" #include "ControllerDialog.h" #include "plugins/peak_controller_effect/peak_controller_effect.h" diff --git a/src/core/Plugin.cpp b/src/core/Plugin.cpp index 9836bdef2..c50521c37 100644 --- a/src/core/Plugin.cpp +++ b/src/core/Plugin.cpp @@ -29,7 +29,6 @@ #include "Plugin.h" #include "embed.h" #include "engine.h" -#include "mixer.h" #include "config_mgr.h" #include "DummyPlugin.h" #include "AutomatableModel.h" diff --git a/src/core/ProjectRenderer.cpp b/src/core/ProjectRenderer.cpp index 63de13509..887f45f6e 100644 --- a/src/core/ProjectRenderer.cpp +++ b/src/core/ProjectRenderer.cpp @@ -77,17 +77,19 @@ FileEncodeDevice __fileEncodeDevices[] = const char * ProjectRenderer::EFF_ext[] = {"wav", "ogg", "mp3", "flac"}; -ProjectRenderer::ProjectRenderer( const mixer::qualitySettings & _qs, +ProjectRenderer::ProjectRenderer( + const AudioOutputContext::QualitySettings & _qs, const OutputSettings & _os, ExportFileFormats _file_format, const QString & _out_file ) : QThread( engine::getMixer() ), m_fileDev( NULL ), - m_qualitySettings( _qs ), - m_oldQualitySettings( engine::getMixer()->currentQualitySettings() ), m_progress( 0 ), m_abort( false ) { + m_context = new AudioOutputContext( engine::getMixer(), + NULL, + _qs ); if( __fileEncodeDevices[_file_format].m_getDevInst == NULL ) { return; @@ -100,13 +102,15 @@ ProjectRenderer::ProjectRenderer( const mixer::qualitySettings & _qs, _os.bitrate, _os.bitrate - 64, _os.bitrate + 64, _os.depth == Depth_32Bit ? 32 : ( _os.depth == Depth_24Bit ? 24 : 16 ), - engine::getMixer() ); + m_context ); if( success_ful == false ) { delete m_fileDev; m_fileDev = NULL; } + m_context->setAudioBackend( m_fileDev ); + } @@ -114,6 +118,7 @@ ProjectRenderer::ProjectRenderer( const mixer::qualitySettings & _qs, ProjectRenderer::~ProjectRenderer() { + delete m_fileDev; } @@ -129,12 +134,12 @@ ProjectRenderer::ExportFileFormats ProjectRenderer::getFileFormatFromExtension( { if( QString( __fileEncodeDevices[idx].m_extension ) == _ext ) { - return( __fileEncodeDevices[idx].m_fileFormat ); + return __fileEncodeDevices[idx].m_fileFormat; } ++idx; } - return( WaveFile ); // default + return WaveFile; // default } @@ -144,11 +149,12 @@ void ProjectRenderer::startProcessing() { if( isReady() ) { + connect( this, SIGNAL( finished() ), this, SLOT( finishProcessing() ) ); + // have to do mixer stuff with GUI-thread-affinity in order to // make slots connected to sampleRateChanged()-signals being // called immediately - engine::getMixer()->setAudioDevice( m_fileDev, - m_qualitySettings, false ); + engine::mixer()->setAudioOutputContext( m_context ); start( #ifndef LMMS_BUILD_WIN32 @@ -160,6 +166,49 @@ void ProjectRenderer::startProcessing() + +void ProjectRenderer::abortProcessing() +{ + m_abort = true; +} + + + + +void ProjectRenderer::updateConsoleProgress() +{ + const int cols = 50; + static int rot = 0; + char buf[80]; + char prog[cols+1]; + + if( m_fileDev == NULL ){ + qWarning("Error occured. Aborting render."); + m_consoleUpdateTimer->stop(); + delete m_consoleUpdateTimer; + // TODO: kill the program. I can't figure out how to do it... + return; + } + + for( int i = 0; i < cols; ++i ) + { + prog[i] = ( i*100/cols <= m_progress ? '-' : ' ' ); + } + prog[cols] = 0; + + const char * activity = (const char *) "|/-\\"; + memset( buf, 0, sizeof( buf ) ); + sprintf( buf, "\r|%s| %3d%% %c ", prog, m_progress, + activity[rot] ); + rot = ( rot+1 ) % 4; + + fprintf( stderr, "%s", buf ); + fflush( stderr ); +} + + + + void ProjectRenderer::run() { #if 0 @@ -194,11 +243,17 @@ void ProjectRenderer::run() } engine::getSong()->stopExport(); +} + + + +void ProjectRenderer::finishProcessing() +{ const QString f = m_fileDev->outputFile(); - engine::getMixer()->restoreAudioDevice(); // also deletes audio-dev - engine::getMixer()->changeQuality( m_oldQualitySettings ); + engine::mixer()->setAudioOutputContext( + engine::mixer()->defaultAudioOutputContext() ); // if the user aborted export-process, the file has to be deleted if( m_abort ) @@ -209,46 +264,5 @@ void ProjectRenderer::run() - -void ProjectRenderer::abortProcessing() -{ - m_abort = true; -} - - - -void ProjectRenderer::updateConsoleProgress() -{ - const int cols = 50; - static int rot = 0; - char buf[80]; - char prog[cols+1]; - - if( m_fileDev == NULL ){ - qWarning("Error occured. Aborting render."); - m_consoleUpdateTimer->stop(); - delete m_consoleUpdateTimer; - // TODO: kill the program. I can't figure out how to do it... - return; - } - - for( int i = 0; i < cols; ++i ) - { - prog[i] = ( i*100/cols <= m_progress ? '-' : ' ' ); - } - prog[cols] = 0; - - const char * activity = (const char *) "|/-\\"; - memset( buf, 0, sizeof( buf ) ); - sprintf( buf, "\r|%s| %3d%% %c ", prog, m_progress, - activity[rot] ); - rot = ( rot+1 ) % 4; - - fprintf( stderr, "%s", buf ); - fflush( stderr ); -} - - - #include "moc_ProjectRenderer.cxx" diff --git a/src/core/RemotePlugin.cpp b/src/core/RemotePlugin.cpp index e712cda80..a711d27cd 100644 --- a/src/core/RemotePlugin.cpp +++ b/src/core/RemotePlugin.cpp @@ -29,7 +29,7 @@ #endif #include "RemotePlugin.h" -#include "mixer.h" +#include "Mixer.h" #include "engine.h" #include "config_mgr.h" diff --git a/src/core/audio/AudioAlsa.cpp b/src/core/audio/AudioAlsa.cpp index b119e619a..077f5cfef 100644 --- a/src/core/audio/AudioAlsa.cpp +++ b/src/core/audio/AudioAlsa.cpp @@ -40,11 +40,11 @@ -AudioAlsa::AudioAlsa( bool & _success_ful, mixer * _mixer ) : - AudioDevice( tLimit( +AudioAlsa::AudioAlsa( bool & _success_ful, AudioOutputContext * context ) : + AudioBackend( tLimit( configManager::inst()->value( "audioalsa", "channels" ).toInt(), DEFAULT_CHANNELS, SURROUND_CHANNELS ), - _mixer ), + context ), m_handle( NULL ), m_hwParams( NULL ), m_swParams( NULL ), @@ -201,7 +201,7 @@ void AudioAlsa::applyQualitySettings() { if( hqAudio() ) { - setSampleRate( engine::getMixer()->processingSampleRate() ); + setSampleRate( mixer()->processingSampleRate() ); if( m_handle != NULL ) { @@ -233,8 +233,6 @@ void AudioAlsa::applyQualitySettings() return; } } - - AudioDevice::applyQualitySettings(); } @@ -242,16 +240,15 @@ void AudioAlsa::applyQualitySettings() void AudioAlsa::run() { - sampleFrameA * temp = CPU::allocFrames( - getMixer()->framesPerPeriod() ); + sampleFrameA * temp = CPU::allocFrames( mixer()->framesPerPeriod() ); intSampleFrameA * outbuf = (intSampleFrameA *) CPU::memAlloc( sizeof( intSampleFrameA ) * channels() / - DEFAULT_CHANNELS * getMixer()->framesPerPeriod() ); + DEFAULT_CHANNELS * mixer()->framesPerPeriod() ); int_sample_t * pcmbuf = new int_sample_t[m_periodSize * channels()]; - int outbuf_size = getMixer()->framesPerPeriod() * channels(); + int outbuf_size = mixer()->framesPerPeriod() * channels(); int outbuf_pos = 0; int pcmbuf_size = m_periodSize * channels(); @@ -274,7 +271,7 @@ void AudioAlsa::run() outbuf_size = frames * channels(); CPU::convertToS16( temp, outbuf, frames, - getMixer()->masterGain(), + mixer()->masterGain(), m_convertEndian ); } int min_len = qMin( len, outbuf_size - outbuf_pos ); @@ -374,7 +371,7 @@ int AudioAlsa::setHWParams( const ch_cnt_t _channels, snd_pcm_access_t _access ) sampleRate(), 0 ) ) < 0 ) { if( ( err = snd_pcm_hw_params_set_rate( m_handle, m_hwParams, - getMixer()->baseSampleRate(), 0 ) ) < 0 ) + mixer()->baseSampleRate(), 0 ) ) < 0 ) { printf( "Could not set sample rate: %s\n", snd_strerror( err ) ); @@ -382,7 +379,7 @@ int AudioAlsa::setHWParams( const ch_cnt_t _channels, snd_pcm_access_t _access ) } } - m_periodSize = getMixer()->framesPerPeriod(); + m_periodSize = mixer()->framesPerPeriod(); m_bufferSize = m_periodSize * 8; dir = 0; err = snd_pcm_hw_params_set_period_size_near( m_handle, m_hwParams, @@ -493,7 +490,7 @@ int AudioAlsa::setSWParams() AudioAlsa::setupWidget::setupWidget( QWidget * _parent ) : - AudioDevice::setupWidget( AudioAlsa::name(), _parent ) + AudioBackend::setupWidget( AudioAlsa::name(), _parent ) { m_device = new QComboBox( this ); diff --git a/src/core/audio/AudioBackend.cpp b/src/core/audio/AudioBackend.cpp new file mode 100644 index 000000000..0b3607049 --- /dev/null +++ b/src/core/audio/AudioBackend.cpp @@ -0,0 +1,144 @@ +/* + * AudioBackend.cpp - base-class for audio-devices used by LMMS-mixer + * + * Copyright (c) 2004-2009 Tobias Doerffel + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#include "AudioBackend.h" +#include "AudioOutputContext.h" +#include "config_mgr.h" +#include "debug.h" +#include "Cpu.h" + + + +AudioBackend::AudioBackend( const ch_cnt_t _channels, + AudioOutputContext * context ) : + m_supportsCapture( false ), + m_context( context ), + m_sampleRate( mixer()->processingSampleRate() ), + m_channels( _channels ), + m_buffer( CPU::allocFrames( mixer()->framesPerPeriod() ) ) +{ +} + + + + +AudioBackend::~AudioBackend() +{ + CPU::freeFrames( m_buffer ); +} + + + + +int AudioBackend::processNextBuffer() +{ + const int frames = getNextBuffer( m_buffer ); + if( frames ) + { + writeBuffer( m_buffer, frames, mixer()->masterGain() ); + } + return frames; +} + + + + +int AudioBackend::getNextBuffer( sampleFrameA * _ab ) +{ + return outputContext()->getCurrentOutputBuffer( _ab, sampleRate() ); +} + + + + +void AudioBackend::stopProcessing() +{ + // flush AudioOutputContext's FIFO + while( processNextBuffer() ) + { + } +} + + + + +void AudioBackend::applyQualitySettings() +{ +} + + + + +void AudioBackend::registerPort( AudioPort * ) +{ +} + + + + +void AudioBackend::unregisterPort( AudioPort * _port ) +{ +} + + + + +void AudioBackend::renamePort( AudioPort * ) +{ +} + + + + +void AudioBackend::clearS16Buffer( intSampleFrameA * _outbuf, const fpp_t _frames ) +{ + CPU::memClear( _outbuf, _frames * sizeof( *_outbuf ) ); +// memset( _outbuf, 0, _frames * channels() * BYTES_PER_INT_SAMPLE ); +} + + + + +bool AudioBackend::hqAudio() const +{ + return configManager::inst()->value( "mixer", "hqaudio" ).toInt(); +} + + + + +const Mixer * AudioBackend::mixer() const +{ + return outputContext()->mixer(); +} + + + + +Mixer * AudioBackend::mixer() +{ + return outputContext()->mixer(); +} + + diff --git a/src/core/audio/AudioDevice.cpp b/src/core/audio/AudioDevice.cpp deleted file mode 100644 index ba38a227f..000000000 --- a/src/core/audio/AudioDevice.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/* - * AudioDevice.cpp - base-class for audio-devices used by LMMS-mixer - * - * Copyright (c) 2004-2009 Tobias Doerffel - * - * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program (see COPYING); if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - * - */ - -#include "AudioDevice.h" -#include "config_mgr.h" -#include "debug.h" -#include "Cpu.h" - - - -AudioDevice::AudioDevice( const ch_cnt_t _channels, mixer * _mixer ) : - m_supportsCapture( false ), - m_sampleRate( _mixer->processingSampleRate() ), - m_channels( _channels ), - m_mixer( _mixer ), - m_buffer( CPU::allocFrames( getMixer()->framesPerPeriod() ) ) -{ - int error; - if( ( m_srcState = src_new( - getMixer()->currentQualitySettings().libsrcInterpolation(), - SURROUND_CHANNELS, &error ) ) == NULL ) - { - printf( "Error: src_new() failed in audio_device.cpp!\n" ); - } -} - - - - -AudioDevice::~AudioDevice() -{ - src_delete( m_srcState ); - CPU::freeFrames( m_buffer ); - - m_devMutex.tryLock(); - unlock(); -} - - - - -void AudioDevice::processNextBuffer() -{ - const fpp_t frames = getNextBuffer( m_buffer ); - if( frames ) - { - writeBuffer( m_buffer, frames, getMixer()->masterGain() ); - } - else - { - m_inProcess = false; - } -} - - - - -fpp_t AudioDevice::getNextBuffer( sampleFrameA * _ab ) -{ - fpp_t frames = getMixer()->framesPerPeriod(); - sampleFrameA * b = getMixer()->nextBuffer(); - if( !b ) - { - return 0; - } - - // make sure, no other thread is accessing device - lock(); - - // resample if neccessary - if( getMixer()->processingSampleRate() != m_sampleRate ) - { - resample( b, frames, _ab, getMixer()->processingSampleRate(), - m_sampleRate ); - frames = frames * m_sampleRate / - getMixer()->processingSampleRate(); - } - else - { - CPU::memCpy( _ab, b, frames * sizeof( surroundSampleFrame ) ); - } - - // release lock - unlock(); - - if( getMixer()->hasFifoWriter() ) - { - CPU::freeFrames( b ); - } - - return frames; -} - - - - -void AudioDevice::stopProcessing() -{ - if( getMixer()->hasFifoWriter() ) - { - while( m_inProcess ) - { - processNextBuffer(); - } - } -} - - - - -void AudioDevice::applyQualitySettings() -{ - src_delete( m_srcState ); - - int error; - if( ( m_srcState = src_new( - getMixer()->currentQualitySettings().libsrcInterpolation(), - SURROUND_CHANNELS, &error ) ) == NULL ) - { - printf( "Error: src_new() failed in audio_device.cpp!\n" ); - } -} - - - - -void AudioDevice::registerPort( AudioPort * ) -{ -} - - - - -void AudioDevice::unregisterPort( AudioPort * _port ) -{ -} - - - - -void AudioDevice::renamePort( AudioPort * ) -{ -} - - - - -void AudioDevice::resample( const sampleFrame * _src, const fpp_t _frames, - sampleFrame * _dst, - const sample_rate_t _src_sr, - const sample_rate_t _dst_sr ) -{ - if( m_srcState == NULL ) - { - return; - } - m_srcData.input_frames = _frames; - m_srcData.output_frames = _frames; - m_srcData.data_in = (float *) _src[0]; - m_srcData.data_out = _dst[0]; - m_srcData.src_ratio = (double) _dst_sr / _src_sr; - m_srcData.end_of_input = 0; - int error; - if( ( error = src_process( m_srcState, &m_srcData ) ) ) - { - printf( "AudioDevice::resample(): error while resampling: %s\n", - src_strerror( error ) ); - } -} - - - -void AudioDevice::clearS16Buffer( intSampleFrameA * _outbuf, const fpp_t _frames ) -{ - CPU::memClear( _outbuf, _frames * sizeof( *_outbuf ) ); -// memset( _outbuf, 0, _frames * channels() * BYTES_PER_INT_SAMPLE ); -} - - - - -bool AudioDevice::hqAudio() const -{ - return configManager::inst()->value( "mixer", "hqaudio" ).toInt(); -} - - diff --git a/src/core/audio/AudioFileDevice.cpp b/src/core/audio/AudioFileDevice.cpp index e57c2a883..e92f41b47 100644 --- a/src/core/audio/AudioFileDevice.cpp +++ b/src/core/audio/AudioFileDevice.cpp @@ -39,8 +39,8 @@ AudioFileDevice::AudioFileDevice( const sample_rate_t _sample_rate, const bitrate_t _min_bitrate, const bitrate_t _max_bitrate, const int _depth, - mixer * _mixer ) : - AudioDevice( _channels, _mixer ), + AudioOutputContext * context ) : + AudioBackend( _channels, context ), m_outputFile( _file ), m_useVbr( _use_vbr ), m_nomBitrate( _nom_bitrate ), diff --git a/src/core/audio/AudioFileFlac.cpp b/src/core/audio/AudioFileFlac.cpp index cfcc7fc51..77e2fa731 100644 --- a/src/core/audio/AudioFileFlac.cpp +++ b/src/core/audio/AudioFileFlac.cpp @@ -37,9 +37,9 @@ AudioFileFlac::AudioFileFlac( const sample_rate_t _sample_rate, const ch_cnt_t _channels, bool & _success_ful, const QString & _file, const bool _use_vbr, const bitrate_t _nom_bitrate, const bitrate_t _min_bitrate, const bitrate_t _max_bitrate, - const int _depth, mixer * _mixer ) : + const int _depth, AudioOutputContext * context ) : AudioFileDevice( _sample_rate, _channels, _file, _use_vbr, _nom_bitrate, - _min_bitrate, _max_bitrate, _depth, _mixer ) + _min_bitrate, _max_bitrate, _depth, context ) { _success_ful = startEncoding(); } diff --git a/src/core/audio/AudioFileMp3.cpp b/src/core/audio/AudioFileMp3.cpp index e9569c99b..72252066e 100644 --- a/src/core/audio/AudioFileMp3.cpp +++ b/src/core/audio/AudioFileMp3.cpp @@ -38,9 +38,9 @@ AudioFileMp3::AudioFileMp3( const sample_rate_t _sample_rate, const ch_cnt_t _channels, bool & _success_ful, const QString & _file, const bool _use_vbr, const bitrate_t _nom_bitrate, const bitrate_t _min_bitrate, const bitrate_t _max_bitrate, - const int _depth, mixer * _mixer ) : + const int _depth, AudioOutputContext * context ) : AudioFileDevice( _sample_rate, _channels, _file, _use_vbr, _nom_bitrate, - _min_bitrate, _max_bitrate, _depth, _mixer ), + _min_bitrate, _max_bitrate, _depth, context ), m_lgf( NULL ), m_lame( LameLibrary() ), m_outfile( NULL ), diff --git a/src/core/audio/AudioFileOgg.cpp b/src/core/audio/AudioFileOgg.cpp index 3ef2856e7..781a3468a 100644 --- a/src/core/audio/AudioFileOgg.cpp +++ b/src/core/audio/AudioFileOgg.cpp @@ -44,10 +44,10 @@ AudioFileOgg::AudioFileOgg( const sample_rate_t _sample_rate, const bitrate_t _min_bitrate, const bitrate_t _max_bitrate, const int _depth, - mixer * _mixer ) : + AudioOutputContext * context ) : AudioFileDevice( _sample_rate, _channels, _file, _use_vbr, _nom_bitrate, _min_bitrate, _max_bitrate, - _depth, _mixer ) + _depth, context ) { m_ok = _success_ful = startEncoding(); } diff --git a/src/core/audio/AudioFileWave.cpp b/src/core/audio/AudioFileWave.cpp index b15ab339e..f52b784dd 100644 --- a/src/core/audio/AudioFileWave.cpp +++ b/src/core/audio/AudioFileWave.cpp @@ -36,10 +36,10 @@ AudioFileWave::AudioFileWave( const sample_rate_t _sample_rate, const bitrate_t _min_bitrate, const bitrate_t _max_bitrate, const int _depth, - mixer * _mixer ) : + AudioOutputContext * context ) : AudioFileDevice( _sample_rate, _channels, _file, _use_vbr, _nom_bitrate, _min_bitrate, _max_bitrate, - _depth, _mixer ) + _depth, context ) { _success_ful = startEncoding(); } @@ -59,7 +59,7 @@ bool AudioFileWave::startEncoding() { m_si.samplerate = sampleRate(); m_si.channels = channels(); - m_si.frames = getMixer()->framesPerPeriod(); + m_si.frames = mixer()->framesPerPeriod(); m_si.sections = 1; m_si.seekable = 0; diff --git a/src/core/audio/AudioJack.cpp b/src/core/audio/AudioJack.cpp index 737f5d462..9eb0856f5 100644 --- a/src/core/audio/AudioJack.cpp +++ b/src/core/audio/AudioJack.cpp @@ -45,15 +45,15 @@ -AudioJack::AudioJack( bool & _success_ful, mixer * _mixer ) : - AudioDevice( tLimit( configManager::inst()->value( +AudioJack::AudioJack( bool & _success_ful, AudioOutputContext * context ) : + AudioBackend( tLimit( configManager::inst()->value( "audiojack", "channels" ).toInt(), DEFAULT_CHANNELS, SURROUND_CHANNELS ), - _mixer ), + context ), m_client( NULL ), m_active( false ), m_stopSemaphore( 1 ), - m_outBuf( CPU::allocFrames( getMixer()->framesPerPeriod() ) ), + m_outBuf( CPU::allocFrames( mixer()->framesPerPeriod() ) ), m_framesDoneInCurBuf( 0 ), m_framesToDoInCurBuf( 0 ) { @@ -210,7 +210,7 @@ void AudioJack::startProcessing() // try to sync JACK's and LMMS's buffer-size -// jack_set_buffer_size( m_client, getMixer()->framesPerPeriod() ); +// jack_set_buffer_size( m_client, mixer()->framesPerPeriod() ); @@ -255,15 +255,13 @@ void AudioJack::applyQualitySettings() { if( hqAudio() ) { - setSampleRate( engine::getMixer()->processingSampleRate() ); + setSampleRate( mixer()->processingSampleRate() ); if( jack_get_sample_rate( m_client ) != sampleRate() ) { setSampleRate( jack_get_sample_rate( m_client ) ); } } - - AudioDevice::applyQualitySettings(); } @@ -343,7 +341,7 @@ int AudioJack::processCallback( jack_nframes_t _nframes, void * _udata ) #ifdef AUDIO_PORT_SUPPORT const Uint32 frames = qMin( _nframes, - getMixer()->framesPerPeriod() ); + mixer()->framesPerPeriod() ); for( jackPortMap::iterator it = m_portMap.begin(); it != m_portMap.end(); ++it ) { @@ -372,7 +370,7 @@ int AudioJack::processCallback( jack_nframes_t _nframes, void * _udata ) _nframes, m_framesToDoInCurBuf - m_framesDoneInCurBuf ); - const float gain = getMixer()->masterGain(); + const float gain = mixer()->masterGain(); for( ch_cnt_t chnl = 0; chnl < channels(); ++chnl ) { jack_default_audio_sample_t * o = outbufs[chnl]; @@ -434,7 +432,7 @@ void AudioJack::shutdownCallback( void * _udata ) AudioJack::setupWidget::setupWidget( QWidget * _parent ) : - AudioDevice::setupWidget( AudioJack::name(), _parent ) + AudioBackend::setupWidget( AudioJack::name(), _parent ) { QString cn = configManager::inst()->value( "audiojack", "clientname" ); if( cn.isEmpty() ) diff --git a/src/core/audio/AudioOss.cpp b/src/core/audio/AudioOss.cpp index 81cbfc05d..05dbf560b 100644 --- a/src/core/audio/AudioOss.cpp +++ b/src/core/audio/AudioOss.cpp @@ -74,11 +74,11 @@ -AudioOss::AudioOss( bool & _success_ful, mixer * _mixer ) : - AudioDevice( tLimit( +AudioOss::AudioOss( bool & _success_ful, AudioOutputContext * context ) : + AudioBackend( tLimit( configManager::inst()->value( "audiooss", "channels" ).toInt(), DEFAULT_CHANNELS, SURROUND_CHANNELS ), - _mixer ), + context ), m_convertEndian( false ) { _success_ful = false; @@ -106,7 +106,7 @@ AudioOss::AudioOss( bool & _success_ful, mixer * _mixer ) : int frag_spec; for( frag_spec = 0; static_cast( 0x01 << frag_spec ) < - getMixer()->framesPerPeriod() * channels() * + mixer()->framesPerPeriod() * channels() * BYTES_PER_INT_SAMPLE; ++frag_spec ) { @@ -178,7 +178,7 @@ AudioOss::AudioOss( bool & _success_ful, mixer * _mixer ) : } if( value != sampleRate() ) { - value = getMixer()->baseSampleRate(); + value = mixer()->baseSampleRate(); if ( ioctl( m_audioFD, SNDCTL_DSP_SPEED, &value ) < 0 ) { perror( "SNDCTL_DSP_SPEED" ); @@ -271,7 +271,7 @@ void AudioOss::applyQualitySettings() { if( hqAudio() ) { - setSampleRate( engine::getMixer()->processingSampleRate() ); + setSampleRate( mixer()->processingSampleRate() ); unsigned int value = sampleRate(); if ( ioctl( m_audioFD, SNDCTL_DSP_SPEED, &value ) < 0 ) @@ -282,7 +282,7 @@ void AudioOss::applyQualitySettings() } if( value != sampleRate() ) { - value = getMixer()->baseSampleRate(); + value = mixer()->baseSampleRate(); if ( ioctl( m_audioFD, SNDCTL_DSP_SPEED, &value ) < 0 ) { perror( "SNDCTL_DSP_SPEED" ); @@ -292,8 +292,6 @@ void AudioOss::applyQualitySettings() setSampleRate( value ); } } - - AudioDevice::applyQualitySettings(); } @@ -302,10 +300,10 @@ void AudioOss::applyQualitySettings() void AudioOss::run() { sampleFrameA * temp = CPU::allocFrames( - getMixer()->framesPerPeriod() ); + mixer()->framesPerPeriod() ); intSampleFrameA * outbuf = (intSampleFrameA *) CPU::memAlloc( sizeof( intSampleFrameA ) * - getMixer()->framesPerPeriod() ); + mixer()->framesPerPeriod() ); while( true ) { @@ -316,7 +314,7 @@ void AudioOss::run() } int bytes = CPU::convertToS16( temp, outbuf, frames, - getMixer()->masterGain(), + mixer()->masterGain(), m_convertEndian ); if( write( m_audioFD, outbuf, bytes ) != bytes ) { @@ -332,7 +330,7 @@ void AudioOss::run() AudioOss::setupWidget::setupWidget( QWidget * _parent ) : - AudioDevice::setupWidget( AudioOss::name(), _parent ) + AudioBackend::setupWidget( AudioOss::name(), _parent ) { m_device = new QLineEdit( probeDevice(), this ); m_device->setGeometry( 10, 20, 160, 20 ); diff --git a/src/core/audio/AudioOutputContext.cpp b/src/core/audio/AudioOutputContext.cpp new file mode 100644 index 000000000..ae3187e60 --- /dev/null +++ b/src/core/audio/AudioOutputContext.cpp @@ -0,0 +1,311 @@ +/* + * AudioOutputContext.cpp - centralize all audio output related functionality + * + * Copyright (c) 2009 Tobias Doerffel + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#include "AudioBackend.h" +#include "AudioOutputContext.h" +#include "Cpu.h" + +#include "config_mgr.h" +#include "engine.h" + +AudioOutputContext::BufferFifo::BufferFifo( int _size, int _bufferSize ) : + m_readerSem( _size ), + m_writerSem( _size ), + m_readerIndex( 0 ), + m_writerIndex( 0 ), + m_size( _size ), + m_bufferSize( _bufferSize ) +{ + m_buffers = new sampleFrameA *[m_size]; + for( int i = 0; i < m_size; ++i ) + { + m_buffers[i] = CPU::allocFrames( m_bufferSize ); + } + + m_bufferStates = new BufferState[m_size]; + + m_readerSem.acquire( _size ); +} + + + +AudioOutputContext::BufferFifo::~BufferFifo() +{ + for( int i = 0; i < m_size; ++i ) + { + CPU::freeFrames( m_buffers[i] ); + } + + delete[] m_buffers; + delete[] m_bufferStates; + + m_readerSem.release( m_size ); +} + + + + +void AudioOutputContext::BufferFifo::write( sampleFrameA * _buffer ) +{ + m_writerSem.acquire(); + + if( _buffer != NULL ) + { + CPU::memCpy( m_buffers[m_writerIndex], _buffer, + m_bufferSize * sizeof( sampleFrameA ) ); + m_bufferStates[m_writerIndex] = Running; + } + else + { + m_bufferStates[m_writerIndex] = NullBuffer; + } + + m_writerIndex = ( m_writerIndex + 1 ) % m_size; + + m_readerSem.release(); +} + + + + +void AudioOutputContext::BufferFifo::startRead() +{ + m_readerSem.acquire(); +} + + + + +void AudioOutputContext::BufferFifo::finishRead() +{ + m_readerIndex = ( m_readerIndex + 1 ) % m_size; + m_writerSem.release(); +} + + + + + + + +AudioOutputContext::AudioOutputContext( Mixer * mixer, + AudioBackend * audioBackend, + const QualitySettings & qualitySettings ) : + m_mixer( mixer ), + m_qualitySettings( qualitySettings ), + m_audioBackend( audioBackend ), + m_fifo( NULL ), + m_fifoWriter( NULL ) +{ + int error; + if( ( m_srcState = src_new( + qualitySettings.libsrcInterpolation(), + SURROUND_CHANNELS, &error ) ) == NULL ) + { + qWarning( "src_new() failed in AudioOutputContext::AudioOutputContext()" ); + } + //m_audioBackend->applyQualitySettings(); + + int framesPerPeriod = m_mixer->framesPerPeriod(); + + // just rendering? + if( !engine::hasGUI() ) + { + m_fifo = new BufferFifo( 1, framesPerPeriod ); + } + else if( configManager::inst()->value( "mixer", "framesperaudiobuffer" + ).toInt() >= 32 ) + { + framesPerPeriod = + (fpp_t) configManager::inst()->value( "mixer", + "framesperaudiobuffer" ).toInt(); + + if( framesPerPeriod > DEFAULT_BUFFER_SIZE ) + { + m_fifo = new BufferFifo( framesPerPeriod / DEFAULT_BUFFER_SIZE, + DEFAULT_BUFFER_SIZE ); + } + else + { + m_fifo = new BufferFifo( 1, framesPerPeriod ); + } + } + else + { + configManager::inst()->setValue( "mixer", + "framesperaudiobuffer", + QString::number( framesPerPeriod ) ); + m_fifo = new BufferFifo( 1, framesPerPeriod ); + } + +} + + + + +AudioOutputContext::~AudioOutputContext() +{ + while( m_fifo->isEmpty() == false ) + { + m_fifo->startRead(); + m_fifo->finishRead(); + } + delete m_fifo; + + src_delete( m_srcState ); +} + + + + +void AudioOutputContext::startProcessing() +{ + if( !isProcessing() ) + { + m_fifoWriter = new FifoWriter( this ); + m_fifoWriter->start( QThread::HighPriority ); + + m_audioBackend->startProcessing(); + } +} + + + + +void AudioOutputContext::stopProcessing() +{ + if( isProcessing() ) + { + m_fifoWriter->finish(); + m_audioBackend->stopProcessing(); + m_fifoWriter->wait(); + + delete m_fifoWriter; + m_fifoWriter = NULL; + } +} + + + + +bool AudioOutputContext::isProcessing() const +{ + return m_fifoWriter && m_fifoWriter->isRunning(); +} + + + + +int AudioOutputContext::getCurrentOutputBuffer( sampleFrameA * _destBuf, + sample_rate_t _destSampleRate ) +{ + int frames = mixer()->framesPerPeriod(); + m_fifo->startRead(); + if( m_fifo->currentReadBufferState() == BufferFifo::NullBuffer ) + { + m_fifo->finishRead(); + return 0; + } + sampleFrameA * srcBuf = m_fifo->currentReadBuffer(); + + if( mixer()->processingSampleRate() != _destSampleRate ) + { + if( m_srcState == NULL ) + { + m_fifo->finishRead(); + return 0; + } + m_srcData.input_frames = frames; + m_srcData.output_frames = frames; + m_srcData.data_in = (float *) srcBuf; + m_srcData.data_out = (float *) _destBuf; + m_srcData.src_ratio = (double) _destSampleRate / + mixer()->processingSampleRate(); + m_srcData.end_of_input = 0; + int error; + if( ( error = src_process( m_srcState, &m_srcData ) ) ) + { + qWarning( "AudioBackend::resample(): error while resampling: %s", + src_strerror( error ) ); + } + frames = frames * _destSampleRate / mixer()->processingSampleRate(); + } + else + { + CPU::memCpy( _destBuf, srcBuf, frames * sizeof( sampleFrameA ) ); + } + + // tell BufferFifo to release current read buffer + m_fifo->finishRead(); + + return frames; +} + + + + + + +AudioOutputContext::FifoWriter::FifoWriter( AudioOutputContext * context ) : + m_context( context ), + m_writing( true ) +{ +} + + + + +void AudioOutputContext::FifoWriter::finish() +{ + m_writing = false; +} + + + + +void AudioOutputContext::FifoWriter::run() +{ +#if 0 +#ifdef LMMS_BUILD_LINUX +#ifdef LMMS_HAVE_PTHREAD_H + cpu_set_t mask; + CPU_ZERO( &mask ); + CPU_SET( 0, &mask ); + pthread_setaffinity_np( pthread_self(), sizeof( mask ), &mask ); +#endif +#endif +#endif + + while( m_writing ) + { + m_context->fifo()->write( m_context->mixer()->renderNextBuffer() ); + } + + // write a NULL in order to signal the AudioBackend that the FifoWriter has + // finished + m_context->fifo()->write( NULL ); +} + + + diff --git a/src/core/audio/AudioPort.cpp b/src/core/audio/AudioPort.cpp index 2b4301178..8129fbfb0 100644 --- a/src/core/audio/AudioPort.cpp +++ b/src/core/audio/AudioPort.cpp @@ -23,7 +23,8 @@ */ #include "AudioPort.h" -#include "AudioDevice.h" +#include "AudioBackend.h" +#include "AudioOutputContext.h" #include "EffectChain.h" #include "engine.h" #include "Cpu.h" @@ -88,11 +89,13 @@ void AudioPort::setExtOutputEnabled( bool _enabled ) m_extOutputEnabled = _enabled; if( m_extOutputEnabled ) { - engine::getMixer()->audioDev()->registerPort( this ); + engine::mixer()->audioOutputContext()-> + audioBackend()->registerPort( this ); } else { - engine::getMixer()->audioDev()->unregisterPort( this ); + engine::mixer()->audioOutputContext()-> + audioBackend()->unregisterPort( this ); } } } @@ -103,7 +106,7 @@ void AudioPort::setExtOutputEnabled( bool _enabled ) void AudioPort::setName( const QString & _name ) { m_name = _name; - engine::getMixer()->audioDev()->renamePort( this ); + engine::mixer()->audioOutputContext()->audioBackend()->renamePort( this ); } diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index 3e0713252..e2742d9b5 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -50,7 +50,7 @@ void AudioPortAudioSetupUtil::updateChannels() AudioPortAudio::AudioPortAudio( bool & _success_ful, mixer * _mixer ) : - AudioDevice( tLimit( + AudioBackend( tLimit( configManager::inst()->value( "audioportaudio", "channels" ).toInt(), DEFAULT_CHANNELS, SURROUND_CHANNELS ), @@ -284,8 +284,6 @@ void AudioPortAudio::applyQualitySettings() return; } } - - audioDevice::applyQualitySettings(); } int AudioPortAudio::process_callback( diff --git a/src/core/audio/AudioPulseAudio.cpp b/src/core/audio/AudioPulseAudio.cpp index 539b1fba5..6bc621b20 100644 --- a/src/core/audio/AudioPulseAudio.cpp +++ b/src/core/audio/AudioPulseAudio.cpp @@ -46,11 +46,11 @@ static void stream_write_callback(pa_stream *s, size_t length, void *userdata) -AudioPulseAudio::AudioPulseAudio( bool & _success_ful, mixer * _mixer ) : - AudioDevice( tLimit( +AudioPulseAudio::AudioPulseAudio( bool & _success_ful, AudioOutputContext * context ) : + AudioBackend( tLimit( configManager::inst()->value( "audiopa", "channels" ).toInt(), DEFAULT_CHANNELS, SURROUND_CHANNELS ), - _mixer ), + context ), m_s( NULL ), m_quit( false ), m_convertEndian( false ) @@ -119,11 +119,9 @@ void AudioPulseAudio::applyQualitySettings() { if( hqAudio() ) { -// setSampleRate( engine::getMixer()->processingSampleRate() ); +// setSampleRate( mixer()->processingSampleRate() ); } - - AudioDevice::applyQualitySettings(); } @@ -139,12 +137,12 @@ static void stream_state_callback( pa_stream *s, void * userdata ) break; case PA_STREAM_READY: - qDebug( "Stream successfully created\n" ); + qDebug( "Stream successfully created" ); break; case PA_STREAM_FAILED: default: - qCritical( "Stream errror: %s\n", + qCritical( "Stream errror: %s", pa_strerror(pa_context_errno( pa_stream_get_context( s ) ) ) ); } @@ -166,7 +164,7 @@ static void context_state_callback(pa_context *c, void *userdata) case PA_CONTEXT_READY: { pa_cvolume cv; - qDebug( "Connection established.\n" ); + qDebug( "Connection established." ); _this->m_s = pa_stream_new( c, "lmms", &_this->m_sampleSpec, NULL); pa_stream_set_state_callback( _this->m_s, stream_state_callback, _this ); pa_stream_set_write_callback( _this->m_s, stream_write_callback, _this ); @@ -181,7 +179,8 @@ static void context_state_callback(pa_context *c, void *userdata) buffer_attr.minreq = (uint32_t)(-1); buffer_attr.fragsize = (uint32_t)(-1); - double latency = (double)( engine::getMixer()->framesPerPeriod() ) / + double latency = (double)( ( (const AudioPulseAudio *) _this )-> + mixer()->framesPerPeriod() ) / (double)_this->sampleRate(); // ask PulseAudio for the desired latency (which might not be approved) @@ -201,7 +200,7 @@ static void context_state_callback(pa_context *c, void *userdata) case PA_CONTEXT_FAILED: default: - qCritical( "Connection failure: %s\n", pa_strerror( pa_context_errno( c ) ) ); + qCritical( "Connection failure: %s", pa_strerror( pa_context_errno( c ) ) ); } } @@ -213,7 +212,7 @@ void AudioPulseAudio::run() pa_mainloop * mainLoop = pa_mainloop_new(); if( !mainLoop ) { - qCritical( "pa_mainloop_new() failed.\n" ); + qCritical( "pa_mainloop_new() failed." ); return; } pa_mainloop_api * mainloop_api = pa_mainloop_get_api( mainLoop ); @@ -250,7 +249,7 @@ void AudioPulseAudio::run() void AudioPulseAudio::streamWriteCallback( pa_stream *s, size_t length ) { - const fpp_t fpp = getMixer()->framesPerPeriod(); + const fpp_t fpp = mixer()->framesPerPeriod(); sampleFrameA * temp = CPU::allocFrames( fpp ); Sint16 * pcmbuf = (Sint16*)CPU::memAlloc( fpp * channels() * sizeof(Sint16) ); @@ -267,7 +266,7 @@ void AudioPulseAudio::streamWriteCallback( pa_stream *s, size_t length ) int bytes = CPU::convertToS16( temp, (intSampleFrameA *) pcmbuf, frames, - getMixer()->masterGain(), + mixer()->masterGain(), m_convertEndian ); if( bytes > 0 ) { @@ -285,7 +284,7 @@ void AudioPulseAudio::streamWriteCallback( pa_stream *s, size_t length ) AudioPulseAudio::setupWidget::setupWidget( QWidget * _parent ) : - AudioDevice::setupWidget( AudioPulseAudio::name(), _parent ) + AudioBackend::setupWidget( AudioPulseAudio::name(), _parent ) { m_device = new QLineEdit( AudioPulseAudio::probeDevice(), this ); m_device->setGeometry( 10, 20, 160, 20 ); diff --git a/src/core/audio/AudioSampleRecorder.cpp b/src/core/audio/AudioSampleRecorder.cpp index 4601182a5..d280c0468 100644 --- a/src/core/audio/AudioSampleRecorder.cpp +++ b/src/core/audio/AudioSampleRecorder.cpp @@ -26,14 +26,14 @@ #include "AudioSampleRecorder.h" #include "sample_buffer.h" -#include "debug.h" +#include "Cpu.h" AudioSampleRecorder::AudioSampleRecorder( const ch_cnt_t _channels, bool & _success_ful, - mixer * _mixer ) : - AudioDevice( _channels, _mixer ), + AudioOutputContext * context ) : + AudioBackend( _channels, context ), m_buffers() { _success_ful = true; @@ -46,7 +46,7 @@ AudioSampleRecorder::~AudioSampleRecorder() { while( !m_buffers.empty() ) { - delete[] m_buffers.front().first; + CPU::freeFrames( m_buffers.front().first ); m_buffers.erase( m_buffers.begin() ); } } @@ -72,9 +72,9 @@ void AudioSampleRecorder::createSampleBuffer( sampleBuffer * * _sample_buf ) { const f_cnt_t frames = framesRecorded(); // create buffer to store all recorded buffers in - sampleFrame * data = new sampleFrame[frames]; + sampleFrameA * data = CPU::allocFrames( frames ); // make sure buffer is cleaned up properly at the end... - sampleFrame * data_ptr = data; + sampleFrameA * data_ptr = data; #ifdef LMMS_DEBUG assert( data != NULL ); @@ -83,30 +83,24 @@ void AudioSampleRecorder::createSampleBuffer( sampleBuffer * * _sample_buf ) for( BufferList::ConstIterator it = m_buffers.begin(); it != m_buffers.end(); ++it ) { - memcpy( data_ptr, ( *it ).first, ( *it ).second * - sizeof( sampleFrame ) ); + CPU::memCpy( data_ptr, ( *it ).first, ( *it ).second * + sizeof( sampleFrameA ) ); data_ptr += ( *it ).second; } // create according sample-buffer out of big buffer *_sample_buf = new sampleBuffer( data, frames ); ( *_sample_buf )->setSampleRate( sampleRate() ); - delete[] data; + CPU::freeFrames( data ); } -void AudioSampleRecorder::writeBuffer( const surroundSampleFrame * _ab, +void AudioSampleRecorder::writeBuffer( const sampleFrameA * srcBuf, const fpp_t _frames, const float ) { - sampleFrame * buf = new sampleFrame[_frames]; - for( fpp_t frame = 0; frame < _frames; ++frame ) - { - for( ch_cnt_t chnl = 0; chnl < DEFAULT_CHANNELS; ++chnl ) - { - buf[frame][chnl] = _ab[frame][chnl]; - } - } + sampleFrameA * buf = CPU::allocFrames( _frames ); + CPU::memCpy( buf, srcBuf, _frames*sizeof( sampleFrameA ) ); m_buffers.push_back( qMakePair( buf, _frames ) ); } diff --git a/src/core/audio/AudioSdl.cpp b/src/core/audio/AudioSdl.cpp index 78affdb9a..bc62ffee0 100644 --- a/src/core/audio/AudioSdl.cpp +++ b/src/core/audio/AudioSdl.cpp @@ -38,16 +38,16 @@ -AudioSdl::AudioSdl( bool & _success_ful, mixer * _mixer ) : - AudioDevice( DEFAULT_CHANNELS, _mixer ), - m_outBuf( CPU::allocFrames( getMixer()->framesPerPeriod() ) ), +AudioSdl::AudioSdl( bool & _success_ful, AudioOutputContext * context ) : + AudioBackend( DEFAULT_CHANNELS, context ), + m_outBuf( CPU::allocFrames( mixer()->framesPerPeriod() ) ), m_convertedBufPos( 0 ), m_convertEndian( false ), m_stopSemaphore( 1 ) { _success_ful = false; - m_convertedBufSize = getMixer()->framesPerPeriod() * + m_convertedBufSize = mixer()->framesPerPeriod() * sizeof( intSampleFrameA ); m_convertedBuf = (intSampleFrameA *) CPU::memAlloc( m_convertedBufSize ); @@ -63,7 +63,7 @@ AudioSdl::AudioSdl( bool & _success_ful, mixer * _mixer ) : // of system, so we don't have // to convert the buffers m_audioHandle.channels = channels(); - m_audioHandle.samples = qMax( 1024, getMixer()->framesPerPeriod()*2 ); + m_audioHandle.samples = qMax( 1024, mixer()->framesPerPeriod()*2 ); m_audioHandle.callback = sdlAudioCallback; m_audioHandle.userdata = this; @@ -131,7 +131,7 @@ void AudioSdl::applyQualitySettings() { SDL_CloseAudio(); - setSampleRate( engine::getMixer()->processingSampleRate() ); + setSampleRate( mixer()->processingSampleRate() ); m_audioHandle.freq = sampleRate(); @@ -143,8 +143,6 @@ void AudioSdl::applyQualitySettings() qCritical( "Couldn't open SDL-audio: %s\n", SDL_GetError() ); } } - - AudioDevice::applyQualitySettings(); } @@ -186,7 +184,7 @@ void AudioSdl::sdlAudioCallback( Uint8 * _buf, int _len ) CPU::convertToS16( m_outBuf, m_convertedBuf, frames, - getMixer()->masterGain(), + mixer()->masterGain(), m_convertEndian ); } const int min_len = qMin( _len, m_convertedBufSize @@ -203,7 +201,7 @@ void AudioSdl::sdlAudioCallback( Uint8 * _buf, int _len ) AudioSdl::setupWidget::setupWidget( QWidget * _parent ) : - AudioDevice::setupWidget( AudioSdl::name(), _parent ) + AudioBackend::setupWidget( AudioSdl::name(), _parent ) { QString dev = configManager::inst()->value( "audiosdl", "device" ); m_device = new QLineEdit( dev, this ); diff --git a/src/core/engine.cpp b/src/core/engine.cpp index 6606619c9..0bb323b5e 100644 --- a/src/core/engine.cpp +++ b/src/core/engine.cpp @@ -37,7 +37,7 @@ #include "InstrumentTrack.h" #include "ladspa_2_lmms.h" #include "MainWindow.h" -#include "mixer.h" +#include "Mixer.h" #include "pattern.h" #include "piano_roll.h" #include "ProjectJournal.h" @@ -56,7 +56,7 @@ bool engine::s_hasGUI = true; bool engine::s_suppressMessages = false; float engine::s_framesPerTick; -mixer * engine::s_mixer = NULL; +Mixer * engine::s_mixer = NULL; FxMixer * engine::s_fxMixer = NULL; FxMixerView * engine::s_fxMixerView = NULL; MainWindow * engine::s_mainWindow = NULL; @@ -89,9 +89,11 @@ void engine::init( const bool _has_gui ) initPluginFileHandling(); s_projectJournal = new ProjectJournal; - s_mixer = new mixer; + s_mixer = new Mixer; + s_song = new song; + s_mixer->initDevices(); // init resource framework s_workingDirResourceDB = @@ -119,8 +121,6 @@ void engine::init( const bool _has_gui ) s_projectJournal->setJournalling( true ); - s_mixer->initDevices(); - s_midiControlListener = new MidiControlListener(); s_automationRecorder = new AutomationRecorder; diff --git a/src/core/main.cpp b/src/core/main.cpp index 41227025f..ec5b46b63 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -126,7 +126,8 @@ int main( int argc, char * * argv ) new QApplication( argc, argv ) ; - mixer::qualitySettings qs( mixer::qualitySettings::Mode_HighQuality ); + AudioOutputContext::QualitySettings qs( + AudioOutputContext::QualitySettings::Preset_HighQuality ); ProjectRenderer::OutputSettings os( 44100, false, 160, ProjectRenderer::Depth_16Bit ); ProjectRenderer::ExportFileFormats eff = ProjectRenderer::WaveFile; @@ -284,19 +285,23 @@ int main( int argc, char * * argv ) const QString ip = QString( argv[i + 1] ); if( ip == "linear" ) { - qs.interpolation = mixer::qualitySettings::Interpolation_Linear; + qs.setInterpolation( AudioOutputContext::QualitySettings:: + Interpolation_Linear ); } else if( ip == "sincfastest" ) { - qs.interpolation = mixer::qualitySettings::Interpolation_SincFastest; + qs.setInterpolation( AudioOutputContext::QualitySettings:: + Interpolation_SincFastest ); } else if( ip == "sincmedium" ) { - qs.interpolation = mixer::qualitySettings::Interpolation_SincMedium; + qs.setInterpolation( AudioOutputContext::QualitySettings:: + Interpolation_SincMedium ); } else if( ip == "sincbest" ) { - qs.interpolation = mixer::qualitySettings::Interpolation_SincBest; + qs.setInterpolation( AudioOutputContext::QualitySettings:: + Interpolation_SincBest ); } else { @@ -314,21 +319,25 @@ int main( int argc, char * * argv ) switch( o ) { case 1: - qs.oversampling = mixer::qualitySettings::Oversampling_None; - break; + qs.setOversampling( AudioOutputContext::QualitySettings:: + Oversampling_None ); + break; case 2: - qs.oversampling = mixer::qualitySettings::Oversampling_2x; - break; + qs.setOversampling( AudioOutputContext::QualitySettings:: + Oversampling_2x ); + break; case 4: - qs.oversampling = mixer::qualitySettings::Oversampling_4x; - break; + qs.setOversampling( AudioOutputContext::QualitySettings:: + Oversampling_4x ); + break; case 8: - qs.oversampling = mixer::qualitySettings::Oversampling_8x; - break; + qs.setOversampling( AudioOutputContext::QualitySettings:: + Oversampling_8x ); + break; default: - printf( "\nInvalid oversampling %s.\n\n" + printf( "\nInvalid oversampling %s.\n\n" "Try \"%s --help\" for more information.\n\n", argv[i + 1], argv[0] ); - return( EXIT_FAILURE ); + return EXIT_FAILURE; } ++i; } diff --git a/src/core/midi/MidiControlListener.cpp b/src/core/midi/MidiControlListener.cpp index f014cfc56..4a089f888 100644 --- a/src/core/midi/MidiControlListener.cpp +++ b/src/core/midi/MidiControlListener.cpp @@ -30,7 +30,6 @@ #include #include "MidiControlListener.h" -#include "mixer.h" #include "MidiClient.h" #include "MidiPort.h" #include "engine.h" diff --git a/src/core/midi/MidiController.cpp b/src/core/midi/MidiController.cpp index ba74a9e62..5cb60c61e 100644 --- a/src/core/midi/MidiController.cpp +++ b/src/core/midi/MidiController.cpp @@ -29,7 +29,6 @@ #include "song.h" #include "engine.h" -#include "mixer.h" #include "MidiClient.h" #include "MidiController.h" #include "automation_recorder.h" diff --git a/src/core/sample_buffer.cpp b/src/core/sample_buffer.cpp index 5958ea82c..4051524fa 100644 --- a/src/core/sample_buffer.cpp +++ b/src/core/sample_buffer.cpp @@ -24,7 +24,7 @@ #include "sample_buffer.h" -#include "mixer.h" +#include "Mixer.h" #include diff --git a/src/gui/ExportProjectDialog.cpp b/src/gui/ExportProjectDialog.cpp index 6ac5f6d7f..b8c8ccf8b 100644 --- a/src/gui/ExportProjectDialog.cpp +++ b/src/gui/ExportProjectDialog.cpp @@ -146,11 +146,12 @@ void ExportProjectDialog::startBtnClicked() ui->progressBar->setEnabled( true ); - mixer::qualitySettings qs = mixer::qualitySettings( - static_cast( - ui->interpolationCB->currentIndex() ), - static_cast( - ui->oversamplingCB->currentIndex() ), + AudioOutputContext::QualitySettings qs = + AudioOutputContext::QualitySettings( + static_cast( + ui->interpolationCB->currentIndex() ), + static_cast( + ui->oversamplingCB->currentIndex() ), ui->sampleExactControllersCB->isChecked(), ui->aliasFreeOscillatorsCB->isChecked() ); diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 453193dbd..307e96bf3 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -56,7 +56,7 @@ #include "plugin_browser.h" #include "SideBar.h" #include "config_mgr.h" -#include "mixer.h" +#include "Mixer.h" #include "project_notes.h" #include "setup_dialog.h" #include "AudioDummy.h" @@ -1470,9 +1470,9 @@ void MainWindow::browseHelp() void MainWindow::setHighQuality( bool _hq ) { - engine::getMixer()->changeQuality( mixer::qualitySettings( - _hq ? mixer::qualitySettings::Mode_HighQuality : - mixer::qualitySettings::Mode_Draft ) ); + /*engine::getMixer()->changeQuality( Mixer::qualitySettings( + _hq ? Mixer::qualitySettings::Mode_HighQuality : + Mixer::qualitySettings::Mode_Draft ) );*/ } diff --git a/src/gui/setup_dialog.cpp b/src/gui/setup_dialog.cpp index 10d783f69..05c813101 100644 --- a/src/gui/setup_dialog.cpp +++ b/src/gui/setup_dialog.cpp @@ -39,7 +39,6 @@ #include "tab_button.h" #include "tab_widget.h" #include "gui_templates.h" -#include "mixer.h" #include "ProjectJournal.h" #include "config_mgr.h" #include "embed.h" diff --git a/src/gui/song_editor.cpp b/src/gui/song_editor.cpp index 5bf826549..697b2b8af 100644 --- a/src/gui/song_editor.cpp +++ b/src/gui/song_editor.cpp @@ -35,6 +35,7 @@ #include +#include "AudioOutputContext.h" #include "song_editor.h" #include "combobox.h" #include "embed.h" @@ -43,7 +44,7 @@ #include "timeline.h" #include "tool_button.h" #include "tooltip.h" -#include "AudioDevice.h" +#include "AudioBackend.h" #include "piano_roll.h" @@ -130,7 +131,7 @@ songEditor::songEditor( song * _song, songEditor * & _engine_ptr ) : m_recordButton->setDisabled( true ); // disable record buttons if capturing is not supported - if( !engine::getMixer()->audioDev()->supportsCapture() ) + if( !engine::mixer()->audioOutputContext()->audioBackend()->supportsCapture() ) { m_recordButton->setDisabled( true ); m_recordAccompanyButton->setDisabled( true ); diff --git a/src/gui/widgets/EnvelopeAndLfoView.cpp b/src/gui/widgets/EnvelopeAndLfoView.cpp index cd68ad36c..dbc1f48c7 100644 --- a/src/gui/widgets/EnvelopeAndLfoView.cpp +++ b/src/gui/widgets/EnvelopeAndLfoView.cpp @@ -33,7 +33,7 @@ #include "gui_templates.h" #include "knob.h" #include "led_checkbox.h" -#include "mixer.h" +#include "Mixer.h" #include "mmp.h" #include "Oscillator.h" #include "pixmap_button.h" @@ -482,7 +482,7 @@ void EnvelopeAndLfoView::paintEvent( QPaintEvent * ) int graphYBase = LFO_GRAPH_Y + 3 + lfoGraphHeight / 2; const float framesForGraph = SECS_PER_LFO_OSCILLATION * - engine::getMixer()->baseSampleRate() / 10; + engine::mixer()->baseSampleRate() / 10; const float lfoGrayAmount = fabsf( m_lfoAmountKnob->value() ); p.setPen( QPen( QColor::fromHsvF( diff --git a/src/gui/widgets/InstrumentMidiIOView.cpp b/src/gui/widgets/InstrumentMidiIOView.cpp index 7db26499b..d8572a03d 100644 --- a/src/gui/widgets/InstrumentMidiIOView.cpp +++ b/src/gui/widgets/InstrumentMidiIOView.cpp @@ -33,7 +33,7 @@ #include "gui_templates.h" #include "lcd_spinbox.h" #include "MidiClient.h" -#include "mixer.h" +#include "Mixer.h" #include "tooltip.h" @@ -93,7 +93,7 @@ InstrumentMidiIOView::InstrumentMidiIOView( QWidget * _parent ) : m_outputProgramSpinBox, SLOT( setEnabled( bool ) ) ); - if( !engine::getMixer()->midiClient()->isRaw() ) + if( !engine::mixer()->midiClient()->isRaw() ) { m_rpBtn = new QToolButton( m_midiInputGroupBox ); m_rpBtn->setText( tr( "MIDI devices to receive MIDI events from" ) ); diff --git a/src/gui/widgets/cpuload_widget.cpp b/src/gui/widgets/cpuload_widget.cpp index 5856bfd6f..7b4db3a29 100644 --- a/src/gui/widgets/cpuload_widget.cpp +++ b/src/gui/widgets/cpuload_widget.cpp @@ -2,8 +2,8 @@ * cpuload_widget.cpp - widget for displaying CPU-load (partly based on * Hydrogen's CPU-load-widget) * - * Copyright (c) 2005-2007 Tobias Doerffel - * + * Copyright (c) 2005-2009 Tobias Doerffel + * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * * This program is free software; you can redistribute it and/or @@ -29,7 +29,7 @@ #include "cpuload_widget.h" #include "embed.h" #include "engine.h" -#include "mixer.h" +#include "Mixer.h" cpuloadWidget::cpuloadWidget( QWidget * _parent ) : @@ -90,7 +90,7 @@ void cpuloadWidget::paintEvent( QPaintEvent * ) void cpuloadWidget::updateCpuLoad() { // smooth load-values a bit - Uint8 new_load = ( m_currentLoad + engine::getMixer()->cpuLoad() ) / 2; + int new_load = ( m_currentLoad + engine::mixer()->cpuLoad() ) / 2; if( new_load != m_currentLoad ) { m_currentLoad = new_load; diff --git a/src/gui/widgets/visualization_widget.cpp b/src/gui/widgets/visualization_widget.cpp index dc017300f..e1de1d384 100644 --- a/src/gui/widgets/visualization_widget.cpp +++ b/src/gui/widgets/visualization_widget.cpp @@ -29,6 +29,7 @@ #include "visualization_widget.h" #include "gui_templates.h" #include "MainWindow.h" +#include "Mixer.h" #include "embed.h" #include "engine.h" #include "tooltip.h" @@ -40,16 +41,16 @@ visualizationWidget::visualizationWidget( const QPixmap & _bg, QWidget * _p, visualizationTypes _vtype ) : QWidget( _p ), s_background( _bg ), - m_points( new QPointF[engine::getMixer()->framesPerPeriod()] ), + m_points( new QPointF[engine::mixer()->framesPerPeriod()] ), m_active( false ) { setFixedSize( s_background.width(), s_background.height() ); setAttribute( Qt::WA_OpaquePaintEvent, true ); - const fpp_t frames = engine::getMixer()->framesPerPeriod(); + const fpp_t frames = engine::mixer()->framesPerPeriod(); m_buffer = new sampleFrame[frames]; - engine::getMixer()->clearAudioBuffer( m_buffer, frames ); + engine::mixer()->clearAudioBuffer( m_buffer, frames ); toolTip::add( this, tr( "click to enable/disable visualization of " @@ -72,12 +73,11 @@ void visualizationWidget::updateAudioBuffer() { if( !engine::getSong()->isExporting() ) { - engine::getMixer()->lock(); - const surroundSampleFrame * c = engine::getMixer()-> - currentReadBuffer(); - const fpp_t fpp = engine::getMixer()->framesPerPeriod(); + engine::mixer()->lock(); + const surroundSampleFrame * c = engine::mixer()->currentReadBuffer(); + const fpp_t fpp = engine::mixer()->framesPerPeriod(); memcpy( m_buffer, c, sizeof( surroundSampleFrame ) * fpp ); - engine::getMixer()->unlock(); + engine::mixer()->unlock(); } } @@ -92,7 +92,7 @@ void visualizationWidget::setActive( bool _active ) connect( engine::mainWindow(), SIGNAL( periodicUpdate() ), this, SLOT( update() ) ); - connect( engine::getMixer(), + connect( engine::mixer(), SIGNAL( nextAudioBuffer() ), this, SLOT( updateAudioBuffer() ) ); } @@ -101,7 +101,7 @@ void visualizationWidget::setActive( bool _active ) disconnect( engine::mainWindow(), SIGNAL( periodicUpdate() ), this, SLOT( update() ) ); - disconnect( engine::getMixer(), + disconnect( engine::mixer(), SIGNAL( nextAudioBuffer() ), this, SLOT( updateAudioBuffer() ) ); // we have to update (remove last waves), @@ -121,7 +121,7 @@ void visualizationWidget::paintEvent( QPaintEvent * ) if( m_active && !engine::getSong()->isExporting() ) { - float master_output = engine::getMixer()->masterGain(); + float master_output = engine::mixer()->masterGain(); int w = width()-4; const float half_h = -( height() - 6 ) / 3.0 * master_output - 1; int x_base = 2; @@ -131,10 +131,10 @@ void visualizationWidget::paintEvent( QPaintEvent * ) const fpp_t frames = - engine::getMixer()->framesPerPeriod(); + engine::mixer()->framesPerPeriod(); const float max_level = qMax( - mixer::peakValueLeft( m_buffer, frames ), - mixer::peakValueRight( m_buffer, frames ) ); + Mixer::peakValueLeft( m_buffer, frames ), + Mixer::peakValueRight( m_buffer, frames ) ); // and set color according to that... LmmsStyle::ColorRole levelColor; @@ -165,7 +165,7 @@ void visualizationWidget::paintEvent( QPaintEvent * ) { m_points[frame] = QPointF( x_base + (float) frame * xd, - y_base + ( mixer::clip( + y_base + ( Mixer::clip( m_buffer[frame][ch] ) * half_h ) ); } diff --git a/src/tracks/bb_track.cpp b/src/tracks/bb_track.cpp index 11a933bb2..96e920efa 100644 --- a/src/tracks/bb_track.cpp +++ b/src/tracks/bb_track.cpp @@ -33,7 +33,7 @@ #include "embed.h" #include "engine.h" #include "gui_templates.h" -#include "mixer.h" +#include "Mixer.h" #include "rename_dialog.h" #include "song.h" #include "song_editor.h" diff --git a/src/tracks/pattern.cpp b/src/tracks/pattern.cpp index 35a7e42d5..e713a6f90 100644 --- a/src/tracks/pattern.cpp +++ b/src/tracks/pattern.cpp @@ -33,6 +33,7 @@ #include #include +#include "AudioOutputContext.h" #include "pattern.h" #include "InstrumentTrack.h" #include "templates.h" @@ -735,15 +736,14 @@ patternFreezeThread::~patternFreezeThread() void patternFreezeThread::run() { - // create and install audio-sample-recorder + AudioOutputContext context( engine::mixer(), NULL, + engine::mixer()->defaultAudioOutputContext()->qualitySettings() ); + + // create and install AudioSampleRecorder bool b; - // we cannot create local copy, because at a later stage - // mixer::restoreAudioDevice(...) deletes old audio-dev and thus - // AudioSampleRecorder would be destroyed two times... - AudioSampleRecorder * freeze_recorder = new AudioSampleRecorder( - DEFAULT_CHANNELS, b, - engine::getMixer() ); - engine::getMixer()->setAudioDevice( freeze_recorder ); + AudioSampleRecorder freezeRecorder( DEFAULT_CHANNELS, b, &context ); + context.setAudioBackend( &freezeRecorder ); + engine::mixer()->setAudioOutputContext( &context ); // prepare stuff for playing correct things later engine::getSong()->playPattern( m_pattern, false ); @@ -761,7 +761,7 @@ void patternFreezeThread::run() while( ppp < m_pattern->length() && m_pattern->m_freezeAborted == false ) { - freeze_recorder->processNextBuffer(); + freezeRecorder.processNextBuffer(); m_statusDlg->setProgress( ppp * 100 / m_pattern->length() ); } m_statusDlg->setProgress( 100 ); @@ -769,7 +769,7 @@ void patternFreezeThread::run() while( engine::getMixer()->hasPlayHandles() && m_pattern->m_freezeAborted == false ) { - freeze_recorder->processNextBuffer(); + freezeRecorder.processNextBuffer(); } @@ -782,12 +782,13 @@ void patternFreezeThread::run() // create final sample-buffer if freezing was successful if( m_pattern->m_freezeAborted == false ) { - freeze_recorder->createSampleBuffer( + freezeRecorder.createSampleBuffer( &m_pattern->m_frozenPattern ); } // restore original audio-device - engine::getMixer()->restoreAudioDevice(); + engine::mixer()->setAudioOutputContext( + engine::mixer()->defaultAudioOutputContext() ); m_statusDlg->setProgress( -1 ); // we're finished