Merge branch 'mixer-new-fifo-arch'

* mixer-new-fifo-arch:
  ProjectRenderer: lock Mixer while calling Song::{start,stop}Export()
  ProjectRenderer: start thread with normal priority
  ProjectRenderer: renamed OutputSettings to EncoderSettings + Doxygen comments
  Mixer: rewrote processing chain of rendered audio buffers
This commit is contained in:
Tobias Doerffel
2009-11-30 00:56:54 +01:00
89 changed files with 1458 additions and 1199 deletions

View File

@@ -34,17 +34,17 @@
#include <alsa/asoundlib.h>
#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 );

View File

@@ -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 <tobydox/at/users.sourceforge.net>
*
@@ -26,37 +26,31 @@
#define _AUDIO_DEVICE_H
#include <QtCore/QPair>
#include <QtCore/QMutex>
#include <QtCore/QThread>
#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;

View File

@@ -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<Sint32>(
getMixer()->framesPerPeriod() *
1000000.0f /
getMixer()->processingSampleRate() -
timer.elapsed() );
mixer()->framesPerPeriod() * 1000000.0f /
mixer()->processingSampleRate() - timer.elapsed() );
if( microseconds > 0 )
{
usleep( microseconds );
}
}
CPU::freeFrames( buf );
}
} ;

View File

@@ -28,10 +28,10 @@
#include <QtCore/QFile>
#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

View File

@@ -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 );
}

View File

@@ -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 );
}

View File

@@ -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 );
}

View File

@@ -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 <tobydox/at/users.sourceforge.net>
@@ -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 );
}

View File

@@ -31,22 +31,22 @@
#include <jack/jack.h>
#endif
#include <QtCore/QVector>
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QSemaphore>
#include <QtCore/QVector>
#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 );

View File

@@ -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 );

View File

@@ -0,0 +1,377 @@
/*
* AudioOutputContext.h - centralize all audio output related functionality
*
* Copyright (c) 2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* 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 <QtCore/QSemaphore>
#include <QtCore/QThread>
#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

View File

@@ -28,7 +28,7 @@
#include <QtCore/QString>
#include <QtCore/QMutex>
#include "mixer.h"
#include "Mixer.h"
class EffectChain;
@@ -140,7 +140,7 @@ private:
EffectChain * m_effects;
friend class mixer;
friend class Mixer;
friend class MixerWorkerThread;
} ;

View File

@@ -47,7 +47,7 @@ public:
#include <portaudio.h>
#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 );

View File

@@ -31,17 +31,17 @@
#include <pulse/pulseaudio.h>
#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 );

View File

@@ -29,16 +29,16 @@
#include <QtCore/QList>
#include <QtCore/QPair>
#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<QPair<sampleFrame *, fpp_t> > BufferList;
typedef QList<QPair<sampleFrameA *, fpp_t> > BufferList;
BufferList m_buffers;
} ;

View File

@@ -29,18 +29,20 @@
#ifdef LMMS_HAVE_SDL
#include <QtCore/QSemaphore>
#include <SDL/SDL.h>
#include <SDL/SDL_audio.h>
#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 );

View File

@@ -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;
}

View File

@@ -28,7 +28,7 @@
#include "Plugin.h"
#include "engine.h"
#include "mixer.h"
#include "Mixer.h"
#include "AutomatableModel.h"
#include "TempoSyncKnobModel.h"

View File

@@ -28,7 +28,7 @@
#include "Model.h"
#include "SerializingObject.h"
#include "mixer.h"
#include "Mixer.h"
#include "AutomatableModel.h"
class Effect;

View File

@@ -26,7 +26,7 @@
#define _FX_MIXER_H
#include "Model.h"
#include "mixer.h"
#include "Mixer.h"
#include "EffectChain.h"
#include "JournallingObject.h"

View File

@@ -29,7 +29,7 @@
#include <QtGui/QWidget>
#include "Plugin.h"
#include "mixer.h"
#include "Mixer.h"
// forward-declarations

View File

@@ -25,7 +25,7 @@
#ifndef _INSTRUMENT_SOUND_SHAPING_H
#define _INSTRUMENT_SOUND_SHAPING_H
#include "mixer.h"
#include "Mixer.h"
#include "ComboBoxModel.h"

View File

@@ -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 <tobydox/at/users.sourceforge.net>
*
@@ -39,19 +39,18 @@
#include <QtCore/QMutex>
#include <QtCore/QThread>
#include <QtCore/QVector>
#include <QtCore/QWaitCondition>
#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;
@@ -68,104 +67,11 @@ class MixerWorkerThread;
#include "play_handle.h"
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 +82,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 +156,7 @@ public:
return m_framesPerPeriod;
}
inline const surroundSampleFrame * currentReadBuffer() const
inline const sampleFrameA * currentReadBuffer() const
{
return m_readBuf;
}
@@ -257,11 +167,6 @@ public:
return m_cpuLoad;
}
const qualitySettings & currentQualitySettings() const
{
return m_qualitySettings;
}
sample_rate_t baseSampleRate() const;
sample_rate_t outputSampleRate() const;
@@ -325,11 +230,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 +237,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 +249,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<surroundSampleFrame *> 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<AudioPort *> m_audioPorts;
fpp_t m_framesPerPeriod;
@@ -415,35 +281,35 @@ private:
f_cnt_t m_inputBufferSize[2];
int m_inputBufferRead;
int m_inputBufferWrite;
surroundSampleFrame * m_readBuf;
surroundSampleFrame * m_writeBuf;
QVector<surroundSampleFrame *> m_bufferPool;
sampleFrameA * m_readBuf;
sampleFrameA * m_writeBuf;
QVector<sampleFrameA *> 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<MixerWorkerThread *> m_workers;
int m_numWorkers;
QWaitCondition m_queueReadyWaitCond;
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;
@@ -455,10 +321,6 @@ private:
QMutex m_inputFramesMutex;
fifo * m_fifo;
fifoWriter * m_fifoWriter;
friend class engine;
} ;

View File

@@ -28,7 +28,7 @@
#include <QtCore/QAtomicPointer>
#include <QtCore/QThread>
#include "mixer.h"
#include "Mixer.h"
class MixerWorkerThread : public QThread
@@ -69,7 +69,7 @@ public:
} ;
MixerWorkerThread( mixer * _mixer );
MixerWorkerThread( Mixer * _mixer );
virtual ~MixerWorkerThread();
virtual void quit();

View File

@@ -26,42 +26,46 @@
#define _PROJECT_RENDERER_H
#include "AudioFileDevice.h"
#include "AudioOutputContext.h"
#include "lmmsconfig.h"
class QTimer;
/*! \brief The ProjectRenderer class provides functionality to render current Song into a file. */
class ProjectRenderer : public QThread
{
Q_OBJECT
public:
/*! Lists all supported output file formats. */
enum ExportFileFormats
{
WaveFile,
OggFile,
Mp3File,
FlacFile,
WaveFile, /*!< Uncompressed WAV file */
OggFile, /*!< Vorbis-encoded OGG file */
Mp3File, /*!< MP3 file encoded via LAME */
FlacFile, /*!< Free Lossless Audio Codec */
NumFileFormats
} ;
static const char * EFF_ext[];
/*! Lists all supported sample type depths. */
enum Depths
{
Depth_16Bit,
Depth_24Bit,
Depth_32Bit,
Depth_16Bit, /*!< 16 bit signed integer */
Depth_24Bit, /*!< 24 bit floating point */
Depth_32Bit, /*!< 32 bit floating point */
NumDepths
} ;
struct OutputSettings
/*! Settings for the output file encoder. */
struct EncoderSettings
{
sample_rate_t samplerate;
bool vbr;
int bitrate;
Depths depth;
sample_rate_t samplerate; /*!< Desired output sample rate */
bool vbr; /*!< Use variable bitrate encoding */
int bitrate; /*!< Desired bitrate (kbps) */
Depths depth; /*!< Depth of samples */
OutputSettings( sample_rate_t _sr, bool _vbr, int _bitrate,
Depths _d ) :
EncoderSettings( sample_rate_t _sr, bool _vbr, int _bitrate, Depths _d ) :
samplerate( _sr ),
vbr( _vbr ),
bitrate( _bitrate ),
@@ -70,30 +74,40 @@ public:
}
} ;
ProjectRenderer( const mixer::qualitySettings & _qs,
const OutputSettings & _os,
ExportFileFormats _file_format,
const QString & _out_file );
/*! \brief Constructs a ProjectRenderer object with given settings.
*
* \param qualitySettings The desired quality settings for the AudioOutputContext
* \param encoderSettings The desired settings for the output file encoder
* \param fileFormat One of the file formats listed in the ExportFileFormats enumeration
* \param outFile The output file name
*/
ProjectRenderer( const AudioOutputContext::QualitySettings & qualitySettings,
const EncoderSettings & encoderSettings,
ExportFileFormats fileFormat,
const QString & outFile );
virtual ~ProjectRenderer();
/*! \brief Returns whether the ProjectRenderer was initialized properly. */
bool isReady() const
{
return m_fileDev != NULL;
}
static ExportFileFormats getFileFormatFromExtension(
const QString & _ext );
static ExportFileFormats getFileFormatFromExtension( const QString & _ext );
void setConsoleUpdateTimer(QTimer * t)
void setConsoleUpdateTimer( QTimer * t )
{
m_consoleUpdateTimer = t;
}
public slots:
/*! \brief Sets according AudioOutputContext for Mixer and starts render thread. */
void startProcessing();
/*! \brief Aborts the processing and cleans up resources. */
void abortProcessing();
/*! \brief Prints current render progress to the console. */
void updateConsoleProgress();
@@ -101,12 +115,16 @@ signals:
void progressChanged( int );
private slots:
/*! \brief Finalizes the render process and restores Mixer's AudioOutputContext. */
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;
@@ -116,6 +134,7 @@ private:
} ;
/*! \brief Holds information about a certain file encoder. */
struct FileEncodeDevice
{
ProjectRenderer::ExportFileFormats m_fileFormat;

View File

@@ -27,7 +27,7 @@
#include <QtCore/QAtomicInt>
#include "mixer.h"
#include "Mixer.h"
class ThreadableJob

View File

@@ -36,7 +36,7 @@
#include <math.h>
#include "lmms_basics.h"
#include "mixer.h"
#include "Mixer.h"
#include "templates.h"
#include "lmms_constants.h"

View File

@@ -51,7 +51,7 @@ protected slots:
private:
Uint8 m_currentLoad;
int m_currentLoad;
QPixmap m_temp;
QPixmap m_background;

View File

@@ -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;

View File

@@ -1,89 +0,0 @@
/*
* fifo_buffer.h - FIFO fixed-size buffer
*
* Copyright (c) 2007 Javier Serrano Polo <jasp00/at/users.sourceforge.net>
* Copyright (c) 2008 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* 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 <QtCore/QSemaphore>
template<typename T>
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

View File

@@ -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"

View File

@@ -31,6 +31,6 @@
#include <limits>
#include "mixer.h"
#include "Mixer.h"
#endif

View File

@@ -25,8 +25,10 @@
#ifndef _PLAY_HANDLE_H
#define _PLAY_HANDLE_H
#include <QtCore/QThread>
#include "ThreadableJob.h"
#include "mixer.h"
#include "Mixer.h"
class track;

View File

@@ -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"

View File

@@ -30,7 +30,7 @@
#include <QtCore/QPair>
#include <qobject.h>
#include "mixer.h"
#include "Mixer.h"
#include "sample_buffer.h"
class bbTrack;

View File

@@ -29,7 +29,7 @@
#include <QtCore/QMap>
#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<QString, AudioDevice::setupWidget *> AswMap;
typedef QMap<QString, AudioBackend::setupWidget *> AswMap;
typedef QMap<QString, MidiClient::setupWidget *> MswMap;
typedef QMap<QString, QString> trMap;

View File

@@ -31,7 +31,7 @@
#include <QtGui/QWidget>
#include "AutomatableModel.h"
#include "mixer.h"
#include "Mixer.h"
class QPixmap;

View File

@@ -29,7 +29,7 @@
#include <QtGui/QWidget>
#include <QtGui/QPixmap>
#include "mixer.h"
#include "Mixer.h"
class visualizationWidget : public QWidget

View File

@@ -2,6 +2,7 @@
* ladspa_description.cpp - LADSPA plugin description
*
* Copyright (c) 2007 Javier Serrano Polo <jasp00/at/users.sourceforge.net>
* Copyright (c) 2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -30,10 +31,11 @@
#include <QtGui/QScrollArea>
#include <QtGui/QVBoxLayout>
#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 );

View File

@@ -2,7 +2,8 @@
* ladspa_port_dialog.cpp - dialog to test a LADSPA plugin
*
* Copyright (c) 2006-2008 Danny McRae <khjklujn/at/users.sourceforge.net>
*
* Copyright (c) 2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* 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 <QtGui/QLayout>
@@ -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();
}
}

View File

@@ -25,14 +25,15 @@
#include <QtGui/QMessageBox>
#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();
}

View File

@@ -28,12 +28,13 @@
#include <QtGui/QHBoxLayout>
#include <QtGui/QLabel>
#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 ) );
}

View File

@@ -37,7 +37,6 @@
#include "InstrumentView.h"
#include "led_checkbox.h"
#include "knob.h"
#include "mixer.h"
class lb302SynthView;
class notePlayHandle;

View File

@@ -30,6 +30,8 @@
#include <QtGui/QFileDialog>
#include <QtXml/QDomDocument>
#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<int>( 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-"

View File

@@ -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 )

View File

@@ -29,7 +29,6 @@
#include <QtCore/QMutex>
#include <QtGui/QWidget>
#include "mixer.h"
#include "JournallingObject.h"
#include "communication.h"

View File

@@ -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"

View File

@@ -30,7 +30,6 @@
#include "song.h"
#include "engine.h"
#include "mixer.h"
#include "ControllerConnection.h"

View File

@@ -23,11 +23,11 @@
*
*/
#include <QtXml/QDomElement>
#include <cstdio>
#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" );

View File

@@ -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"

View File

@@ -31,7 +31,6 @@
#include "song.h"
#include "engine.h"
#include "mixer.h"
#include "LfoController.h"
#include "ControllerDialog.h"

View File

@@ -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 <tobydox/at/users.sourceforge.net>
*
@@ -24,7 +24,8 @@
#include <math.h>
#include "mixer.h"
#include "AudioOutputContext.h"
#include "Mixer.h"
#include "FxMixer.h"
#include "MixerWorkerThread.h"
#include "play_handle.h"
@@ -62,8 +63,10 @@
#endif
mixer::mixer() :
m_framesPerPeriod( DEFAULT_BUFFER_SIZE ),
Mixer::Mixer() :
m_framesPerPeriod( qBound<int>( 32,
configManager::inst()->value( "mixer", "framesperaudiobuffer" ).toInt(),
DEFAULT_BUFFER_SIZE ) ),
m_workingBuf( NULL ),
m_inputBufferRead( 0 ),
m_inputBufferWrite( 1 ),
@@ -72,53 +75,21 @@ mixer::mixer() :
m_cpuLoad( 0 ),
m_workers(),
m_numWorkers( QThread::idealThreadCount()-1 ),
m_qualitySettings( qualitySettings::Mode_Draft ),
m_queueReadyWaitCond(),
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] );
}
// 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++ )
{
@@ -140,12 +111,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()
{
for( int w = 0; w < m_numWorkers; ++w )
{
@@ -157,13 +133,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++ )
@@ -177,54 +147,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();
@@ -238,33 +208,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;
}
@@ -272,14 +245,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 );
@@ -292,25 +265,24 @@ 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;
FxMixer * fxm = engine::fxMixer();
song::playPos p = engine::getSong()->getPlayPos(
song::Mode_PlayPattern );
song::playPos p = engine::getSong()->getPlayPos( song::Mode_PlayPattern );
if( engine::getSong()->playMode() == song::Mode_PlayPattern &&
engine::getPianoRoll()->isRecording() == true &&
p != last_metro_pos && p.getTicks() %
@@ -423,7 +395,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();
@@ -443,7 +415,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,
@@ -483,7 +455,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 ) )
@@ -498,18 +470,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 )
@@ -529,7 +491,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 )
@@ -549,97 +511,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<AudioPort *>::Iterator it = qFind( m_audioPorts.begin(),
m_audioPorts.end(),
@@ -655,7 +527,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
@@ -682,7 +554,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();
@@ -706,10 +578,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() )
@@ -720,7 +592,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();
@@ -734,7 +606,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();
@@ -748,7 +620,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();
@@ -762,7 +634,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();
@@ -776,7 +648,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();
@@ -790,7 +662,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();
@@ -801,7 +673,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;
@@ -814,13 +686,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" );
@@ -885,46 +757,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()
{
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"

View File

@@ -25,7 +25,6 @@
#include "MixerWorkerThread.h"
#include "Cpu.h"
#include "engine.h"
#include "mixer.h"
MixerWorkerThread::JobQueue MixerWorkerThread::globalJobQueue;
@@ -98,7 +97,7 @@ void MixerWorkerThread::JobQueue::wait()
// implementation of worker threads
MixerWorkerThread::MixerWorkerThread( mixer * _mixer ) :
MixerWorkerThread::MixerWorkerThread( Mixer * _mixer ) :
QThread( _mixer ),
m_workingBuf( CPU::allocFrames( _mixer->framesPerPeriod() ) ),
m_quit( false )

View File

@@ -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 )
{

View File

@@ -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"

View File

@@ -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"

View File

@@ -22,7 +22,6 @@
*
*/
#include <QtCore/QFile>
#include <QTimer>
@@ -60,9 +59,9 @@ FileEncodeDevice __fileEncodeDevices[] =
".mp3", &AudioFileMp3::getInst },
{ ProjectRenderer::FlacFile,
QT_TRANSLATE_NOOP( "ProjectRenderer", "FLAC File (*.flac)" ),
".flac",
".flac",
#ifdef LMMS_HAVE_FLAC
&AudioFileFlac::getInst
&AudioFileFlac::getInst
#else
NULL
#endif
@@ -77,36 +76,40 @@ FileEncodeDevice __fileEncodeDevices[] =
const char * ProjectRenderer::EFF_ext[] = {"wav", "ogg", "mp3", "flac"};
ProjectRenderer::ProjectRenderer( const mixer::qualitySettings & _qs,
const OutputSettings & _os,
ExportFileFormats _file_format,
const QString & _out_file ) :
ProjectRenderer::ProjectRenderer(
const AudioOutputContext::QualitySettings & _qs,
const EncoderSettings & es,
ExportFileFormats fileFormat,
const QString & outFile ) :
QThread( engine::getMixer() ),
m_fileDev( NULL ),
m_qualitySettings( _qs ),
m_oldQualitySettings( engine::getMixer()->currentQualitySettings() ),
m_progress( 0 ),
m_abort( false )
{
if( __fileEncodeDevices[_file_format].m_getDevInst == NULL )
m_context = new AudioOutputContext( engine::getMixer(),
NULL,
_qs );
if( __fileEncodeDevices[fileFormat].m_getDevInst == NULL )
{
return;
}
bool success_ful = false;
m_fileDev = __fileEncodeDevices[_file_format].m_getDevInst(
_os.samplerate, DEFAULT_CHANNELS, success_ful,
_out_file, _os.vbr,
_os.bitrate, _os.bitrate - 64, _os.bitrate + 64,
_os.depth == Depth_32Bit ? 32 :
( _os.depth == Depth_24Bit ? 24 : 16 ),
engine::getMixer() );
m_fileDev = __fileEncodeDevices[fileFormat].m_getDevInst(
es.samplerate, DEFAULT_CHANNELS, success_ful,
outFile, es.vbr,
es.bitrate, es.bitrate - 64, es.bitrate + 64,
es.depth == Depth_32Bit ? 32 :
( es.depth == Depth_24Bit ? 24 : 16 ),
m_context );
if( success_ful == false )
{
delete m_fileDev;
m_fileDev = NULL;
}
m_context->setAudioBackend( m_fileDev );
}
@@ -114,6 +117,8 @@ ProjectRenderer::ProjectRenderer( const mixer::qualitySettings & _qs,
ProjectRenderer::~ProjectRenderer()
{
delete m_fileDev;
delete m_context;
}
@@ -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,66 +149,14 @@ 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
QThread::HighPriority
#endif
);
}
}
void ProjectRenderer::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
engine::getSong()->startExport();
song::playPos & pp = engine::getSong()->getPlayPos(
song::Mode_PlaySong );
m_progress = 0;
const int sl = ( engine::getSong()->length() + 1 ) * 192;
while( engine::getSong()->isExportDone() == false &&
engine::getSong()->isExporting() == true
&& !m_abort )
{
m_fileDev->processNextBuffer();
const int nprog = pp * 100 / sl;
if( m_progress != nprog )
{
m_progress = nprog;
emit progressChanged( m_progress );
}
}
engine::getSong()->stopExport();
const QString f = m_fileDev->outputFile();
engine::getMixer()->restoreAudioDevice(); // also deletes audio-dev
engine::getMixer()->changeQuality( m_oldQualitySettings );
// if the user aborted export-process, the file has to be deleted
if( m_abort )
{
QFile( f ).remove();
start();
}
}
@@ -217,6 +170,7 @@ void ProjectRenderer::abortProcessing()
void ProjectRenderer::updateConsoleProgress()
{
const int cols = 50;
@@ -224,7 +178,8 @@ void ProjectRenderer::updateConsoleProgress()
char buf[80];
char prog[cols+1];
if( m_fileDev == NULL ){
if( m_fileDev == NULL )
{
qWarning("Error occured. Aborting render.");
m_consoleUpdateTimer->stop();
delete m_consoleUpdateTimer;
@@ -250,5 +205,68 @@ void ProjectRenderer::updateConsoleProgress()
void ProjectRenderer::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
// have to lock Mixer when touching Song's state as the FIFO writer thread
// may call Mixer::renderNextBuffer() (which calls Song::doActions())
// simultaneously
engine::mixer()->lock();
engine::getSong()->startExport();
engine::mixer()->unlock();
song::playPos & pp = engine::getSong()->getPlayPos(
song::Mode_PlaySong );
m_progress = 0;
const int sl = ( engine::getSong()->length() + 1 ) * 192;
while( engine::getSong()->isExportDone() == false &&
engine::getSong()->isExporting() == true
&& !m_abort )
{
m_fileDev->processNextBuffer();
const int nprog = pp * 100 / sl;
if( m_progress != nprog )
{
m_progress = nprog;
emit progressChanged( m_progress );
}
}
engine::mixer()->lock();
engine::getSong()->stopExport();
engine::mixer()->unlock();
}
void ProjectRenderer::finishProcessing()
{
const QString f = m_fileDev->outputFile();
engine::mixer()->setAudioOutputContext(
engine::mixer()->defaultAudioOutputContext() );
// if the user aborted export-process, the file has to be deleted
if( m_abort )
{
QFile( f ).remove();
}
}
#include "moc_ProjectRenderer.cxx"

View File

@@ -29,7 +29,7 @@
#endif
#include "RemotePlugin.h"
#include "mixer.h"
#include "Mixer.h"
#include "engine.h"
#include "config_mgr.h"

View File

@@ -40,11 +40,11 @@
AudioAlsa::AudioAlsa( bool & _success_ful, mixer * _mixer ) :
AudioDevice( tLimit<ch_cnt_t>(
AudioAlsa::AudioAlsa( bool & _success_ful, AudioOutputContext * context ) :
AudioBackend( tLimit<ch_cnt_t>(
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 );

View File

@@ -0,0 +1,144 @@
/*
* AudioBackend.cpp - base-class for audio-devices used by LMMS-mixer
*
* Copyright (c) 2004-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* 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();
}

View File

@@ -1,208 +0,0 @@
/*
* AudioDevice.cpp - base-class for audio-devices used by LMMS-mixer
*
* Copyright (c) 2004-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* 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();
}

View File

@@ -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 ),

View File

@@ -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();
}

View File

@@ -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 ),

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -45,15 +45,15 @@
AudioJack::AudioJack( bool & _success_ful, mixer * _mixer ) :
AudioDevice( tLimit<int>( configManager::inst()->value(
AudioJack::AudioJack( bool & _success_ful, AudioOutputContext * context ) :
AudioBackend( tLimit<int>( 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<Uint32>( _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() )

View File

@@ -74,11 +74,11 @@
AudioOss::AudioOss( bool & _success_ful, mixer * _mixer ) :
AudioDevice( tLimit<ch_cnt_t>(
AudioOss::AudioOss( bool & _success_ful, AudioOutputContext * context ) :
AudioBackend( tLimit<ch_cnt_t>(
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<int>( 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 );

View File

@@ -0,0 +1,311 @@
/*
* AudioOutputContext.cpp - centralize all audio output related functionality
*
* Copyright (c) 2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* 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 );
}

View File

@@ -22,8 +22,9 @@
*
*/
#include "AudioBackend.h"
#include "AudioOutputContext.h"
#include "AudioPort.h"
#include "AudioDevice.h"
#include "Cpu.h"
#include "EffectChain.h"
#include "FxMixer.h"
@@ -89,11 +90,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 );
}
}
}
@@ -104,7 +107,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 );
}

View File

@@ -50,7 +50,7 @@ void AudioPortAudioSetupUtil::updateChannels()
AudioPortAudio::AudioPortAudio( bool & _success_ful, mixer * _mixer ) :
AudioDevice( tLimit<ch_cnt_t>(
AudioBackend( tLimit<ch_cnt_t>(
configManager::inst()->value( "audioportaudio",
"channels" ).toInt(),
DEFAULT_CHANNELS, SURROUND_CHANNELS ),
@@ -284,8 +284,6 @@ void AudioPortAudio::applyQualitySettings()
return;
}
}
audioDevice::applyQualitySettings();
}
int AudioPortAudio::process_callback(

View File

@@ -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<ch_cnt_t>(
AudioPulseAudio::AudioPulseAudio( bool & _success_ful, AudioOutputContext * context ) :
AudioBackend( tLimit<ch_cnt_t>(
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 );

View File

@@ -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 ) );
}

View File

@@ -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 );

View File

@@ -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;

View File

@@ -22,7 +22,6 @@
*
*/
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QLocale>
@@ -127,9 +126,10 @@ int main( int argc, char * * argv )
new QApplication( argc, argv ) ;
mixer::qualitySettings qs( mixer::qualitySettings::Mode_HighQuality );
ProjectRenderer::OutputSettings os( 44100, false, 160,
ProjectRenderer::Depth_16Bit );
AudioOutputContext::QualitySettings qs(
AudioOutputContext::QualitySettings::Preset_HighQuality );
ProjectRenderer::EncoderSettings es( 44100, false, 160,
ProjectRenderer::Depth_16Bit );
ProjectRenderer::ExportFileFormats eff = ProjectRenderer::WaveFile;
@@ -251,7 +251,7 @@ int main( int argc, char * * argv )
sample_rate_t sr = QString( argv[i + 1] ).toUInt();
if( sr >= 44100 && sr <= 192000 )
{
os.samplerate = sr;
es.samplerate = sr;
}
else
{
@@ -268,7 +268,7 @@ int main( int argc, char * * argv )
int br = QString( argv[i + 1] ).toUInt();
if( br >= 64 && br <= 384 )
{
os.bitrate = br;
es.bitrate = br;
}
else
{
@@ -285,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
{
@@ -315,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;
}
@@ -514,7 +522,7 @@ int main( int argc, char * * argv )
if( !render_out.isEmpty() )
{
// create renderer
ProjectRenderer * r = new ProjectRenderer( qs, os, eff,
ProjectRenderer * r = new ProjectRenderer( qs, es, eff,
render_out + QString( ProjectRenderer::EFF_ext[eff] ) );
QCoreApplication::instance()->connect( r,
SIGNAL( finished() ), SLOT( quit() ) );

View File

@@ -30,7 +30,6 @@
#include <QtXml/QDomNodeList>
#include "MidiControlListener.h"
#include "mixer.h"
#include "MidiClient.h"
#include "MidiPort.h"
#include "engine.h"

View File

@@ -29,7 +29,6 @@
#include "song.h"
#include "engine.h"
#include "mixer.h"
#include "MidiClient.h"
#include "MidiController.h"
#include "automation_recorder.h"

View File

@@ -24,7 +24,7 @@
#include "sample_buffer.h"
#include "mixer.h"
#include "Mixer.h"
#include <QtCore/QBuffer>

View File

@@ -146,21 +146,22 @@ void ExportProjectDialog::startBtnClicked()
ui->progressBar->setEnabled( true );
mixer::qualitySettings qs = mixer::qualitySettings(
static_cast<mixer::qualitySettings::Interpolation>(
ui->interpolationCB->currentIndex() ),
static_cast<mixer::qualitySettings::Oversampling>(
ui->oversamplingCB->currentIndex() ),
AudioOutputContext::QualitySettings qs =
AudioOutputContext::QualitySettings(
static_cast<AudioOutputContext::QualitySettings::Interpolation>(
ui->interpolationCB->currentIndex() ),
static_cast<AudioOutputContext::QualitySettings::Oversampling>(
ui->oversamplingCB->currentIndex() ),
ui->sampleExactControllersCB->isChecked(),
ui->aliasFreeOscillatorsCB->isChecked() );
ProjectRenderer::OutputSettings os = ProjectRenderer::OutputSettings(
ProjectRenderer::EncoderSettings es = ProjectRenderer::EncoderSettings(
ui->samplerateCB->currentText().section( " ", 0, 0 ).toUInt(),
false,
ui->bitrateCB->currentText().section( " ", 0, 0 ).toUInt(),
static_cast<ProjectRenderer::Depths>( ui->depthCB->currentIndex() ) );
m_renderer = new ProjectRenderer( qs, os, ft, m_fileName );
m_renderer = new ProjectRenderer( qs, es, ft, m_fileName );
if( m_renderer->isReady() )
{
updateTitleBar( 0 );

View File

@@ -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"
@@ -1478,9 +1478,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 ) );*/
}

View File

@@ -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"

View File

@@ -35,6 +35,7 @@
#include <math.h>
#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 );

View File

@@ -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<float>() );
p.setPen( QPen( QColor::fromHsvF(

View File

@@ -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" ) );

View File

@@ -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 <tobydox/at/users.sourceforge.net>
*
* Copyright (c) 2005-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* 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;

View File

@@ -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<float>(
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 ) );
}

View File

@@ -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"

View File

@@ -33,6 +33,7 @@
#include <QtGui/QPushButton>
#include <QtAlgorithms>
#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