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:
@@ -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 );
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
} ;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 );
|
||||
|
||||
377
include/AudioOutputContext.h
Normal file
377
include/AudioOutputContext.h
Normal 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
|
||||
@@ -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;
|
||||
|
||||
} ;
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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;
|
||||
|
||||
} ;
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
#include "Plugin.h"
|
||||
#include "engine.h"
|
||||
#include "mixer.h"
|
||||
#include "Mixer.h"
|
||||
#include "AutomatableModel.h"
|
||||
#include "TempoSyncKnobModel.h"
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
#include "Model.h"
|
||||
#include "SerializingObject.h"
|
||||
#include "mixer.h"
|
||||
#include "Mixer.h"
|
||||
#include "AutomatableModel.h"
|
||||
|
||||
class Effect;
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#define _FX_MIXER_H
|
||||
|
||||
#include "Model.h"
|
||||
#include "mixer.h"
|
||||
#include "Mixer.h"
|
||||
#include "EffectChain.h"
|
||||
#include "JournallingObject.h"
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include <QtGui/QWidget>
|
||||
|
||||
#include "Plugin.h"
|
||||
#include "mixer.h"
|
||||
#include "Mixer.h"
|
||||
|
||||
|
||||
// forward-declarations
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#ifndef _INSTRUMENT_SOUND_SHAPING_H
|
||||
#define _INSTRUMENT_SOUND_SHAPING_H
|
||||
|
||||
#include "mixer.h"
|
||||
#include "Mixer.h"
|
||||
#include "ComboBoxModel.h"
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* mixer.h - audio-device-independent mixer for LMMS
|
||||
* Mixer.h - Mixer for audio processing and rendering
|
||||
*
|
||||
* Copyright (c) 2004-2009 Tobias Doerffel <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;
|
||||
|
||||
} ;
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
#include <QtCore/QAtomicInt>
|
||||
|
||||
#include "mixer.h"
|
||||
#include "Mixer.h"
|
||||
|
||||
|
||||
class ThreadableJob
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#include <math.h>
|
||||
|
||||
#include "lmms_basics.h"
|
||||
#include "mixer.h"
|
||||
#include "Mixer.h"
|
||||
#include "templates.h"
|
||||
#include "lmms_constants.h"
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ protected slots:
|
||||
|
||||
|
||||
private:
|
||||
Uint8 m_currentLoad;
|
||||
int m_currentLoad;
|
||||
|
||||
QPixmap m_temp;
|
||||
QPixmap m_background;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -31,6 +31,6 @@
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "mixer.h"
|
||||
#include "Mixer.h"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#include <QtCore/QPair>
|
||||
#include <qobject.h>
|
||||
|
||||
#include "mixer.h"
|
||||
#include "Mixer.h"
|
||||
#include "sample_buffer.h"
|
||||
|
||||
class bbTrack;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include <QtGui/QWidget>
|
||||
|
||||
#include "AutomatableModel.h"
|
||||
#include "mixer.h"
|
||||
#include "Mixer.h"
|
||||
|
||||
|
||||
class QPixmap;
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include <QtGui/QWidget>
|
||||
#include <QtGui/QPixmap>
|
||||
|
||||
#include "mixer.h"
|
||||
#include "Mixer.h"
|
||||
|
||||
|
||||
class visualizationWidget : public QWidget
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 ) );
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
#include "InstrumentView.h"
|
||||
#include "led_checkbox.h"
|
||||
#include "knob.h"
|
||||
#include "mixer.h"
|
||||
|
||||
class lb302SynthView;
|
||||
class notePlayHandle;
|
||||
|
||||
@@ -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-"
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include <QtCore/QMutex>
|
||||
#include <QtGui/QWidget>
|
||||
|
||||
#include "mixer.h"
|
||||
#include "JournallingObject.h"
|
||||
#include "communication.h"
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
|
||||
#include "song.h"
|
||||
#include "engine.h"
|
||||
#include "mixer.h"
|
||||
#include "ControllerConnection.h"
|
||||
|
||||
|
||||
|
||||
@@ -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" );
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
|
||||
#include "song.h"
|
||||
#include "engine.h"
|
||||
#include "mixer.h"
|
||||
#include "LfoController.h"
|
||||
#include "ControllerDialog.h"
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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 )
|
||||
{
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#endif
|
||||
|
||||
#include "RemotePlugin.h"
|
||||
#include "mixer.h"
|
||||
#include "Mixer.h"
|
||||
#include "engine.h"
|
||||
#include "config_mgr.h"
|
||||
|
||||
|
||||
@@ -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 );
|
||||
|
||||
144
src/core/audio/AudioBackend.cpp
Normal file
144
src/core/audio/AudioBackend.cpp
Normal 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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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 ),
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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 ),
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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() )
|
||||
|
||||
@@ -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 );
|
||||
|
||||
311
src/core/audio/AudioOutputContext.cpp
Normal file
311
src/core/audio/AudioOutputContext.cpp
Normal 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 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 ) );
|
||||
}
|
||||
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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() ) );
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include <QtXml/QDomNodeList>
|
||||
|
||||
#include "MidiControlListener.h"
|
||||
#include "mixer.h"
|
||||
#include "MidiClient.h"
|
||||
#include "MidiPort.h"
|
||||
#include "engine.h"
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
|
||||
#include "song.h"
|
||||
#include "engine.h"
|
||||
#include "mixer.h"
|
||||
#include "MidiClient.h"
|
||||
#include "MidiController.h"
|
||||
#include "automation_recorder.h"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
|
||||
#include "sample_buffer.h"
|
||||
#include "mixer.h"
|
||||
#include "Mixer.h"
|
||||
|
||||
|
||||
#include <QtCore/QBuffer>
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 ) );*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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" ) );
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 ) );
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user