added support for exporting WAVE-files with 32-bit-float format
git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@1186 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
12
ChangeLog
12
ChangeLog
@@ -1,5 +1,17 @@
|
||||
2008-06-28 Tobias Doerffel <tobydox/at/users/dot/sourceforge/dot/net>
|
||||
|
||||
* include/audio_file_device.h:
|
||||
* include/audio_file_ogg.h:
|
||||
* include/audio_file_wave.h:
|
||||
* include/project_renderer.h:
|
||||
* src/core/audio/audio_file_device.cpp:
|
||||
* src/core/audio/audio_file_ogg.cpp:
|
||||
* src/core/audio/audio_file_wave.cpp:
|
||||
* src/core/main.cpp:
|
||||
* src/core/project_renderer.cpp:
|
||||
* src/gui/export_project_dialog.cpp:
|
||||
added support for exporting WAVE-files with 32-bit-float format
|
||||
|
||||
* include/automation_editor.h:
|
||||
fixed node-name
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ public:
|
||||
const bitrate_t _nom_bitrate,
|
||||
const bitrate_t _min_bitrate,
|
||||
const bitrate_t _max_bitrate,
|
||||
const int _depth,
|
||||
mixer * _mixer );
|
||||
virtual ~audioFileDevice();
|
||||
|
||||
@@ -75,6 +76,11 @@ protected:
|
||||
return( m_maxBitrate );
|
||||
}
|
||||
|
||||
inline int depth( void ) const
|
||||
{
|
||||
return( m_depth );
|
||||
}
|
||||
|
||||
inline bool outputFileOpened( void ) const
|
||||
{
|
||||
return( m_outputFile.isOpen() );
|
||||
@@ -90,6 +96,8 @@ private:
|
||||
bitrate_t m_minBitrate;
|
||||
bitrate_t m_maxBitrate;
|
||||
|
||||
int m_depth;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
@@ -102,6 +110,7 @@ typedef audioFileDevice * ( * audioFileDeviceInstantiaton )
|
||||
const bitrate_t _nom_bitrate,
|
||||
const bitrate_t _min_bitrate,
|
||||
const bitrate_t _max_bitrate,
|
||||
const int _depth,
|
||||
mixer * _mixer );
|
||||
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ public:
|
||||
const bitrate_t _nom_bitrate,
|
||||
const bitrate_t _min_bitrate,
|
||||
const bitrate_t _max_bitrate,
|
||||
const int _depth,
|
||||
mixer * _mixer );
|
||||
virtual ~audioFileOgg();
|
||||
|
||||
@@ -59,12 +60,13 @@ public:
|
||||
const bitrate_t _nom_bitrate,
|
||||
const bitrate_t _min_bitrate,
|
||||
const bitrate_t _max_bitrate,
|
||||
const int _depth,
|
||||
mixer * _mixer )
|
||||
{
|
||||
return( new audioFileOgg( _sample_rate, _channels, _success_ful,
|
||||
_file, _use_vbr, _nom_bitrate,
|
||||
_min_bitrate, _max_bitrate,
|
||||
_mixer ) );
|
||||
_depth, _mixer ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* audio_file_wave.h - Audio-device which encodes wave-stream and writes it
|
||||
* into an WAVE-file. This is used for song-export.
|
||||
*
|
||||
* Copyright (c) 2004-2006 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
* Copyright (c) 2004-2008 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
@@ -28,8 +28,12 @@
|
||||
#define _AUDIO_FILE_WAVE_H
|
||||
|
||||
|
||||
#include "lmmsconfig.h"
|
||||
#include "audio_file_device.h"
|
||||
|
||||
#ifdef LMMS_HAVE_SNDFILE_H
|
||||
#include <sndfile.h>
|
||||
#endif
|
||||
|
||||
|
||||
class audioFileWave : public audioFileDevice
|
||||
@@ -43,6 +47,7 @@ public:
|
||||
const bitrate_t _nom_bitrate,
|
||||
const bitrate_t _min_bitrate,
|
||||
const bitrate_t _max_bitrate,
|
||||
const int _depth,
|
||||
mixer * _mixer );
|
||||
virtual ~audioFileWave();
|
||||
|
||||
@@ -54,12 +59,13 @@ public:
|
||||
const bitrate_t _nom_bitrate,
|
||||
const bitrate_t _min_bitrate,
|
||||
const bitrate_t _max_bitrate,
|
||||
const int _depth,
|
||||
mixer * _mixer )
|
||||
{
|
||||
return( new audioFileWave( _sample_rate, _channels,
|
||||
_success_ful, _file, _use_vbr,
|
||||
_nom_bitrate, _min_bitrate,
|
||||
_max_bitrate,
|
||||
_max_bitrate, _depth,
|
||||
_mixer ) );
|
||||
}
|
||||
|
||||
@@ -73,6 +79,10 @@ private:
|
||||
void finishEncoding( void );
|
||||
|
||||
|
||||
#if LMMS_HAVE_SNDFILE_H
|
||||
SF_INFO m_si;
|
||||
SNDFILE * m_sf;
|
||||
#else
|
||||
int m_bytesWritten;
|
||||
|
||||
struct waveFileHeader
|
||||
@@ -91,6 +101,7 @@ private:
|
||||
char data_chunk_id[4]; // "data"
|
||||
Uint32 data_bytes; // total size of sample-data
|
||||
} m_waveFileHeader;
|
||||
#endif
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
@@ -42,15 +42,26 @@ public:
|
||||
NumFileFormats
|
||||
} ;
|
||||
|
||||
enum Depths
|
||||
{
|
||||
Depth_16Bit,
|
||||
Depth_32Bit,
|
||||
NumDepths
|
||||
} ;
|
||||
|
||||
struct outputSettings
|
||||
{
|
||||
sample_rate_t samplerate;
|
||||
bool vbr;
|
||||
int bitrate;
|
||||
outputSettings( sample_rate_t _sr, bool _vbr, int _bitrate ) :
|
||||
Depths depth;
|
||||
|
||||
outputSettings( sample_rate_t _sr, bool _vbr, int _bitrate,
|
||||
Depths _d ) :
|
||||
samplerate( _sr ),
|
||||
vbr( _vbr ),
|
||||
bitrate( _bitrate )
|
||||
bitrate( _bitrate ),
|
||||
depth( _d )
|
||||
{
|
||||
}
|
||||
} ;
|
||||
|
||||
@@ -39,13 +39,15 @@ audioFileDevice::audioFileDevice( const sample_rate_t _sample_rate,
|
||||
const bitrate_t _nom_bitrate,
|
||||
const bitrate_t _min_bitrate,
|
||||
const bitrate_t _max_bitrate,
|
||||
const int _depth,
|
||||
mixer * _mixer ) :
|
||||
audioDevice( _channels, _mixer ),
|
||||
m_outputFile( _file ),
|
||||
m_useVbr( _use_vbr ),
|
||||
m_nomBitrate( _nom_bitrate ),
|
||||
m_minBitrate( _min_bitrate ),
|
||||
m_maxBitrate( _max_bitrate )
|
||||
m_maxBitrate( _max_bitrate ),
|
||||
m_depth( _depth )
|
||||
{
|
||||
setSampleRate( _sample_rate );
|
||||
|
||||
|
||||
@@ -49,9 +49,11 @@ audioFileOgg::audioFileOgg( const sample_rate_t _sample_rate,
|
||||
const bitrate_t _nom_bitrate,
|
||||
const bitrate_t _min_bitrate,
|
||||
const bitrate_t _max_bitrate,
|
||||
const int _depth,
|
||||
mixer * _mixer ) :
|
||||
audioFileDevice( _sample_rate, _channels, _file, _use_vbr,
|
||||
_nom_bitrate, _min_bitrate, _max_bitrate, _mixer )
|
||||
_nom_bitrate, _min_bitrate, _max_bitrate,
|
||||
_depth, _mixer )
|
||||
{
|
||||
_success_ful = startEncoding();
|
||||
}
|
||||
@@ -95,13 +97,13 @@ bool audioFileOgg::startEncoding( void )
|
||||
// vbr enabled?
|
||||
if( useVBR() == 0 )
|
||||
{
|
||||
m_minBitrate = nominalBitrate(); // min for vbr
|
||||
m_maxBitrate = nominalBitrate(); // max for vbr
|
||||
m_minBitrate = nominalBitrate(); // min for vbr
|
||||
m_maxBitrate = nominalBitrate(); // max for vbr
|
||||
}
|
||||
else
|
||||
{
|
||||
m_minBitrate = minBitrate(); // min for vbr
|
||||
m_maxBitrate = maxBitrate(); // max for vbr
|
||||
m_minBitrate = minBitrate(); // min for vbr
|
||||
m_maxBitrate = maxBitrate(); // max for vbr
|
||||
}
|
||||
|
||||
m_rate = sampleRate(); // default-samplerate
|
||||
|
||||
@@ -40,9 +40,11 @@ audioFileWave::audioFileWave( const sample_rate_t _sample_rate,
|
||||
const bitrate_t _nom_bitrate,
|
||||
const bitrate_t _min_bitrate,
|
||||
const bitrate_t _max_bitrate,
|
||||
const int _depth,
|
||||
mixer * _mixer ) :
|
||||
audioFileDevice( _sample_rate, _channels, _file, _use_vbr,
|
||||
_nom_bitrate, _min_bitrate, _max_bitrate, _mixer )
|
||||
_nom_bitrate, _min_bitrate, _max_bitrate,
|
||||
_depth, _mixer )
|
||||
{
|
||||
_success_ful = startEncoding();
|
||||
}
|
||||
@@ -60,6 +62,21 @@ audioFileWave::~audioFileWave()
|
||||
|
||||
bool audioFileWave::startEncoding( void )
|
||||
{
|
||||
#if LMMS_HAVE_SNDFILE_H
|
||||
m_si.samplerate = sampleRate();
|
||||
m_si.channels = channels();
|
||||
m_si.frames = getMixer()->framesPerPeriod();
|
||||
m_si.sections = 1;
|
||||
m_si.seekable = 0;
|
||||
|
||||
switch( depth() )
|
||||
{
|
||||
case 32: m_si.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT; break;
|
||||
case 16:
|
||||
default: m_si.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; break;
|
||||
}
|
||||
m_sf = sf_open( outputFile().toUtf8().constData(), SFM_WRITE, &m_si );
|
||||
#else
|
||||
if( outputFileOpened() == FALSE )
|
||||
{
|
||||
return( FALSE );
|
||||
@@ -68,11 +85,10 @@ bool audioFileWave::startEncoding( void )
|
||||
m_bytesWritten = 0;
|
||||
|
||||
memcpy( m_waveFileHeader.riff_id, "RIFF", 4 );
|
||||
m_waveFileHeader.total_bytes = swap32IfBE( 0 );
|
||||
m_waveFileHeader.total_bytes = 0;
|
||||
memcpy( m_waveFileHeader.wave_fmt_str, "WAVEfmt ", 8 );
|
||||
m_waveFileHeader.bitrate_1 =
|
||||
m_waveFileHeader.bitrate_2 =
|
||||
swap16IfBE( BYTES_PER_INT_SAMPLE * 8 );
|
||||
m_waveFileHeader.bitrate_1 = m_waveFileHeader.bitrate_2 =
|
||||
BYTES_PER_INT_SAMPLE * 8;
|
||||
m_waveFileHeader.uncompressed = swap16IfBE( 1 );
|
||||
m_waveFileHeader.channels = swap16IfBE( channels() );
|
||||
m_waveFileHeader.sample_rate = swap32IfBE( sampleRate() );
|
||||
@@ -81,10 +97,10 @@ bool audioFileWave::startEncoding( void )
|
||||
m_waveFileHeader.block_alignment = swap16IfBE( BYTES_PER_INT_SAMPLE *
|
||||
channels() );
|
||||
memcpy ( m_waveFileHeader.data_chunk_id, "data", 4 );
|
||||
m_waveFileHeader.data_bytes = swap32IfBE( 0 );
|
||||
m_waveFileHeader.data_bytes = 0;
|
||||
|
||||
writeData( &m_waveFileHeader, sizeof( m_waveFileHeader ) );
|
||||
|
||||
#endif
|
||||
return( TRUE );
|
||||
}
|
||||
|
||||
@@ -95,14 +111,40 @@ void audioFileWave::writeBuffer( const surroundSampleFrame * _ab,
|
||||
const fpp_t _frames,
|
||||
const float _master_gain )
|
||||
{
|
||||
#if LMMS_HAVE_SNDFILE_H
|
||||
if( depth() == 32 )
|
||||
{
|
||||
float * buf = new float[_frames*channels()];
|
||||
for( fpp_t frame = 0; frame < _frames; ++frame )
|
||||
{
|
||||
for( ch_cnt_t chnl = 0; chnl < channels(); ++chnl )
|
||||
{
|
||||
buf[frame*channels()+chnl] = _ab[frame][chnl] *
|
||||
_master_gain;
|
||||
}
|
||||
}
|
||||
sf_writef_float( m_sf, buf, _frames );
|
||||
delete[] buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
int_sample_t * buf = new int_sample_t[_frames * channels()];
|
||||
convertToS16( _ab, _frames, _master_gain, buf,
|
||||
!isLittleEndian() );
|
||||
|
||||
sf_writef_short( m_sf, buf, _frames );
|
||||
delete[] buf;
|
||||
}
|
||||
#else
|
||||
int bytes = 0;
|
||||
int_sample_t * outbuf = new int_sample_t[_frames * channels()];
|
||||
Uint32 bytes = convertToS16( _ab, _frames, _master_gain, outbuf,
|
||||
!isLittleEndian() );
|
||||
writeData( outbuf, bytes );
|
||||
|
||||
delete[] outbuf;
|
||||
|
||||
m_bytesWritten += bytes;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -110,14 +152,18 @@ void audioFileWave::writeBuffer( const surroundSampleFrame * _ab,
|
||||
|
||||
void audioFileWave::finishEncoding( void )
|
||||
{
|
||||
#if LMMS_HAVE_SNDFILE_H
|
||||
sf_close( m_sf );
|
||||
#else
|
||||
seekToBegin();
|
||||
|
||||
m_waveFileHeader.total_bytes = m_bytesWritten+36;
|
||||
m_waveFileHeader.data_bytes = m_bytesWritten;
|
||||
m_waveFileHeader.total_bytes = swap32IfBE( m_bytesWritten+36 );
|
||||
m_waveFileHeader.data_bytes = swap32IfBE( m_bytesWritten );
|
||||
|
||||
// write header again, because total-bytes-field and data-bytes-field
|
||||
// have to be updated...
|
||||
writeData( &m_waveFileHeader, sizeof( m_waveFileHeader ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -102,7 +102,8 @@ int main( int argc, char * * argv )
|
||||
QString file_to_load, render_out;
|
||||
|
||||
mixer::qualitySettings qs( mixer::qualitySettings::Mode_HighQuality );
|
||||
projectRenderer::outputSettings os( 44100, FALSE, 160 );
|
||||
projectRenderer::outputSettings os( 44100, FALSE, 160,
|
||||
projectRenderer::Depth_16Bit );
|
||||
projectRenderer::ExportFileFormats eff = projectRenderer::WaveFile;
|
||||
|
||||
|
||||
|
||||
@@ -79,6 +79,7 @@ projectRenderer::projectRenderer( const mixer::qualitySettings & _qs,
|
||||
_os.samplerate, DEFAULT_CHANNELS, success_ful,
|
||||
_out_file, _os.vbr,
|
||||
_os.bitrate, _os.bitrate - 64, _os.bitrate + 64,
|
||||
_os.depth == Depth_32Bit ? 32 : 16,
|
||||
engine::getMixer() );
|
||||
if( success_ful == FALSE )
|
||||
{
|
||||
|
||||
@@ -137,9 +137,11 @@ void exportProjectDialog::startBtnClicked( void )
|
||||
aliasFreeOscillatorsCB->isChecked() );
|
||||
|
||||
projectRenderer::outputSettings os = projectRenderer::outputSettings(
|
||||
samplerateCB->currentText().section( " ", 0, 0 ).toUInt(),
|
||||
FALSE,
|
||||
bitrateCB->currentText().section( " ", 0, 0 ).toUInt() );
|
||||
samplerateCB->currentText().section( " ", 0, 0 ).toUInt(),
|
||||
FALSE,
|
||||
bitrateCB->currentText().section( " ", 0, 0 ).toUInt(),
|
||||
static_cast<projectRenderer::Depths>(
|
||||
depthCB->currentIndex() ) );
|
||||
|
||||
m_renderer = new projectRenderer( qs, os, ft, m_fileName );
|
||||
connect( m_renderer, SIGNAL( progressChanged( int ) ),
|
||||
|
||||
Reference in New Issue
Block a user