Initial revision

git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@3 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
Tobias Doerffel
2005-09-22 13:49:52 +00:00
commit 4c7832a975
242 changed files with 23424 additions and 0 deletions

439
src/audio/audio_alsa.cpp Normal file
View File

@@ -0,0 +1,439 @@
/*
* audio_alsa.cpp - device-class that implements ALSA-PCM-output
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <QLineEdit>
#include <QLabel>
#else
#include <qpair.h>
#include <qlineedit.h>
#include <qlabel.h>
#endif
#include "audio_alsa.h"
#ifdef ALSA_SUPPORT
#include "endian_handling.h"
#include "buffer_allocator.h"
#include "config_mgr.h"
#include "lcd_spinbox.h"
#include "templates.h"
audioALSA::audioALSA( Uint32 _sample_rate, bool & _success_ful ) :
audioDevice( _sample_rate, tLimit<int>( configManager::inst()->value(
"audioalsa", "channels" ).toInt(),
DEFAULT_CHANNELS, SURROUND_CHANNELS ) ),
m_handle( NULL ),
m_hwParams( NULL ),
m_swParams( NULL ),
m_littleEndian( isLittleEndian() )
{
_success_ful = FALSE;
int err;
if( ( err = snd_pcm_open( &m_handle,
#ifdef QT4
probeDevice().toAscii().constData(),
#else
probeDevice().ascii(),
#endif
SND_PCM_STREAM_PLAYBACK,
SND_PCM_NONBLOCK ) ) < 0 )
{
printf( "Playback open error: %s\n", snd_strerror( err ) );
return;
}
snd_pcm_hw_params_alloca( &m_hwParams );
snd_pcm_sw_params_alloca( &m_swParams );
if( ( err = setHWParams( _sample_rate, channels(),
SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 )
{
printf( "Setting of hwparams failed: %s\n",
snd_strerror( err ) );
return;
}
if( ( err = setSWParams() ) < 0 )
{
printf( "Setting of swparams failed: %s\n",
snd_strerror( err ) );
return;
}
_success_ful = TRUE;
}
audioALSA::~audioALSA()
{
if( m_handle != NULL )
{
snd_pcm_close( m_handle );
}
// the following code doesn't work and leads to a crash...
/* if( m_hwParams != NULL )
{
snd_pcm_hw_params_free( m_hwParams );
}
if( m_swParams != NULL )
{
snd_pcm_sw_params_free( m_swParams );
}*/
}
QString audioALSA::probeDevice( void )
{
QString dev = configManager::inst()->value( "audioalsa", "device" );
if( dev == "" )
{
if( getenv( "AUDIODEV" ) != NULL )
{
return( getenv( "AUDIODEV" ) );
}
return( "default" );
}
return( dev );
}
int audioALSA::handleError( int _err )
{
if( _err == -EPIPE )
{
// under-run
_err = snd_pcm_prepare( m_handle );
if( _err < 0 )
printf( "Can't recovery from underrun, prepare "
"failed: %s\n", snd_strerror( _err ) );
return ( 0 );
}
else if( _err == -ESTRPIPE )
{
while( ( _err = snd_pcm_resume( m_handle ) ) == -EAGAIN )
{
sleep( 1 ); // wait until the suspend flag
// is released
}
if( _err < 0 )
{
_err = snd_pcm_prepare( m_handle );
if( _err < 0 )
printf( "Can't recovery from suspend, prepare "
"failed: %s\n", snd_strerror( _err ) );
}
return ( 0 );
}
return( _err );
}
void audioALSA::writeBufferToDev( surroundSampleFrame * _ab, Uint32 _frames,
float _master_output )
{
outputSampleType * outbuf = bufferAllocator::alloc<outputSampleType>(
_frames * channels() );
bufferAllocator::autoCleaner<> ac( outbuf );
convertToS16( _ab, _frames, _master_output, outbuf,
m_littleEndian != isLittleEndian() );
Uint32 frame = 0;
while( frame < _frames )
{
int err = snd_pcm_writei( m_handle, outbuf, _frames );
if( err == -EAGAIN )
{
continue;
}
if( err < 0 )
{
if( handleError( err ) < 0 )
{
printf( "Write error: %s\n",
snd_strerror( err ) );
return;
}
break; // skip this buffer
}
outbuf += err * channels();
frame += err;
}
}
int audioALSA::setHWParams( Uint32 _sample_rate, Uint32 _channels,
snd_pcm_access_t _access )
{
int err, dir;
// choose all parameters
if( ( err = snd_pcm_hw_params_any( m_handle, m_hwParams ) ) < 0 )
{
printf( "Broken configuration for playback: no configurations "
"available: %s\n", snd_strerror( err ) );
return( err );
}
// set the interleaved read/write format
if( ( err = snd_pcm_hw_params_set_access( m_handle, m_hwParams,
_access ) ) < 0 )
{
printf( "Access type not available for playback: %s\n",
snd_strerror( err ) );
return( err );
}
// set the sample format
if( ( snd_pcm_hw_params_set_format( m_handle, m_hwParams,
SND_PCM_FORMAT_S16_LE ) ) < 0 )
{
if( ( snd_pcm_hw_params_set_format( m_handle, m_hwParams,
SND_PCM_FORMAT_S16_BE ) ) < 0 )
{
printf( "Neither little- nor big-endian available for "
"playback: %s\n", snd_strerror( err ) );
return( err );
}
m_littleEndian = FALSE;
}
// set the count of channels
if( ( err = snd_pcm_hw_params_set_channels( m_handle, m_hwParams,
_channels ) ) < 0 )
{
printf( "Channel count (%i) not available for playbacks: %s\n"
"(Does your soundcard not support surround?)\n",
_channels, snd_strerror( err ) );
return( err );
}
// set the sample rate
if( ( err = snd_pcm_hw_params_set_rate( m_handle, m_hwParams,
_sample_rate, 0 ) ) < 0 )
{
int q = 0;
if( sampleRate() == SAMPLE_RATES[1] )
{
q = 1;
}
if( sampleRate() == 44100 || sampleRate() == 88200 )
{
SAMPLE_RATES[0] = 48000;
SAMPLE_RATES[1] = 96000;
}
else
{
SAMPLE_RATES[0] = 44100;
SAMPLE_RATES[1] = 82000;
}
setSampleRate( SAMPLE_RATES[q] );
if( ( err = snd_pcm_hw_params_set_rate( m_handle, m_hwParams,
SAMPLE_RATES[q], 0 ) ) < 0 )
{
printf( "Could not set sample rate: %s\n",
snd_strerror( err ) );
return( err );
}
}
m_periodSize = mixer::inst()->framesPerAudioBuffer();
m_bufferSize = m_periodSize * 8;
dir = 0;
err = snd_pcm_hw_params_set_period_size_near( m_handle, m_hwParams,
&m_periodSize, &dir );
if( err < 0 )
{
printf( "Unable to set period size %lu for playback: %s\n",
m_periodSize, snd_strerror( err ) );
return( err );
}
dir = 0;
err = snd_pcm_hw_params_get_period_size( m_hwParams, &m_periodSize,
&dir );
if( err < 0 )
{
printf( "Unable to get period size for playback: %s\n",
snd_strerror( err ) );
}
dir = 0;
err = snd_pcm_hw_params_set_buffer_size_near( m_handle, m_hwParams,
&m_bufferSize );
if( err < 0 )
{
printf( "Unable to set buffer size %lu for playback: %s\n",
m_bufferSize, snd_strerror( err ) );
return ( err );
}
err = snd_pcm_hw_params_get_buffer_size( m_hwParams, &m_bufferSize );
if( 2 * m_periodSize > m_bufferSize )
{
printf( "buffer to small, could not use\n" );
return ( err );
}
// write the parameters to device
err = snd_pcm_hw_params( m_handle, m_hwParams );
if( err < 0 )
{
printf( "Unable to set hw params for playback: %s\n",
snd_strerror( err ) );
return ( err );
}
return ( 0 ); // all ok
}
int audioALSA::setSWParams( void )
{
int err;
// get the current swparams
if( ( err = snd_pcm_sw_params_current( m_handle, m_swParams ) ) < 0 )
{
printf( "Unable to determine current swparams for playback: %s"
"\n", snd_strerror( err ) );
return( err );
}
// start the transfer when a period is full
if( ( err = snd_pcm_sw_params_set_start_threshold( m_handle,
m_swParams, m_periodSize ) ) < 0 )
{
printf( "Unable to set start threshold mode for playback: %s\n",
snd_strerror( err ) );
return( err );
}
// allow the transfer when at least m_periodSize samples can be
// processed
if( ( err = snd_pcm_sw_params_set_avail_min( m_handle, m_swParams,
m_periodSize ) ) < 0 )
{
printf( "Unable to set avail min for playback: %s\n",
snd_strerror( err ) );
return( err );
}
// align all transfers to 1 sample
if( ( err = snd_pcm_sw_params_set_xfer_align( m_handle,
m_swParams, 1 ) ) < 0 )
{
printf( "Unable to set transfer align for playback: %s\n",
snd_strerror( err ) );
return( err );
}
// write the parameters to the playback device
if( ( err = snd_pcm_sw_params( m_handle, m_swParams ) ) < 0 )
{
printf( "Unable to set sw params for playback: %s\n",
snd_strerror( err ) );
return( err );
}
return( 0 ); // all ok
}
audioALSA::setupWidget::setupWidget( QWidget * _parent ) :
audioDevice::setupWidget( audioALSA::name(), _parent )
{
m_device = new QLineEdit( audioALSA::probeDevice(), this );
m_device->setGeometry( 10, 20, 160, 20 );
QLabel * dev_lbl = new QLabel( tr( "DEVICE" ), this );
dev_lbl->setFont( pointSize<6>( dev_lbl->font() ) );
dev_lbl->setGeometry( 10, 40, 160, 10 );
m_channels = new lcdSpinBox( DEFAULT_CHANNELS, SURROUND_CHANNELS, 1,
this );
m_channels->setStep( 2 );
m_channels->setLabel( tr( "CHANNELS" ) );
m_channels->setValue( configManager::inst()->value( "audioalsa",
"channels" ).toInt() );
m_channels->move( 180, 20 );
}
audioALSA::setupWidget::~setupWidget()
{
}
void audioALSA::setupWidget::saveSettings( void )
{
configManager::inst()->setValue( "audioalsa", "device",
m_device->text() );
configManager::inst()->setValue( "audioalsa", "channels",
QString::number( m_channels->value() ) );
}
#endif

290
src/audio/audio_device.cpp Normal file
View File

@@ -0,0 +1,290 @@
/*
* audio_device.cpp - base-class for audio-devices used by LMMS-mixer
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <cstring>
#include "audio_device.h"
#include "buffer_allocator.h"
#include "debug.h"
audioDevice::audioDevice( Uint32 _sample_rate, Uint8 _channels ) :
m_sampleRate( _sample_rate ),
m_channels( _channels )
{
#ifdef HAVE_SAMPLERATE_H
int error;
if( ( m_srcState = src_new(
#ifdef HQ_SINC
SRC_SINC_BEST_QUALITY,
#else
SRC_SINC_FASTEST,
#endif
SURROUND_CHANNELS, &error ) ) == NULL )
{
printf( "Error: src_new() failed in audio_device.cpp!\n" );
}
m_srcData.end_of_input = 0;
#endif
}
audioDevice::~audioDevice()
{
#ifdef HAVE_SAMPLERATE_H
src_delete( m_srcState );
#endif
unlock();
}
void audioDevice::writeBuffer( surroundSampleFrame * _ab, Uint32 _frames,
Uint32 _src_sample_rate, float _master_output )
{
// make sure, no other thread is accessing device
lock();
// now were save to access the device
if( _src_sample_rate != m_sampleRate )
{
surroundSampleFrame * temp =
bufferAllocator::alloc<surroundSampleFrame>(
_frames * channels() );
resample( _ab, _frames, temp, _src_sample_rate, m_sampleRate );
writeBufferToDev( temp, _frames * m_sampleRate /
_src_sample_rate, _master_output );
bufferAllocator::free( temp );
}
else
{
writeBufferToDev( _ab, _frames, _master_output );
}
// release lock
unlock();
}
#ifndef HAVE_SAMPLERATE_H
const Uint8 LP_FILTER_TAPS = 24;
const float LP_FILTER_COEFFS[LP_FILTER_TAPS] =
{
+0.000511851442,
-0.001446936402,
-0.005058312516,
-0.002347181570,
+0.011236146012,
+0.020351310667,
-0.000479735368,
-0.045333228189
-0.055186434405,
+0.032962246498,
+0.202439670159,
+0.342350604673,
+0.342350604673,
+0.202439670159,
+0.032962246498,
-0.055186434405,
-0.045333228189
-0.000479735368,
+0.020351310667,
+0.011236146012,
-0.002347181570,
-0.005058312516,
-0.001446936402,
+0.000511851442
} ;
#endif
void FASTCALL audioDevice::resample( surroundSampleFrame * _src, Uint32 _frames,
surroundSampleFrame * _dst,
Uint32 _src_sr, Uint32 _dst_sr )
{
#ifdef HAVE_SAMPLERATE_H
if( m_srcState == NULL )
{
return;
}
m_srcData.input_frames = _frames;
m_srcData.output_frames = _frames;
m_srcData.data_in = _src[0];
m_srcData.data_out = _dst[0];
m_srcData.src_ratio = (float) _dst_sr / _src_sr;
int error;
if( ( error = src_process( m_srcState, &m_srcData ) ) )
{
printf( "audioDevice::resample(): error while resampling: %s\n",
src_strerror( error ) );
}
#else
if( _src_sr == 2*SAMPLE_RATES[DEFAULT_QUALITY_LEVEL] )
{
// we use a simple N-tap FIR-Filter with
// precalculated/-designed LP-Coeffs
static surroundSampleFrame lp_hist[LP_FILTER_TAPS] =
{
#ifndef DISABLE_SURROUND
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f }
#else
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f }
#endif
} ;
static Uint8 oldest = 0;
for( Uint32 frame = 0; frame < _frames; ++frame )
{
for( Uint8 chnl = 0; chnl < SURROUND_CHANNELS; ++chnl )
{
lp_hist[oldest][chnl] = _src[frame][chnl];
if( frame % 2==0 )
{
_dst[frame/2][chnl] = 0.0f;
for( Uint8 tap = 0;
tap < LP_FILTER_TAPS; ++tap )
{
_dst[frame / 2][chnl] +=
LP_FILTER_COEFFS[tap] * lp_hist[( oldest + tap ) % LP_FILTER_TAPS][chnl];
}
}
}
oldest = ( oldest + 1 ) % LP_FILTER_TAPS;
}
}
else if( _src_sr == SAMPLE_RATES[DEFAULT_QUALITY_LEVEL] / 2 )
{
printf( "No resampling for given sample-rates implemented!\n"
"Consider installing libsamplerate and recompile "
"LMMS!\n" );
}
#endif
}
int FASTCALL audioDevice::convertToS16( surroundSampleFrame * _ab,
Uint32 _frames, float _master_output,
outputSampleType * _output_buffer,
bool _convert_endian )
{
for( Uint32 frame = 0; frame < _frames; ++frame )
{
for( Uint8 chnl = 0; chnl < channels(); ++chnl )
{
( _output_buffer + frame * channels() )[chnl] =
static_cast<outputSampleType>(
mixer::clip( _ab[frame][chnl] *
_master_output ) *
OUTPUT_SAMPLE_MULTIPLIER );
}
}
if( _convert_endian )
{
for( Uint32 frame = 0; frame < _frames; ++frame )
{
for( Uint8 chnl = 0; chnl < channels(); ++chnl )
{
Sint8 * ptr = reinterpret_cast<Sint8 *>(
_output_buffer +
frame * channels() +
chnl );
*(outputSampleType *)ptr =
( ( outputSampleType )*ptr << 8
) |
( ( outputSampleType ) *
( ptr+1 ) );
}
}
}
return( _frames * channels() * BYTES_PER_OUTPUT_SAMPLE );
}
void FASTCALL audioDevice::clearS16Buffer( outputSampleType * _outbuf,
Uint32 _frames )
{
#ifdef LMMS_DEBUG
assert( _outbuf != NULL );
#endif
memset( _outbuf, 0, _frames * channels() * BYTES_PER_OUTPUT_SAMPLE );
}

View File

@@ -0,0 +1,103 @@
/*
* audio_file_device.cpp - base-class for audio-device-classes which write
* their output into a file
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <QMessageBox>
#else
#include <qmessagebox.h>
#endif
#include "audio_file_device.h"
#include "export_project_dialog.h"
audioFileDevice::audioFileDevice( Uint32 _sample_rate, Uint8 _channels,
const QString & _file,
bool _use_vbr,
Uint16 _nom_bitrate,
Uint16 _min_bitrate,
Uint16 _max_bitrate ) :
audioDevice( _sample_rate, _channels),
m_outputFile( _file ),
m_useVbr( _use_vbr ),
m_nomBitrate( _nom_bitrate ),
m_minBitrate( _min_bitrate ),
m_maxBitrate( _max_bitrate )
{
#ifdef QT4
if( m_outputFile.open( QFile::WriteOnly | QFile::Truncate ) == FALSE )
#else
if( m_outputFile.open( IO_WriteOnly | IO_Truncate ) == FALSE )
#endif
{
QMessageBox::critical( NULL,
exportProjectDialog::tr( "Could not open file" ),
exportProjectDialog::tr( "Could not open file %1 "
"for writing.\nPlease make "
"sure you have write-"
"permission to the file and "
"the directory containing the "
"file and try again!" ).arg(
_file ),
QMessageBox::Ok,
QMessageBox::NoButton );
}
}
audioFileDevice::~audioFileDevice()
{
m_outputFile.close();
}
int audioFileDevice::writeData( const void * _data, int _len )
{
#ifdef QT4
return( m_outputFile.write( (const char *)_data, _len ) );
#else
return( m_outputFile.writeBlock( (const char *)_data, _len ) );
#endif
}
void audioFileDevice::seekToBegin( void )
{
m_outputFile.seek( 0 );
}

View File

@@ -0,0 +1,267 @@
/*
* audio_file_ogg.cpp - Audio-device which encodes wave-stream and writes it
* into an OGG-file. This is used for song-export.
*
* This file is based on encode.c from vorbis-tools-source, for more information
* see below.
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
/* OggEnc
**
** This program is distributed under the GNU General Public License, version 2.
** A copy of this license is included with this source.
**
** Copyright 2000-2002, Michael Smith <msmith@labyrinth.net.au>
**
** Portions from Vorbize, (c) Kenneth Arnold <kcarnold@yahoo.com>
** and libvorbis examples, (c) Monty <monty@xiph.org>
**/
#include <qpair.h>
#include "audio_file_ogg.h"
#ifdef HAVE_VORBIS_CODEC_H
#include <vorbis/vorbisenc.h>
#include <cstring>
audioFileOgg::audioFileOgg( Uint32 _sample_rate, Uint32 _channels,
bool & _success_ful, const QString & _file,
bool _use_vbr, Uint16 _nom_bitrate,
Uint16 _min_bitrate, Uint16 _max_bitrate ) :
audioFileDevice( _sample_rate, _channels, _file, _use_vbr,
_nom_bitrate, _min_bitrate, _max_bitrate )
{
_success_ful = startEncoding();
}
audioFileOgg::~audioFileOgg()
{
finishEncoding();
}
inline int audioFileOgg::writePage( void )
{
int written = writeData( m_og.header, m_og.header_len );
written += writeData( m_og.body, m_og.body_len );
return( written );
}
bool audioFileOgg::startEncoding( void )
{
vorbis_comment vc;
char * comments = "Cool=This song was written with Linux "
"MultiMedia Studio";
int comment_length = strlen( comments );
vc.user_comments = &comments;
vc.comment_lengths = &comment_length;
vc.comments = 1;
vc.vendor = NULL;
m_channels = channels();
// vbr enabled?
if( useVBR() == 0 )
{
m_managed = -1; // we don't want vbr
m_minBitrate = nominalBitrate(); // min for vbr
m_maxBitrate = nominalBitrate(); // max for vbr
}
else
{
m_managed = 0; // let's use vbr
m_minBitrate = minBitrate(); // min for vbr
m_maxBitrate = maxBitrate(); // max for vbr
}
m_bitrate = nominalBitrate(); // nominal bitrate
m_rate = sampleRate(); // default-samplerate
m_serialNo = 0; // track-num?
m_comments = &vc; // comments for ogg-file
// Have vorbisenc choose a mode for us
vorbis_info_init( &m_vi );
if( vorbis_encode_setup_managed( &m_vi, m_channels, m_rate,
( m_maxBitrate > 0 )? m_maxBitrate * 1000 : -1,
m_bitrate * 1000,
( m_minBitrate > 0 )? m_minBitrate * 1000 : -1 ) )
{
printf( "Mode initialization failed: invalid parameters for "
"bitrate\n" );
vorbis_info_clear( &m_vi );
return( FALSE );
}
if( m_managed && m_bitrate < 0 )
{
vorbis_encode_ctl( &m_vi, OV_ECTL_RATEMANAGE_AVG, NULL );
}
else if( !m_managed )
{
// Turn off management entirely (if it was turned on).
vorbis_encode_ctl( &m_vi, OV_ECTL_RATEMANAGE_SET, NULL );
}
vorbis_encode_setup_init( &m_vi );
// Now, set up the analysis engine, stream encoder, and other
// preparation before the encoding begins.
vorbis_analysis_init( &m_vd, &m_vi );
vorbis_block_init( &m_vd, &m_vb );
ogg_stream_init( &m_os, m_serialNo );
// Now, build the three header packets and send through to the stream
// output stage (but defer actual file output until the main encode
// loop)
ogg_packet header_main;
ogg_packet header_comments;
ogg_packet header_codebooks;
int result;
// Build the packets
vorbis_analysis_headerout( &m_vd, m_comments, &header_main,
&header_comments, &header_codebooks );
// And stream them out
ogg_stream_packetin( &m_os, &header_main );
ogg_stream_packetin( &m_os, &header_comments );
ogg_stream_packetin( &m_os, &header_codebooks );
while( ( result = ogg_stream_flush( &m_os, &m_og ) ) )
{
if( !result )
{
break;
}
int ret = writePage();
if( ret != m_og.header_len + m_og.body_len )
{
// clean up
finishEncoding();
return( FALSE );
}
}
return( TRUE );
}
void FASTCALL audioFileOgg::writeBufferToDev( surroundSampleFrame * _ab,
Uint32 _frames,
float _master_output )
{
int eos = 0;
float * * buffer = vorbis_analysis_buffer( &m_vd, _frames *
BYTES_PER_SAMPLE *
channels() );
for( Uint32 frame = 0; frame < _frames; ++frame )
{
for( Uint8 chnl = 0; chnl < channels(); ++chnl )
{
buffer[chnl][frame] = _ab[frame][chnl] * _master_output;
}
}
vorbis_analysis_wrote( &m_vd, _frames );
// While we can get enough data from the library to analyse,
// one block at a time...
while( vorbis_analysis_blockout( &m_vd, &m_vb ) == 1 )
{
// Do the main analysis, creating a packet
vorbis_analysis( &m_vb, NULL );
vorbis_bitrate_addblock( &m_vb );
while( vorbis_bitrate_flushpacket( &m_vd, &m_op ) )
{
// Add packet to bitstream
ogg_stream_packetin( &m_os, &m_op );
// If we've gone over a page boundary, we can do
// actual output, so do so (for however many pages
// are available)
while( !eos )
{
int result = ogg_stream_pageout( &m_os,
&m_og );
if( !result )
{
break;
}
int ret = writePage();
if( ret != m_og.header_len +
m_og.body_len )
{
printf( "failed writing to "
"outstream\n" );
return;
}
if( ogg_page_eos( &m_og ) )
{
eos = 1;
}
}
}
}
}
void audioFileOgg::finishEncoding( void )
{
// just for flushing buffers...
writeBufferToDev( NULL, 0, 0.0f );
// clean up
ogg_stream_clear( &m_os );
vorbis_block_clear( &m_vb );
vorbis_dsp_clear( &m_vd );
vorbis_info_clear( &m_vi );
}
#endif

View File

@@ -0,0 +1,118 @@
/*
* audio_file_wave.cpp - Audio-device which encodes wave-stream and writes it
* into a WAVE-file. This is used for song-export.
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "audio_file_wave.h"
#include "endian_handling.h"
#include "buffer_allocator.h"
#include <cstring>
audioFileWave::audioFileWave( Uint32 _sample_rate, Uint32 _channels,
bool & _success_ful, const QString & _file,
bool _use_vbr, Uint16 _nom_bitrate,
Uint16 _min_bitrate, Uint16 _max_bitrate ) :
audioFileDevice( _sample_rate, _channels, _file, _use_vbr,
_nom_bitrate, _min_bitrate, _max_bitrate )
{
_success_ful = startEncoding();
}
audioFileWave::~audioFileWave()
{
finishEncoding();
}
bool audioFileWave::startEncoding( void )
{
if( outputFileOpened() == FALSE )
{
return( FALSE );
}
m_bytesWritten = 0;
memcpy( m_waveFileHeader.riff_id, "RIFF", 4 );
m_waveFileHeader.total_bytes = swap32IfBE( 0 );
memcpy( m_waveFileHeader.wave_fmt_str, "WAVEfmt ", 8 );
m_waveFileHeader.bitrate_1 =
m_waveFileHeader.bitrate_2 =
swap16IfBE( BYTES_PER_OUTPUT_SAMPLE * 8 );
m_waveFileHeader.uncompressed = swap16IfBE( 1 );
m_waveFileHeader.channels = swap16IfBE( channels() );
m_waveFileHeader.sample_rate = swap32IfBE( sampleRate() );
m_waveFileHeader.bytes_per_second = swap32IfBE( sampleRate() *
BYTES_PER_OUTPUT_SAMPLE *
channels() );
m_waveFileHeader.block_alignment = swap16IfBE( BYTES_PER_OUTPUT_SAMPLE *
channels() );
memcpy ( m_waveFileHeader.data_chunk_id, "data", 4 );
m_waveFileHeader.data_bytes = swap32IfBE( 0 );
writeData( &m_waveFileHeader, sizeof( m_waveFileHeader ) );
return( TRUE );
}
void FASTCALL audioFileWave::writeBufferToDev( surroundSampleFrame * _ab,
Uint32 _frames,
float _master_output )
{
outputSampleType * outbuf = bufferAllocator::alloc<outputSampleType>(
_frames * channels() );
int bytes = convertToS16( _ab, _frames, _master_output, outbuf,
!isLittleEndian() );
writeData( outbuf, bytes );
bufferAllocator::free( outbuf );
m_bytesWritten += bytes;
}
void audioFileWave::finishEncoding( void )
{
seekToBegin();
m_waveFileHeader.total_bytes = m_bytesWritten+36;
m_waveFileHeader.data_bytes = m_bytesWritten;
// write header again, because total-bytes-field and data-bytes-field
// have to be updated...
writeData( &m_waveFileHeader, sizeof( m_waveFileHeader ) );
}

379
src/audio/audio_jack.cpp Normal file
View File

@@ -0,0 +1,379 @@
/*
* audio_jack.cpp - support for JACK-transport
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "audio_jack.h"
#ifdef HAVE_UNISTD_H
// for usleep
#include <unistd.h>
#endif
#ifdef JACK_SUPPORT
#ifdef QT4
#include <QLineEdit>
#include <QLabel>
#else
#include <qlineedit.h>
#include <qlabel.h>
#endif
#include "debug.h"
#include "templates.h"
#include "buffer_allocator.h"
#include "config_mgr.h"
#include "lcd_spinbox.h"
audioJACK::audioJACK( Uint32 _sample_rate, bool & _success_ful ) :
audioDevice( _sample_rate, tLimit<int>( configManager::inst()->value(
"audiojack", "channels" ).toInt(),
DEFAULT_CHANNELS, SURROUND_CHANNELS ) ),
m_framesDoneInCurBuf( 0 ),
m_frameSync( 0 ),
m_jackBufSize( 0 ),
m_bufMutex()
{
_success_ful = FALSE;
QString client_name = configManager::inst()->value( "audiojack",
"clientname" );
if( client_name == "" )
{
client_name = "lmms";
}
#ifndef OLD_JACK
const char * server_name = NULL;
jack_status_t status;
m_client = jack_client_open( client_name.
#ifdef QT4
toAscii().constData(),
#else
ascii(),
#endif
JackNullOption, &status,
server_name );
if( m_client == NULL )
{
printf( "jack_client_open() failed with status %d\n", status );
if( status & JackServerFailed )
{
printf( "Could not connect to JACK server.\n" );
}
return;
}
if( status & JackNameNotUnique )
{
printf( "there's already a client with name '%s', so unique "
"name '%s' was assigned\n", client_name.
#ifdef QT4
toAscii().constData(),
#else
ascii(),
#endif
jack_get_client_name( m_client ) );
}
#else
m_client = jack_client_new( client_name.
#ifdef QT4
toAscii().constData()
#else
ascii()
#endif
);
#endif
// set process-callback
jack_set_process_callback( m_client, processCallback, this );
// we need to know about buffer-size changes to know how long to block
// in writeToDev()-method
jack_set_buffer_size_callback( m_client, bufSizeCallback, this );
// set shutdown-callback
//jack_on_shutdown( m_client, shutdown, this );
m_jackBufSize = jack_get_buffer_size( m_client );
if( jack_get_sample_rate( m_client ) != sampleRate() )
{
SAMPLE_RATES[0] = jack_get_sample_rate( m_client );
SAMPLE_RATES[1] = 2 * SAMPLE_RATES[0];
setSampleRate( SAMPLE_RATES[0] );
}
for( Uint8 ch = 0; ch < channels(); ++ch )
{
QString name = QString( "master_out_" ) +
( ( ch % 2 ) ? "R" : "L" ) +
QString::number( ch / 2 + 1 );
m_outputPorts.push_back( jack_port_register( m_client,
#ifdef QT4
name.toAscii().constData(),
#else
name.ascii(),
#endif
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsOutput, 0 ) );
if( m_outputPorts.back() == NULL )
{
printf( "no more JACK-ports available!\n" );
return;
}
}
if( jack_activate( m_client ) )
{
printf( "cannot activate client\n" );
return;
}
const char * * ports = jack_get_ports( m_client, NULL, NULL,
JackPortIsPhysical |
JackPortIsInput );
if( ports == NULL )
{
printf( "no physical playback ports. you'll have to do "
"connections at your own!\n" );
}
else
{
for( Uint8 ch = 0; ch < channels(); ++ch )
{
if( jack_connect( m_client, jack_port_name(
m_outputPorts[ch] ),
ports[ch] ) )
{
printf( "cannot connect output ports. you'll "
"have to do connections at your own!\n"
);
}
}
}
free( ports );
_success_ful = TRUE;
}
audioJACK::~audioJACK()
{
jack_deactivate( m_client );
jack_client_close( m_client );
while( m_bufferSets.size() )
{
while( m_bufferSets.front().size() )
{
bufferAllocator::free(
m_bufferSets.front().front().buf );
m_bufferSets.front().erase(
m_bufferSets.front().begin() );
}
m_bufferSets.erase( m_bufferSets.begin() );
}
}
void audioJACK::writeBufferToDev( surroundSampleFrame * _ab, Uint32 _frames,
float _master_output )
{
m_bufMutex.lock();
vvector<bufset> bufs;
for( Uint8 chnl = 0; chnl < channels(); ++chnl )
{
sampleType * buf = bufferAllocator::alloc<sampleType>(
_frames );
for( Uint32 frame = 0; frame < _frames; ++frame )
{
buf[frame] = _ab[frame][chnl] * _master_output;
}
bufset b = { buf, _frames } ;
bufs.push_back( b );
}
m_bufferSets.push_back( bufs );
m_frameSync += _frames;
m_bufMutex.unlock();
// now wait until data has been collected by processCallback()
while( m_frameSync > m_jackBufSize )
{
#ifdef HAVE_UNISTD_H
#ifdef HAVE_USLEEP
// just wait and give cpu-time to other processes
usleep( 500 );
#endif
#endif
}
}
int audioJACK::processCallback( jack_nframes_t _nframes, void * _udata )
{
audioJACK * _this = static_cast<audioJACK *>( _udata );
#ifdef LMMS_DEBUG
assert( _this != NULL );
#endif
jack_transport_state_t ts = jack_transport_query( _this->m_client,
NULL );
if( ts != JackTransportRolling )
{
return( 0 );
}
vvector<jack_default_audio_sample_t *> outbufs( _this->channels(),
NULL );
Uint8 ch = 0;
for( vvector<jack_default_audio_sample_t *>::iterator it =
outbufs.begin(); it != outbufs.end(); ++it, ++ch )
{
*it = (jack_default_audio_sample_t *) jack_port_get_buffer(
_this->m_outputPorts[ch], _nframes );
}
_this->m_bufMutex.lock();
jack_nframes_t done = 0;
while( done < _nframes )
{
if( _this->m_bufferSets.size() == 0 )
{
break;
}
jack_nframes_t todo = tMin( _nframes - done,
_this->m_bufferSets.front()[0].frames -
_this->m_framesDoneInCurBuf );
for( Uint8 ch = 0; ch < _this->channels(); ++ch )
{
memcpy( outbufs[ch] + done,
_this->m_bufferSets.front()[ch].buf +
_this->m_framesDoneInCurBuf,
sizeof( jack_default_audio_sample_t ) *
todo );
}
_this->m_framesDoneInCurBuf += todo;
if( _this->m_framesDoneInCurBuf >=
_this->m_bufferSets.front()[0].frames )
{
for( Uint8 ch = 0; ch < _this->channels(); ++ch )
{
bufferAllocator::free(
_this->m_bufferSets.front()[ch].buf );
}
_this->m_bufferSets.erase(
_this->m_bufferSets.begin() );
_this->m_framesDoneInCurBuf = 0;
}
done += todo;
_this->m_frameSync -= todo;
}
_this->m_bufMutex.unlock();
return( 0 );
}
int audioJACK::bufSizeCallback( jack_nframes_t _nframes, void * _udata )
{
audioJACK * _this = static_cast<audioJACK *>( _udata );
#ifdef LMMS_DEBUG
assert( _this != NULL );
#endif
_this->m_jackBufSize = _nframes;
return( 0 );
}
audioJACK::setupWidget::setupWidget( QWidget * _parent ) :
audioDevice::setupWidget( audioJACK::name(), _parent )
{
QString cn = configManager::inst()->value( "audiojack", "clientname" );
if( cn == "" )
{
cn = "lmms";
}
m_clientName = new QLineEdit( cn, this );
m_clientName->setGeometry( 10, 20, 160, 20 );
QLabel * cn_lbl = new QLabel( tr( "CLIENT-NAME" ), this );
cn_lbl->setFont( pointSize<6>( cn_lbl->font() ) );
cn_lbl->setGeometry( 10, 40, 160, 10 );
m_channels = new lcdSpinBox( DEFAULT_CHANNELS, SURROUND_CHANNELS, 1,
this );
m_channels->setStep( 2 );
m_channels->setLabel( tr( "CHANNELS" ) );
m_channels->setValue( configManager::inst()->value( "audiojack",
"channels" ).toInt() );
m_channels->move( 180, 20 );
}
audioJACK::setupWidget::~setupWidget()
{
}
void audioJACK::setupWidget::saveSettings( void )
{
configManager::inst()->setValue( "audiojack", "clientname",
m_clientName->text() );
configManager::inst()->setValue( "audiojack", "channels",
QString::number( m_channels->value() ) );
}
#endif

329
src/audio/audio_oss.cpp Normal file
View File

@@ -0,0 +1,329 @@
/*
* audio_oss.cpp - device-class that implements OSS-PCM-output
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <QFileInfo>
#include <QLineEdit>
#include <QLabel>
#else
#include <qfileinfo.h>
#include <qlineedit.h>
#include <qlabel.h>
#endif
#include "audio_oss.h"
#include "buffer_allocator.h"
#include "endian_handling.h"
#include "lcd_spinbox.h"
#include "templates.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef OSS_USE_SOUNDCARD_H
/* This is installed on some systems */
#include <soundcard.h>
#else
/* This is recommended by OSS */
#include <sys/soundcard.h>
#endif
#include "config_mgr.h"
#ifndef _PATH_DEV_DSP
#ifdef __OpenBSD__
#define _PATH_DEV_DSP "/dev/audio"
#else
#define _PATH_DEV_DSP "/dev/dsp"
#endif
#endif
audioOSS::audioOSS( Uint32 _sample_rate, bool & _success_ful ) :
audioDevice( _sample_rate, tLimit<int>( configManager::inst()->value(
"audiooss", "channels" ).toInt(),
DEFAULT_CHANNELS, SURROUND_CHANNELS ) ),
m_convertEndian( FALSE )
{
_success_ful = FALSE;
m_audioFD = open(
#ifdef QT4
probeDevice().toAscii().constData(),
#else
probeDevice().ascii(),
#endif
O_WRONLY, 0 );
if( m_audioFD == -1 )
{
printf( "audioOSS: failed opening audio-device\n" );
return;
}
// Make the file descriptor use blocking writes with fcntl()
if ( fcntl( m_audioFD, F_SETFL, fcntl( m_audioFD, F_GETFL ) &
~O_NONBLOCK ) < 0 )
{
printf( "could not set audio blocking mode\n" );
return;
}
int frag_spec;
for( frag_spec = 0; static_cast<unsigned int>( 0x01 << frag_spec ) <
mixer::inst()->framesPerAudioBuffer() * channels() *
BYTES_PER_OUTPUT_SAMPLE;
++frag_spec )
{
}
frag_spec |= 0x00020000; // two fragments, for low latency
if ( ioctl( m_audioFD, SNDCTL_DSP_SETFRAGMENT, &frag_spec ) < 0 )
{
perror( "SNDCTL_DSP_SETFRAGMENT" );
printf( "Warning: Couldn't set audio fragment size\n" );
}
unsigned int value;
// Get a list of supported hardware formats
if ( ioctl( m_audioFD, SNDCTL_DSP_GETFMTS, &value ) < 0 )
{
perror( "SNDCTL_DSP_GETFMTS" );
printf( "Couldn't get audio format list\n" );
return;
}
// Set the audio format
if( value & AFMT_S16_LE )
{
value = AFMT_S16_LE;
}
else if( value & AFMT_S16_BE )
{
value = AFMT_S16_BE;
}
else
{
printf(" Soundcard doesn't support signed 16-bit-data\n");
}
if ( ioctl( m_audioFD, SNDCTL_DSP_SETFMT, &value ) < 0 )
{
perror( "SNDCTL_DSP_SETFMT" );
printf( "Couldn't set audio format\n" );
return;
}
if( ( isLittleEndian() && ( value == AFMT_S16_BE ) ) ||
( !isLittleEndian() && ( value == AFMT_S16_LE ) ) )
{
m_convertEndian = TRUE;
}
// Set the number of channels of output
value = channels();
if ( ioctl( m_audioFD, SNDCTL_DSP_CHANNELS, &value ) < 0 )
{
perror( "SNDCTL_DSP_CHANNELS" );
printf( "Cannot set the number of channels\n" );
return;
}
if( value != channels() )
{
printf( "Couldn't set number of channels\n" );
return;
}
// Set the DSP frequency
value = sampleRate();
if ( ioctl( m_audioFD, SNDCTL_DSP_SPEED, &value ) < 0 )
{
perror( "SNDCTL_DSP_SPEED" );
printf( "Couldn't set audio frequency\n" );
return;
}
if( value != sampleRate() )
{
//printf( "Soundcard uses different sample-rate than LMMS "
// "does!\n" );
int q = 0;
if( sampleRate() == SAMPLE_RATES[1] )
{
q = 1;
}
if( sampleRate() == 44100 || sampleRate() == 88200 )
{
SAMPLE_RATES[0] = 48000;
SAMPLE_RATES[1] = 96000;
}
else
{
SAMPLE_RATES[0] = 44100;
SAMPLE_RATES[1] = 82000;
}
setSampleRate( SAMPLE_RATES[q] );
value = sampleRate();
if ( ioctl( m_audioFD, SNDCTL_DSP_SPEED, &value ) < 0 )
{
perror( "SNDCTL_DSP_SPEED" );
printf( "Couldn't set audio frequency\n" );
return;
}
}
_success_ful = TRUE;
}
audioOSS::~audioOSS()
{
close( m_audioFD );
}
QString audioOSS::probeDevice( void )
{
QString dev = configManager::inst()->value( "audiooss", "device" );
if( dev == "" )
{
char * adev = getenv( "AUDIODEV" ); // Is there a standard
// variable name?
if( adev != NULL )
{
dev = adev;
}
else
{
dev = _PATH_DEV_DSP; // default device
}
}
// if the first open fails, look for other devices
if ( QFileInfo( dev ).isWritable() == FALSE )
{
int instance = -1;
while( 1 )
{
dev = _PATH_DEV_DSP + QString::number( ++instance );
if( !QFileInfo( dev ).exists() )
{
dev = _PATH_DEV_DSP;
break;
}
if( QFileInfo( dev ).isWritable() )
{
break;
}
}
}
return( dev );
}
void audioOSS::writeBufferToDev( surroundSampleFrame * _ab, Uint32 _frames,
float _master_output )
{
outputSampleType * outbuf = bufferAllocator::alloc<outputSampleType>(
_frames * channels() );
int bytes = convertToS16( _ab, _frames, _master_output, outbuf,
m_convertEndian );
write( m_audioFD, outbuf, bytes );
bufferAllocator::free( outbuf );
}
audioOSS::setupWidget::setupWidget( QWidget * _parent ) :
audioDevice::setupWidget( audioOSS::name(), _parent )
{
m_device = new QLineEdit( probeDevice(), this );
m_device->setGeometry( 10, 20, 160, 20 );
QLabel * dev_lbl = new QLabel( tr( "DEVICE" ), this );
dev_lbl->setFont( pointSize<6>( dev_lbl->font() ) );
dev_lbl->setGeometry( 10, 40, 160, 10 );
m_channels = new lcdSpinBox( DEFAULT_CHANNELS, SURROUND_CHANNELS, 1,
this );
m_channels->setStep( 2 );
m_channels->setLabel( tr( "CHANNELS" ) );
m_channels->setValue( configManager::inst()->value( "audiooss",
"channels" ).toInt() );
m_channels->move( 180, 20 );
}
audioOSS::setupWidget::~setupWidget()
{
}
void audioOSS::setupWidget::saveSettings( void )
{
configManager::inst()->setValue( "audiooss", "device",
m_device->text() );
configManager::inst()->setValue( "audiooss", "channels",
QString::number( m_channels->value() ) );
}

View File

@@ -0,0 +1,112 @@
/*
* audio_sample_recorder.cpp - device-class that implements recording
* surround-audio-buffers into RAM, maybe later
* also harddisk
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "audio_sample_recorder.h"
#include "sample_buffer.h"
#include "buffer_allocator.h"
#include "debug.h"
audioSampleRecorder::audioSampleRecorder( Uint32 _sample_rate, Uint32 _channels,
bool & _success_ful ) :
audioDevice( _sample_rate, _channels ),
m_buffers()
{
_success_ful = TRUE;
}
audioSampleRecorder::~audioSampleRecorder()
{
while( !m_buffers.isEmpty() )
{
bufferAllocator::free( m_buffers.front().first );
m_buffers.erase( m_buffers.begin() );
}
}
Uint32 audioSampleRecorder::framesRecorded( void ) const
{
Uint32 frames = 0;
for( bufferVector::const_iterator it = m_buffers.begin();
it != m_buffers.end(); ++it )
{
frames += it->second;
}
return( frames );
}
void audioSampleRecorder::createSampleBuffer( sampleBuffer * * _sample_buf )
const
{
Uint32 frames = framesRecorded();
// create buffer to store all recorded buffers in
sampleFrame * data = bufferAllocator::alloc<sampleFrame>( frames );
// make sure buffer is cleaned up properly at the end...
bufferAllocator::autoCleaner<sampleFrame> ac( data );
#ifdef LMMS_DEBUG
assert( data != NULL );
#endif
// now copy all buffers into big buffer
for( bufferVector::const_iterator it = m_buffers.begin();
it != m_buffers.end(); ++it )
{
memcpy( data, it->first, it->second * sizeof( sampleFrame ) );
data += it->second;
}
// create according sample-buffer out of big buffer
*_sample_buf = new sampleBuffer( ac.ptr(), frames );
}
void audioSampleRecorder::writeBufferToDev( surroundSampleFrame * _ab,
Uint32 _frames, float )
{
sampleFrame * buf = bufferAllocator::alloc<sampleFrame>( _frames );
for( Uint32 frame = 0; frame < _frames; ++frame )
{
for( Uint8 chnl = 0; chnl < DEFAULT_CHANNELS; ++chnl )
{
buf[frame][chnl] = _ab[frame][chnl];
}
}
m_buffers.push_back( qMakePair( buf, _frames ) );
}

203
src/audio/audio_sdl.cpp Normal file
View File

@@ -0,0 +1,203 @@
/*
* audio_sdl.cpp - device-class that performs PCM-output via SDL
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "audio_sdl.h"
#ifdef SDL_AUDIO_SUPPORT
#ifdef QT4
#include <QLineEdit>
#include <QLabel>
#else
#include <qlineedit.h>
#include <qlabel.h>
#endif
#include "buffer_allocator.h"
#include "debug.h"
#include "config_mgr.h"
#include "templates.h"
audioSDL::audioSDL( Uint32 _sample_rate, bool & _success_ful ) :
audioDevice( _sample_rate, DEFAULT_CHANNELS ),
m_buffer( bufferAllocator::alloc<outputSampleType>(
mixer::inst()->framesPerAudioBuffer() *
channels() ) ),
m_bufMutex(),
m_callbackMutex(),
m_convertEndian( FALSE )
{
_success_ful = FALSE;
// if device is set, we set AUDIODEV-environment-variable, so that
// SDL can evaluate and use it
QString dev = configManager::inst()->value( "audiosdl", "device" );
if( dev != "" )
{
putenv( const_cast<char *>( ( "AUDIODEV=" + dev ).
#ifdef QT4
toAscii().constData() ) );
#else
ascii() ) );
#endif
}
if( SDL_Init( SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE ) < 0 )
{
printf( "Couldn't initialize SDL: %s\n", SDL_GetError() );
return;
}
m_audioHandle.freq = _sample_rate;
m_audioHandle.format = AUDIO_S16SYS; // we want it in byte-order
// of system, so we don't have
// to convert the buffers
m_audioHandle.channels = channels();
m_audioHandle.samples = mixer::inst()->framesPerAudioBuffer();
m_audioHandle.callback = sdlAudioCallback;
m_audioHandle.userdata = this;
SDL_AudioSpec actual;
// open the audio device, forcing the desired format
if( SDL_OpenAudio( &m_audioHandle, &actual ) < 0 )
{
printf( "Couldn't open SDL-audio: %s\n", SDL_GetError() );
return;
}
m_convertEndian = ( m_audioHandle.format != actual.format );
clearS16Buffer( m_buffer, m_audioHandle.samples );
// start playing
SDL_PauseAudio( 0 );
_success_ful = TRUE;
}
audioSDL::~audioSDL()
{
SDL_PauseAudio( 1 );
SDL_CloseAudio();
SDL_Quit();
m_bufMutex.lock();
bufferAllocator::free( m_buffer );
m_bufMutex.unlock();
}
void audioSDL::writeBufferToDev( surroundSampleFrame * _ab, Uint32 _frames,
float _master_output )
{
m_bufMutex.lock();
convertToS16( _ab, _frames, _master_output, m_buffer,
m_convertEndian );
m_bufMutex.unlock();
// before returning make sure, callback was called, so we're synced
// with it (otherwise it could be that (if there's not much to render)
// this function is called several times although we had to wait until
// we can proceed with next audio-output)
m_callbackMutex.lock();
}
void audioSDL::sdlAudioCallback( void * _udata, Uint8 * _buf, int _len )
{
audioSDL * _this = static_cast<audioSDL *>( _udata );
#ifdef LMMS_DEBUG
assert( _this != NULL );
#endif
_this->m_bufMutex.lock();
// writeBufferToDev() prepared everything for us, so we just have
// to do a memcpy() :-)
memcpy( _buf, _this->m_buffer, _len );
// clear our output buffer, so that we don't output the same noise
// when being called again without that writeBufferToDev() was called
// (e.g. if there's too much to render)
_this->clearS16Buffer( _this->m_buffer, _this->m_audioHandle.samples );
_this->m_bufMutex.unlock();
// we got our last buffer, so we let writeBufferToDev() return
_this->m_callbackMutex.unlock();
}
audioSDL::setupWidget::setupWidget( QWidget * _parent ) :
audioDevice::setupWidget( audioSDL::name(), _parent )
{
QString dev = configManager::inst()->value( "audiosdl", "device" );
m_device = new QLineEdit( dev, this );
m_device->setGeometry( 10, 20, 160, 20 );
QLabel * dev_lbl = new QLabel( tr( "DEVICE" ), this );
dev_lbl->setFont( pointSize<6>( dev_lbl->font() ) );
dev_lbl->setGeometry( 10, 40, 160, 10 );
}
audioSDL::setupWidget::~setupWidget()
{
}
void audioSDL::setupWidget::saveSettings( void )
{
configManager::inst()->setValue( "audiosdl", "device",
m_device->text() );
}
#endif

View File

@@ -0,0 +1,197 @@
/*
* buffer_allocator.cpp - namespace bufferAllocator providing routines for own
* optimized memory-management for audio-buffers
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <QList>
#include <QMutex>
#else
#include <qpair.h>
#include <qvaluelist.h>
#include <qmutex.h>
#define qSort qHeapSort
#endif
#include <math.h>
#include <cstring>
#include "buffer_allocator.h"
#include "templates.h"
#include "mixer.h"
#include "debug.h"
struct bufDesc
{
bool free;
char * origPtr;
void * buf;
Uint32 bytes;
Uint32 timesUsed;
} ;
inline bool operator<( const bufDesc & _bd1, const bufDesc & _bd2 )
{
return( _bd1.timesUsed < _bd2.timesUsed );
}
#ifdef QT4
inline bool operator==( const bufDesc & _bd1, const bufDesc & _bd2 )
{
return( memcmp( &_bd1, &_bd2, sizeof( bufDesc ) ) == 0 );
}
#else
inline bool operator!=( const bufDesc & _bd1, const bufDesc & _bd2 )
{
return( memcmp( &_bd1, &_bd2, sizeof( bufDesc ) ) != 0 );
}
#endif
static vlist<bufDesc> s_buffers;
typedef vlist<bufDesc>::iterator bufIt;
QMutex s_buffersMutex;
const int BUFFER_ALIGN = 16;
const int BUFFER_ALIGN_MASK = BUFFER_ALIGN - 1;
void bufferAllocator::cleanUp( Uint16 _level )
{
// first insert all unused bufs into an array
vvector<bufDesc> bufsToRemove;
for( bufIt it = s_buffers.begin(); it != s_buffers.end(); ++it )
{
if( ( *it ).free )
{
bufsToRemove.push_back( *it );
}
}
// sort array by usage of each buffer
// ( operator<(...) compares bufDesc::timesUsed )
qSort( bufsToRemove );
const Uint16 todo = tMin<Uint16>( s_buffers.size() - _level,
bufsToRemove.size() );
// now cleanup the first n elements of sorted array
for( Uint16 i = 0; i < todo ; ++i )
{
delete[] bufsToRemove[i].origPtr;
s_buffers.erase( qFind( s_buffers.begin(), s_buffers.end(),
bufsToRemove[i] ) );
}
#ifdef LMMS_DEBUG
//printf( "cleaned up %d buffers\n", todo );
#endif
}
void bufferAllocator::free( void * _buf )
{
s_buffersMutex.lock();
// look for buffer
for( bufIt it = s_buffers.begin(); it != s_buffers.end(); ++it )
{
if( !( *it ).free && ( *it ).buf == _buf )
{
++( *it ).timesUsed;
( *it ).free = TRUE;
break;
}
}
// do clean-up if neccessary
static Uint16 CLEANUP_LEVEL = static_cast<Uint16>( 512 / ( logf(
mixer::inst()->framesPerAudioBuffer() ) /
logf( 2 ) ) );
if( s_buffers.size() > CLEANUP_LEVEL )
{
cleanUp( CLEANUP_LEVEL );
}
s_buffersMutex.unlock();
}
void * bufferAllocator::allocBytes( Uint32 _bytes )
{
QMutexLocker ml( &s_buffersMutex );
bufIt free_buf = s_buffers.end();
// look whether there's a buffer matching to the one wanted and
// find out the most used one (higher chances for being in CPU-cache)
for( bufIt it = s_buffers.begin(); it != s_buffers.end(); ++it )
{
if( ( *it ).free && ( *it ).bytes == _bytes )
{
if( free_buf == s_buffers.end() ||
( *it ).timesUsed > ( *free_buf ).timesUsed )
{
free_buf = it;
}
}
}
if( free_buf != s_buffers.end() )
{
( *free_buf ).free = FALSE;
return( ( *free_buf ).buf );
}
// nothing so far, so we'll alloc a new (aligned) buf
bufDesc d = { FALSE, new char[_bytes + BUFFER_ALIGN], NULL, _bytes, 0 };
d.buf = (void *)( (size_t) d.origPtr + ( BUFFER_ALIGN -
( (size_t) d.origPtr &
BUFFER_ALIGN_MASK ) ) );
s_buffers.push_back( d );
return( d.buf );
}

58
src/lib/clipboard.cpp Normal file
View File

@@ -0,0 +1,58 @@
/*
* clipboard.cpp - the clipboard for patterns, notes etc.
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "clipboard.h"
#include "settings.h"
namespace clipboard
{
map content;
void copy( settings * _settings_object )
{
QDomDocument doc;
QDomElement parent = doc.createElement( "clipboard" );
_settings_object->saveSettings( doc, parent );
content[_settings_object->nodeName()] =
parent.firstChild().toElement();
}
const QDomElement * getContent( const QString & _node_name )
{
if( content.find( _node_name ) != content.end() )
{
return( &content[_node_name] );
}
return( NULL );
}
} ;

123
src/lib/embed.cpp Normal file
View File

@@ -0,0 +1,123 @@
/*
* embed.cpp - misc stuff for using embedded resources (linked into binary)
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <QApplication>
#include <QTranslator>
#include <QImage>
#else
#include <qapplication.h>
#include <qtranslator.h>
#include <qimage.h>
#endif
#include "embed.h"
#include "config_mgr.h"
namespace embed
{
#include "embedded_resources.h"
QPixmap getIconPixmap( const char * _name, int _w, int _h )
{
if( _w == -1 || _h == -1 )
{
QString name = QString( _name ) + ".png";
#ifdef QT4
const embedDesc & e = findEmbeddedData(
name.toAscii().constData() );
#else
const embedDesc & e = findEmbeddedData( name.ascii() );
#endif
// not found?
if( QString( e.name ) != name )
{
// then look whether icon is in data-dir
QPixmap p( configManager::inst()->artworkDir() + name );
if( p.isNull() )
{
p = QPixmap( 1, 1 );
}
return( p );
}
QPixmap p;
p.loadFromData( e.data, e.size );
return( p );
}
#ifdef QT4
return( getIconPixmap( _name ).scaled( _w, _h, Qt::IgnoreAspectRatio,
Qt::SmoothTransformation ) );
#else
return( getIconPixmap( _name ).convertToImage().smoothScale( _w, _h ) );
#endif
}
QString getText( const char * _name )
{
const embedDesc & e = findEmbeddedData( _name );
return( QString::fromLatin1( (const char *) e.data, e.size ) );
}
void loadTranslation( const QString & _tname )
{
#if QT_VERSION >= 0x030100
QString name = _tname + ".qm";
#ifdef QT4
const embedDesc & e = findEmbeddedData( name.toAscii().constData() );
#else
const embedDesc & e = findEmbeddedData( name.ascii() );
#endif
QTranslator * t = new QTranslator( 0 );
// not found?
if( QString( e.name ) != name )
{
// then look whether translation is in data-dir
t->load( name, configManager::inst()->localeDir() );
}
else
{
t->load( e.data, (int) e.size );
}
qApp->installTranslator( t );
#endif
}
}

273
src/lib/mmp.cpp Normal file
View File

@@ -0,0 +1,273 @@
/*
* mmp.cpp - implementation of class multimediaProject
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <QFile>
#include <QMessageBox>
#else
#include <qfile.h>
#include <qmessagebox.h>
#endif
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "mmp.h"
#include "song_editor.h"
multimediaProject::typeDescStruct multimediaProject::s_types[multimediaProject::PROJ_TYPE_COUNT] =
{
{ multimediaProject::UNKNOWN, "unknown" },
{ multimediaProject::SONG_PROJECT, "song" },
{ multimediaProject::CHANNEL_SETTINGS, "channelsettings" },
{ multimediaProject::EFFECT_SETTINGS, "effectsettings" },
{ multimediaProject::VIDEO_PROJECT, "video" },
{ multimediaProject::BURN_PROJECT, "burn" },
{ multimediaProject::PLAYLIST, "playlist" }
} ;
multimediaProject::multimediaProject( projectTypes _project_type ) :
QDomDocument( "multimedia-project" ),
m_content(),
m_head(),
m_type( _project_type )
{
QDomElement root = createElement( "multimediaproject" );
root.setAttribute( "version", MMP_VERSION_STRING );
root.setAttribute( "type", typeName( _project_type ) );
root.setAttribute( "creator", "Linux MultiMedia Studio (LMMS)" );
root.setAttribute( "creatorversion", VERSION );
appendChild( root );
m_head = createElement( "head" );
root.appendChild( m_head );
m_content = createElement( typeName( _project_type ) );
root.appendChild( m_content );
}
multimediaProject::multimediaProject( const QString & _in_file_name ) :
QDomDocument(),
m_content(),
m_head()
{
QFile in_file( _in_file_name );
#ifdef QT4
if( !in_file.open( QIODevice::ReadOnly ) )
#else
if( !in_file.open( IO_ReadOnly ) )
#endif
{
QMessageBox::critical( NULL,
songEditor::tr( "Could not open file" ),
songEditor::tr( "Could not open "
"file %1. You probably "
"have no rights to "
"read this file.\n"
"Please make sure you "
"have at least read-"
"access to the file "
"and try again."
).arg( _in_file_name ) );
return;
}
QString error_msg;
int line;
int col;
if( !setContent( &in_file, &error_msg, &line, &col ) )
{
QMessageBox::critical( NULL, songEditor::tr( "Error in "
"multimedia-project" ),
songEditor::tr( "The multimedia-"
"project %1 seems to "
"contain errors. LMMS "
"will try its best "
"to recover as much as "
"possible data from "
"this file."
).arg( _in_file_name ) );
return;
}
in_file.close();
QDomElement root = documentElement();
m_type = type( root.attribute( "type" ) );
QDomNode node = root.firstChild();
while( !node.isNull() )
{
if( node.isElement() )
{
if( node.nodeName() == "head" )
{
m_head = node.toElement();
}
else if( node.nodeName() == typeName( m_type ) )
{
m_content = node.toElement();
}
}
node = node.nextSibling();
}
}
multimediaProject::~multimediaProject()
{
}
bool multimediaProject::writeFile( const QString & _fn, bool _overwrite_check )
{
QString xml = "<?xml version=\"1.0\"?>\n" + toString(
#if QT_VERSION >= 0x030100
2
#endif
);
QString fn = _fn;
if( type() == CHANNEL_SETTINGS )
{
if( fn.section( '.', -2, -1 ) != "cs.xml" )
{
fn += ".cs.xml";
}
}
else if( fn.section( '.',-1 ) != "xml" )
{
fn += ".xml";
}
QFile outfile( fn );
if( _overwrite_check == TRUE &&
outfile.exists() == TRUE &&
QMessageBox::
#if QT_VERSION >= 0x030200
question
#else
information
#endif
( NULL,
songEditor::tr( "File already exists" ),
songEditor::tr( "The file %1 already "
"exists.\nDo you want "
"to overwrite it?"
).arg( fn ),
QMessageBox::Yes, QMessageBox::No )
== QMessageBox::No )
{
return( FALSE );
}
#ifdef QT4
if( !outfile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
#else
if( !outfile.open( IO_WriteOnly | IO_Truncate ) )
#endif
{
QMessageBox::critical( NULL, songEditor::tr( "Could not write "
"file" ),
songEditor::tr( "Could not write file "
"%1. You probably are "
"not permitted to "
"write to this file. "
"Please make sure you "
"have write-access to "
"the file and try "
"again."
).arg( fn ) );
return( FALSE );
}
#ifdef QT4
outfile.write( xml.toAscii().constData(), xml.length() );
#else
outfile.writeBlock( xml.ascii(), xml.length() );
#endif
outfile.close();
return( TRUE );
}
multimediaProject::projectTypes multimediaProject::typeOfFile(
const QString & _fn )
{
multimediaProject m( _fn );
return( m.type() );
}
multimediaProject::projectTypes multimediaProject::type(
const QString & _type_name )
{
for( int i = 0; i < PROJ_TYPE_COUNT; ++i )
{
if( s_types[i].m_name == _type_name )
{
return( static_cast<multimediaProject::projectTypes>(
i ) );
}
}
return( UNKNOWN );
}
QString multimediaProject::typeName( projectTypes _project_type )
{
if( _project_type >= UNKNOWN && _project_type < PROJ_TYPE_COUNT )
{
return( s_types[_project_type].m_name );
}
return( s_types[UNKNOWN].m_name );
}

259
src/lib/oscillator.cpp Normal file
View File

@@ -0,0 +1,259 @@
/*
* oscillator.cpp - implementation of powerful oscillator-class
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "oscillator.h"
const sampleFrame zero_frame = { 0.0f, 0.0f };
oscillator::oscillator( modulationAlgos _modulation_algo, float _freq,
Sint16 _phase_offset, float _volume_factor,
oscillator * _sub_osc ) :
m_freq(_freq),
m_volumeFactor(_volume_factor),
m_phaseOffset(_phase_offset),
m_subOsc(_sub_osc),
m_userWaveData( &zero_frame ),
m_userWaveFrames( 1 )
{
if( m_subOsc != NULL )
{
switch( _modulation_algo )
{
case FREQ_MODULATION:
m_callUpdate = &oscillator::updateFM;
break;
case AMP_MODULATION:
m_callUpdate = &oscillator::updateAM;
break;
case MIX:
m_callUpdate = &oscillator::updateMix;
break;
case SYNC:
m_callUpdate = &oscillator::updateSync;
break;
}
}
else
{
m_callUpdate = &oscillator::updateNoSub;
}
recalcOscCoeff();
}
// if we have no sub-osc, we can't do any modulation... just get our samples
#define defineNoSubUpdateFor(x,getSampleFunction) \
void x::updateNoSub( sampleFrame * _ab, Uint32 _frames, Uint8 _chnl ) \
{ \
for( Uint16 frame = 0; frame < _frames; ++frame ) \
{ \
_ab[frame][_chnl] = getSampleFunction( ++m_sample * \
m_oscCoeff ) * m_volumeFactor; \
} \
}
// do fm by using sub-osc as modulator
#define defineFMUpdateFor(x,getSampleFunction) \
void x::updateFM( sampleFrame * _ab, Uint32 _frames, Uint8 _chnl ) \
{ \
m_subOsc->update( _ab, _frames, _chnl ); \
for( Uint16 frame = 0; frame < _frames; ++frame ) \
{ \
_ab[frame][_chnl] = getSampleFunction( ++m_sample * \
m_oscCoeff + \
_ab[frame][_chnl] ) * \
m_volumeFactor; \
/* following line is REAL FM */ \
/* float new_freq = powf( 2.0, _ab[frame][_chnl] ); \
_ab[frame][_chnl] = getSampleFunction( ++m_sample*((m_freq * \
new_freq )/mixer::inst()->sampleRate() )) * m_volumeFactor; \
_ab[frame][_chnl] = getSampleFunction( ++m_sample*(m_oscCoeff *\
_ab[frame][_chnl] )) * m_volumeFactor;*/ \
} \
}
// do am by using sub-osc as modulator
#define defineAMUpdateFor(x,getSampleFunction) \
void x::updateAM( sampleFrame * _ab, Uint32 _frames, Uint8 _chnl ) \
{ \
m_subOsc->update( _ab, _frames, _chnl ); \
for( Uint16 frame = 0; frame < _frames; ++frame ) \
{ \
_ab[frame][_chnl] *= getSampleFunction( ++m_sample * \
m_oscCoeff ) * m_volumeFactor; \
} \
}
// do mix by using sub-osc as mix-sample
#define defineMixUpdateFor(x,getSampleFunction) \
void x::updateMix( sampleFrame * _ab, Uint32 _frames, Uint8 _chnl ) \
{ \
m_subOsc->update( _ab, _frames, _chnl ); \
for( Uint16 frame = 0; frame < _frames; ++frame ) \
{ \
_ab[frame][_chnl] += getSampleFunction( ++m_sample * \
m_oscCoeff ) * m_volumeFactor; \
} \
}
// sync with sub-osc (every time sub-osc starts new period, we also start new
// period)
#define defineSyncUpdateFor(x,getSampleFunction) \
void x::updateSync( sampleFrame * _ab, Uint32 _frames, Uint8 _chnl ) \
{ \
for( Uint16 frame = 0; frame < _frames ; ++frame ) \
{ \
if( m_subOsc->syncOk() ) \
{ \
sync(); \
} \
_ab[frame][_chnl] = getSampleFunction( ++m_sample * \
m_oscCoeff ) * m_volumeFactor; \
} \
}
#define generateOscillatorCodeFor(x,getSampleFunction); \
class x : public oscillator \
{ \
public: \
x( modulationAlgos modulation_algo, float _freq, Sint16 _phase_offset, \
float _volume_factor, oscillator * _sub_osc) : \
oscillator (modulation_algo, _freq, _phase_offset, _volume_factor, \
_sub_osc ) \
{ \
} \
\
protected: \
void updateNoSub( sampleFrame * _ab, Uint32 _frames, \
Uint8 _chnl ); \
void updateFM( sampleFrame * _ab, Uint32 _frames, \
Uint8 _chnl ); \
void updateAM( sampleFrame * _ab, Uint32 _frames, \
Uint8 _chnl ); \
void updateMix( sampleFrame * _ab, Uint32 _frames, \
Uint8 _chnl ); \
void updateSync( sampleFrame * _ab, Uint32 _frames, \
Uint8 _chnl ); \
\
} ; \
\
defineNoSubUpdateFor( x, getSampleFunction ) \
defineFMUpdateFor( x, getSampleFunction ) \
defineAMUpdateFor( x, getSampleFunction ) \
defineMixUpdateFor( x, getSampleFunction ) \
defineSyncUpdateFor( x, getSampleFunction )
generateOscillatorCodeFor( sinWaveOsc, sinSample );
generateOscillatorCodeFor( triangleWaveOsc, triangleSample );
generateOscillatorCodeFor( sawWaveOsc, sawSample );
generateOscillatorCodeFor( squareWaveOsc, squareSample );
generateOscillatorCodeFor( moogSawWaveOsc, moogSawSample );
generateOscillatorCodeFor( expWaveOsc, expSample );
generateOscillatorCodeFor( noiseWaveOsc, noiseSample );
generateOscillatorCodeFor( userWaveOsc, userWaveSample );
oscillator * FASTCALL oscillator::createNewOsc( waveShapes _wave_shape,
modulationAlgos _modulation_algo,
float _freq, Sint16 _phase_offset,
float _volume_factor,
oscillator * _sub_osc )
{
switch( _wave_shape )
{
case SIN_WAVE:
return( new sinWaveOsc( _modulation_algo, _freq,
_phase_offset, _volume_factor,
_sub_osc ) );
case TRIANGLE_WAVE:
return( new triangleWaveOsc( _modulation_algo, _freq,
_phase_offset, _volume_factor,
_sub_osc ) );
case SAW_WAVE:
return( new sawWaveOsc( _modulation_algo, _freq,
_phase_offset, _volume_factor,
_sub_osc ) );
case SQUARE_WAVE:
return( new squareWaveOsc( _modulation_algo, _freq,
_phase_offset, _volume_factor,
_sub_osc ) );
case MOOG_SAW_WAVE:
return( new moogSawWaveOsc( _modulation_algo, _freq,
_phase_offset, _volume_factor,
_sub_osc ) );
case EXP_WAVE:
return( new expWaveOsc( _modulation_algo, _freq,
_phase_offset, _volume_factor,
_sub_osc ) );
case WHITE_NOISE_WAVE:
return( new noiseWaveOsc( _modulation_algo, _freq,
_phase_offset, _volume_factor,
_sub_osc ) );
case USER_DEF_WAVE:
return( new userWaveOsc( _modulation_algo, _freq,
_phase_offset, _volume_factor,
_sub_osc ) );
default:
return( new sinWaveOsc( _modulation_algo, _freq,
_phase_offset, _volume_factor,
_sub_osc ) );
}
}
// should be called every time phase-offset or frequency is changed...
void oscillator::recalcOscCoeff( const float additional_phase_offset )
{
m_oscCoeff = m_freq / static_cast<float>( mixer::inst()->sampleRate() );
m_sample = static_cast<Uint32>( ( m_phaseOffset * ( 1.0f / 360.0f ) +
additional_phase_offset ) *
( mixer::inst()->sampleRate() /
m_freq ) );
// because we pre-increment m_sample in update-function, we should
// decrement it here... (not possible when 0 because it is
// unsigned - overflow!!!)
if( m_sample > 0 )
{
--m_sample;
}
}

1014
src/lib/sample_buffer.cpp Normal file

File diff suppressed because it is too large Load Diff

233
src/midi/midi_alsa_raw.cpp Normal file
View File

@@ -0,0 +1,233 @@
/*
* midi_alsa_raw.cpp - midi-device-driver for RawMIDI via ALSA
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <QLineEdit>
#include <QLabel>
#else
#include <qpair.h>
#include <qlineedit.h>
#include <qlabel.h>
#endif
#include "midi_alsa_raw.h"
#include "config_mgr.h"
#include "templates.h"
#ifdef ALSA_SUPPORT
midiALSARaw::midiALSARaw( channelTrack * _ct ) :
midiDevice( _ct ),
QThread(),
m_inputp( &m_input ),
m_outputp( &m_output ),
m_quit( FALSE )
{
int err;
if( ( err = snd_rawmidi_open( m_inputp, m_outputp,
#ifdef QT4
probeDevice().toAscii().constData(),
#else
probeDevice().ascii(),
#endif
0 ) ) < 0 )
{
printf( "cannot open MIDI-device: %s\n", snd_strerror( err ) );
return;
}
snd_rawmidi_read( m_input, NULL, 0 );
snd_rawmidi_nonblock( m_input, 1 );
m_npfds = snd_rawmidi_poll_descriptors_count( m_input );
m_pfds = new pollfd[m_npfds];
snd_rawmidi_poll_descriptors( m_input, m_pfds, m_npfds );
start(
#if QT_VERSION >= 0x030200
QThread::LowPriority
#endif
);
}
midiALSARaw::~midiALSARaw()
{
if( running() )
{
m_quit = TRUE;
wait( 500 );
terminate();
snd_rawmidi_close( m_input );
snd_rawmidi_close( m_output );
delete[] m_pfds;
}
}
QString midiALSARaw::probeDevice( void )
{
QString dev = configManager::inst()->value( "midialsa", "device" );
if( dev == "" )
{
if( getenv( "MIDIDEV" ) != NULL )
{
return( getenv( "MIDIDEV" ) );
}
return( "default" );
}
return( dev );
}
void midiALSARaw::sendByte( Uint8 _c )
{
snd_rawmidi_write( m_output, &_c, sizeof( _c ) );
}
void midiALSARaw::run( void )
{
Uint8 buf[128];
//int cnt = 0;
while( m_quit == FALSE )
{
msleep( 5 ); // must do that, otherwise this thread takes
// too much CPU-time, even with LowPriority...
int err = poll( m_pfds, m_npfds, 10000 );
if( err < 0 && errno == EINTR )
{
printf( "midiALSARaw::run(): Got EINTR while "
"polling. Will stop polling MIDI-events from "
"MIDI-port.\n" );
break;
}
if( err < 0 )
{
printf( "poll failed: %s\nWill stop polling "
"MIDI-events from MIDI-port.\n",
strerror( errno ) );
break;
}
if( err == 0 )
{
//printf( "there seems to be no active MIDI-device %d\n", ++cnt );
continue;
}
unsigned short revents;
if( ( err = snd_rawmidi_poll_descriptors_revents(
m_input, m_pfds, m_npfds, &revents ) ) < 0 )
{
printf( "cannot get poll events: %s\nWill stop polling "
"MIDI-events from MIDI-port.\n",
snd_strerror( errno ) );
break;
}
if( revents & ( POLLERR | POLLHUP ) )
{
printf( "POLLERR or POLLHUP\n" );
break;
}
if( !( revents & POLLIN ) )
{
continue;
}
err = snd_rawmidi_read( m_input, buf, sizeof( buf ) );
if( err == -EAGAIN )
{
continue;
}
if( err < 0 )
{
printf( "cannot read from port \"%s\": %s\nWill stop "
"polling MIDI-events from MIDI-port.\n",
/*port_name*/"default", snd_strerror( err ) );
break;
}
if( err == 0 )
continue;
for( int i = 0; i < err; ++i )
{
const midiEvent * midi_event = parseData( buf[i] );
if( midi_event != NULL )
{
processInEvent( *midi_event );
}
}
}
}
midiALSARaw::setupWidget::setupWidget( QWidget * _parent ) :
midiDevice::setupWidget( midiALSARaw::name(), _parent )
{
m_device = new QLineEdit( midiALSARaw::probeDevice(), this );
m_device->setGeometry( 10, 20, 160, 20 );
QLabel * dev_lbl = new QLabel( tr( "DEVICE" ), this );
dev_lbl->setFont( pointSize<6>( dev_lbl->font() ) );
dev_lbl->setGeometry( 10, 40, 160, 10 );
}
midiALSARaw::setupWidget::~setupWidget()
{
}
void midiALSARaw::setupWidget::saveSettings( void )
{
configManager::inst()->setValue( "midialsa", "device",
m_device->text() );
}
#endif

222
src/midi/midi_mapper.cpp Normal file
View File

@@ -0,0 +1,222 @@
/*
* midi_mapper.cpp - MIDI-mapper for any midiDevice
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "midi_mapper.h"
#ifdef QT4
#include <QRegExp>
#else
#include <qregexp.h>
#define indexOf find
#endif
midiMapper::midiMapper( const QString & _map ) :
m_drumsetChannel( 0 ),
m_drumsetPatch( 0 )
{
// default mappings
for( Uint8 i = 0; i < MIDI_PROGRAMS; ++i )
{
m_patchMap[i].first = i;
}
for( Uint8 i = 0; i < MIDI_KEYS; ++i )
{
m_drumsetKeyMap[i].first = i;
}
for( Uint8 i = 0; i < MIDI_CHANNELS; ++i )
{
m_channelMap[i] = i;
}
QFile map( _map );
#ifdef QT4
if( !map.open( QIODevice::ReadOnly ) )
#else
if( !map.open( IO_ReadOnly ) )
#endif
{
return;
}
while( !map.atEnd() )
{
char buf[1024];
int len = map.readLine( buf, sizeof( buf ) );
if( len <= 0 )
{
continue;
}
QString line( buf );
line.replace( '\n', "" );
if( line.left( 6 ) == "DEFINE" )
{
if( line.section( ' ', 1, 1 ) == "PATCHMAP" )
{
readPatchMap( map );
}
else if( line.section( ' ', 1, 1 ) == "KEYMAP" &&
line.section( ' ', 2, 2 ) ==
"\"Drumset\"" )
{
readDrumsetKeyMap( map );
}
else if( line.section( ' ', 1, 1 ) == "CHANNELMAP" )
{
readChannelMap( map );
}
}
}
}
midiMapper::~midiMapper()
{
}
void midiMapper::readPatchMap( QFile & _f )
{
Uint8 prog_idx = 0;
while( !_f.atEnd() && prog_idx < MIDI_PROGRAMS )
{
char buf[1024];
int len = _f.readLine( buf, sizeof( buf ) );
if( len <= 0 )
{
continue;
}
QString line( buf );
line.replace( '\n', "" );
if( line.left( 3 ) == "END" )
{
return;
}
if( QString( line ).replace( ' ', "" )[0] == '#' )
{
continue;
}
m_patchMap[prog_idx].first = line.section( '=', 1, 1 ).toInt();
m_patchMap[prog_idx].second = line.section( '=', 0, 0 ).
replace( ' ', "" );
++prog_idx;
}
}
void midiMapper::readDrumsetKeyMap( QFile & _f )
{
Uint8 key = 0;
while( !_f.atEnd() )
{
char buf[1024];
int len = _f.readLine( buf, sizeof( buf ) );
if( len <= 0 )
{
continue;
}
QString line( buf );
line.replace( '\n', "" );
if( line.left( 3 ) == "END" )
{
return;
}
if( QString( line ).replace( ' ', "" )[0] == '#' )
{
continue;
}
if( line[4] != '=' )
{
m_drumsetKeyMap[key].first = line.section( '=', 1, 1 ).
toInt();
m_drumsetKeyMap[key].second = line.mid( 4 ).
section( '=', 0, 0 ).
section( ' ', 1, 1 ).
replace( ' ', "" );
}
++key;
}
}
void midiMapper::readChannelMap( QFile & _f )
{
while( !_f.atEnd() )
{
char buf[1024];
int len = _f.readLine( buf, sizeof( buf ) );
if( len <= 0 )
{
continue;
}
QString line( buf );
line.replace( '\n', "" );
if( line.left( 3 ) == "END" )
{
return;
}
if( QString( line ).replace( ' ', "" )[0] == '#' )
{
continue;
}
Uint8 ch = line.section( ' ', 0, 0 ).toInt();
Uint8 mch = line.section( '=', 1, 1 ).mid( 1 ).
section( ' ', 0, 0 ).
toInt();
if( ch < MIDI_CHANNELS && mch < MIDI_CHANNELS )
{
m_channelMap[ch] = mch;
if( line.contains( QRegExp( "Keymap *\"Drumset\"" ) ) )
{
m_drumsetChannel = mch;
int fp = line.indexOf( "ForcePatch" );
if( fp != -1 )
{
m_drumsetPatch = line.mid( fp ).
section( ' ', 1, 1 ).
toInt();
}
}
}
}
}
#undef indexOf

164
src/midi/midi_oss.cpp Normal file
View File

@@ -0,0 +1,164 @@
/*
* midi_oss.cpp - simple midi-device-driver for OSS
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <QLineEdit>
#include <QLabel>
#else
#include <qmap.h>
#include <qlineedit.h>
#include <qlabel.h>
#endif
#include "midi_oss.h"
#include "config_mgr.h"
#include "templates.h"
midiOSS::midiOSS( channelTrack * _ct ) :
midiDevice( _ct ),
QThread(),
m_midiDev( probeDevice() ),
m_quit( FALSE )
{
// only start thread, if opening of MIDI-device is successful,
// otherwise isRunning()==FALSE indicates error
#ifdef QT4
if( m_midiDev.open( QIODevice::ReadWrite ) ||
m_midiDev.open( QIODevice::ReadOnly ) )
#else
if( m_midiDev.open( IO_ReadWrite ) || m_midiDev.open( IO_ReadOnly ) )
#endif
{
start(
#if QT_VERSION >= 0x030200
QThread::LowPriority
#endif
);
}
}
midiOSS::~midiOSS()
{
m_quit = TRUE;
wait( 500 );
terminate();
}
QString midiOSS::probeDevice( void )
{
QString dev = configManager::inst()->value( "midioss", "device" );
if( dev == "" )
{
if( getenv( "MIDIDEV" ) != NULL )
{
return( getenv( "MIDIDEV" ) );
}
return( "/dev/midi" );
}
return( dev );
}
void midiOSS::sendByte( Uint8 _c )
{
#ifdef QT4
m_midiDev.putChar( _c );
#else
m_midiDev.putch( _c );
#endif
}
void midiOSS::run( void )
{
while( m_quit == FALSE )
{
#ifdef QT4
char c;
if( !m_midiDev.getChar( &c ) )
{
continue;
}
const midiEvent * midi_event = parseData( c );
#else
const midiEvent * midi_event = parseData( m_midiDev.getch() );
#endif
if( midi_event != NULL )
{
processInEvent( *midi_event );
}
}
}
midiOSS::setupWidget::setupWidget( QWidget * _parent ) :
midiDevice::setupWidget( midiOSS::name(), _parent )
{
m_device = new QLineEdit( midiOSS::probeDevice(), this );
m_device->setGeometry( 10, 20, 160, 20 );
QLabel * dev_lbl = new QLabel( tr( "DEVICE" ), this );
dev_lbl->setFont( pointSize<6>( dev_lbl->font() ) );
dev_lbl->setGeometry( 10, 40, 160, 10 );
}
midiOSS::setupWidget::~setupWidget()
{
}
void midiOSS::setupWidget::saveSettings( void )
{
configManager::inst()->setValue( "midioss", "device",
m_device->text() );
}

509
src/tracks/bb_track.cpp Normal file
View File

@@ -0,0 +1,509 @@
/*
* bb_track.cpp - implementation of class bbTrack
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <Qt/QtXml>
#include <QPainter>
#include <QColorDialog>
#include <QMenu>
#else
#include <qdom.h>
#include <qpainter.h>
#include <qcolordialog.h>
#include <qpopupmenu.h>
#endif
#include "bb_track.h"
#include "song_editor.h"
#include "bb_editor.h"
#include "templates.h"
#include "name_label.h"
#include "embed.h"
#include "rename_dialog.h"
#include "bb_track.moc"
QMap<bbTrack *, bbTrack::bbInfoStruct> bbTrack::s_bbNums;
bbTCO::bbTCO( track * _track, const QColor & _c ) :
trackContentObject( _track ),
m_name( ( dynamic_cast<bbTrack *>( _track ) != NULL ) ?
dynamic_cast<bbTrack *>( _track )->trackLabel()->text() :
QString( "" ) ),
m_color( _c.isValid() ? _c : QColor( 64, 128, 255 ) )
{
//setPaletteBackgroundColor( QColor( 64, 128, 255 ) );
#ifndef QT4
setBackgroundMode( Qt::NoBackground );
#endif
tact t = bbEditor::inst()->lengthOfBB(
bbTrack::numOfBBTrack( getTrack() ) );
if( t > 0 )
{
changeLength( midiTime( t, 0 ) );
}
}
bbTCO::~bbTCO()
{
}
void bbTCO::movePosition( const midiTime & _pos )
{
// bb-playlist-entries are always aligned on tact-boundaries
trackContentObject::movePosition( midiTime( _pos.getTact(), 0 ) );
}
void bbTCO::changeLength( const midiTime & _length )
{
// the length of bb-playlist-entries is always a multiple of one tact
trackContentObject::changeLength( midiTime( _length.getTact(), 0 ) );
}
void bbTCO::constructContextMenu( QMenu * _cm )
{
#ifdef QT4
QAction * a = new QAction( embed::getIconPixmap( "bb_track" ),
tr( "Open in Beat+Bassline-Editor" ),
_cm );
_cm->insertAction( _cm->actions()[0], a );
connect( a, SIGNAL( triggered( bool ) ), this,
SLOT( openInBBEditor( bool ) ) );
#else
_cm->insertItem( embed::getIconPixmap( "bb_track" ),
tr( "Open in Beat+Bassline-Editor" ),
this, SLOT( openInBBEditor() ),
0, -1, 0 );
#endif
#ifdef QT4
_cm->insertSeparator( _cm->actions()[1] );
#else
_cm->insertSeparator( 1 );
#endif
#ifdef QT4
_cm->addSeparator();
#else
_cm->insertSeparator();
#endif
_cm->addAction( embed::getIconPixmap( "reload" ), tr( "Reset name" ),
this, SLOT( resetName() ) );
_cm->addAction( embed::getIconPixmap( "rename" ), tr( "Change name" ),
this, SLOT( changeName() ) );
_cm->addAction( embed::getIconPixmap( "colorize" ),
tr( "Change color" ), this, SLOT( changeColor() ) );
}
void bbTCO::mouseDoubleClickEvent( QMouseEvent * )
{
openInBBEditor();
}
void bbTCO::paintEvent( QPaintEvent * )
{
QColor col = m_color;
if( getTrack()->muted() )
{
col = QColor( 160, 160, 160 );
}
#ifdef QT4
QPainter p( this );
// TODO: set according brush/pen for gradient!
p.fillRect( rect(), col );
#else
// create pixmap for whole widget
QPixmap pm( rect().size() );
// and a painter for it
QPainter p( &pm );
// COOL gradient ;-)
for( int y = 0; y < height(); ++y )
{
p.setPen( col.light( 130 - y * 60 / height() ) );
p.drawLine( 0, y, width(), y );
}
//pm.fill( col );
#endif
tact t = bbEditor::inst()->lengthOfBB( bbTrack::numOfBBTrack(
getTrack() ) );
if( length().getTact() > 1 && t > 0 )
{
for( int x = TCO_BORDER_WIDTH + static_cast<int>( t *
pixelsPerTact() ); x < width();
x += static_cast<int>( t * pixelsPerTact() ) )
{
p.setPen( col.light( 80 ) );
p.drawLine( x, 1, x, 5 );
p.setPen( col.light( 120 ) );
p.drawLine( x, height() - 6, x, height() - 2 );
}
}
p.setPen( col.dark() );
p.drawRect( 0, 0, width(), height() );
p.setFont( pointSize<7>( p.font() ) );
p.setPen( QColor( 0, 0, 0 ) );
p.drawText( 2, QFontMetrics( p.font() ).height() - 1, m_name );
#ifndef QT4
bitBlt( this, rect().topLeft(), &pm );
#endif
}
void bbTCO::saveSettings( QDomDocument & _doc, QDomElement & _parent )
{
QDomElement bbtco_de = _doc.createElement( nodeName() );
bbtco_de.setAttribute( "name", m_name );
if( _parent.nodeName() == "clipboard" )
{
bbtco_de.setAttribute( "pos", QString::number( -1 ) );
}
else
{
bbtco_de.setAttribute( "pos",
QString::number( startPosition() ) );
}
bbtco_de.setAttribute( "len", QString::number( length() ) );
bbtco_de.setAttribute( "color", QString::number( m_color.rgb() ) );
_parent.appendChild( bbtco_de );
}
void bbTCO::loadSettings( const QDomElement & _this )
{
m_name = _this.attribute( "name" );
if( _this.attribute( "pos" ).toInt() >= 0 )
{
movePosition( _this.attribute( "pos" ).toInt() );
}
changeLength( _this.attribute( "len" ).toInt() );
if( _this.attribute( "color" ).toUInt() != 0 )
{
m_color.setRgb( _this.attribute( "color" ).toUInt() );
}
}
void bbTCO::openInBBEditor( bool )
{
bbEditor::inst()->setCurrentBB( bbTrack::numOfBBTrack( getTrack() ) );
bbEditor::inst()->show();
bbEditor::inst()->setFocus();
}
void bbTCO::openInBBEditor( void )
{
openInBBEditor( FALSE );
}
void bbTCO::resetName( void )
{
if( dynamic_cast<bbTrack *>( getTrack() ) != NULL )
{
m_name = dynamic_cast<bbTrack *>( getTrack() )->
trackLabel()->text();
}
}
void bbTCO::changeName( void )
{
renameDialog rename_dlg( m_name );
rename_dlg.exec();
}
void bbTCO::changeColor( void )
{
QColor _new_color = QColorDialog::getColor( m_color );
if( _new_color.isValid() && _new_color != m_color )
{
m_color = _new_color;
songEditor::inst()->setModified();
update();
}
}
bbTrack::bbTrack( trackContainer * _tc )
: track( _tc )
{
getTrackWidget()->setFixedHeight( 32 );
csize bbNum = s_bbNums.size();
bbInfoStruct bis = { bbNum, "" };
s_bbNums[this] = bis;
m_trackLabel = new nameLabel( tr( "Beat/Bassline %1" ).arg( bbNum ),
getTrackSettingsWidget(),
embed::getIconPixmap( "bb_track" ) );
m_trackLabel->setGeometry( 1, 1, DEFAULT_SETTINGS_WIDGET_WIDTH-2, 29 );
m_trackLabel->show();
connect( m_trackLabel, SIGNAL( clicked() ), this,
SLOT( clickedTrackLabel() ) );
bbEditor::inst()->setCurrentBB( bbNum );
_tc->updateAfterTrackAdd();
}
bbTrack::~bbTrack()
{
csize bb = s_bbNums[this].num;
bbEditor::inst()->removeBB( bb );
for( QMap<bbTrack *, bbTrack::bbInfoStruct>::iterator it =
s_bbNums.begin(); it != s_bbNums.end(); ++it )
{
#ifdef QT4
if( it.value().num > bb )
{
--it.value().num;
}
#else
if( it.data().num > bb )
{
--it.data().num;
}
#endif
}
s_bbNums.remove( this );
}
track::trackTypes bbTrack::trackType( void ) const
{
return( BB_TRACK );
}
// play _frames frames of given TCO within starting with _start/_start_frame
bool FASTCALL bbTrack::play( const midiTime & _start, Uint32 _start_frame,
Uint32 _frames, Uint32 _frame_base,
Sint16 _tco_num )
{
if( _tco_num >= 0 )
{
return( bbEditor::inst()->play( _start, _start_frame, _frames,
_frame_base,
s_bbNums[this].num ) );
}
vlist<trackContentObject *> tcos;
getTCOsInRange( tcos, _start, _start +static_cast<Sint32>( _frames *
64 / songEditor::inst()->framesPerTact() ) );
if ( tcos.size() == 0 )
{
return( FALSE );
}
midiTime lastPosition;
midiTime lastLen;
for( vlist<trackContentObject *>::iterator it = tcos.begin();
it != tcos.end(); ++it )
{
if( ( *it )->startPosition() >= lastPosition )
{
lastPosition = ( *it )->startPosition();
lastLen = ( *it )->length();
}
}
if( _start - lastPosition < lastLen )
{
return( bbEditor::inst()->play( _start - lastPosition,
_start_frame, _frames,
_frame_base,
s_bbNums[this].num ) );
}
return( FALSE );
}
trackContentObject * bbTrack::createTCO( const midiTime & _pos )
{
// if we're creating a new bbTCO, we colorize it according to the
// previous bbTCO, so we have to get all TCOs from 0 to _pos and
// pickup the last and take the color if it
vlist<trackContentObject *> tcos;
getTCOsInRange( tcos, 0, _pos );
if( tcos.size() > 0 && dynamic_cast<bbTCO *>( tcos.back() ) != NULL )
{
return( new bbTCO( this,
dynamic_cast<bbTCO *>( tcos.back() )->color() ) );
}
return( new bbTCO( this ) );
}
void bbTrack::saveTrackSpecificSettings( QDomDocument & _doc,
QDomElement & _parent )
{
QDomElement bbt_de = _doc.createElement( nodeName() );
bbt_de.setAttribute( "name", m_trackLabel->text() );
/* bbt_de.setAttribute( "current", s_bbNums[this].num ==
bbEditor::inst()->currentBB() );*/
_parent.appendChild( bbt_de );
if( s_bbNums[this].num == 0 &&
_parent.parentNode().nodeName() != "clone" )
{
bbEditor::inst()->saveSettings( _doc, bbt_de );
}
}
void bbTrack::loadTrackSpecificSettings( const QDomElement & _this )
{
m_trackLabel->setText( _this.attribute( "name" ) );
if( _this.firstChild().isElement() )
{
bbEditor::inst()->loadSettings(
_this.firstChild().toElement() );
}
/* doesn't work yet because bbTrack-ctor also sets current bb so if
bb-tracks are created after this function is called, this doesn't
help at all....
if( _this.attribute( "current" ).toInt() )
{
bbEditor::inst()->setCurrentBB( s_bbNums[this].num );
}*/
}
// return pointer to bbTrack specified by _bb_num
bbTrack * bbTrack::findBBTrack( csize _bb_num )
{
for( QMap<bbTrack *, bbTrack::bbInfoStruct>::iterator it =
s_bbNums.begin();
it != s_bbNums.end(); ++it )
{
#ifdef QT4
if( it.value().num == _bb_num )
#else
if( it.data().num == _bb_num )
#endif
{
return( it.key() );
}
}
return( NULL );
}
csize bbTrack::numOfBBTrack( track * _track )
{
if( dynamic_cast<bbTrack *>( _track ) != NULL )
{
return( s_bbNums[dynamic_cast<bbTrack *>( _track )].num );
}
return( 0 );
}
void bbTrack::swapBBTracks( track * _track1, track * _track2 )
{
bbTrack * t1 = dynamic_cast<bbTrack *>( _track1 );
bbTrack * t2 = dynamic_cast<bbTrack *>( _track2 );
if( t1 != NULL && t2 != NULL )
{
qSwap( s_bbNums[t1].num, s_bbNums[t2].num );
bbEditor::inst()->swapBB( s_bbNums[t1].num, s_bbNums[t2].num );
bbEditor::inst()->setCurrentBB( s_bbNums[t2].num );
}
}
void bbTrack::clickedTrackLabel( void )
{
bbEditor::inst()->setCurrentBB( s_bbNums[this].num );
bbEditor::inst()->show();
}

1027
src/tracks/pattern.cpp Normal file

File diff suppressed because it is too large Load Diff

395
src/tracks/sample_track.cpp Normal file
View File

@@ -0,0 +1,395 @@
/*
* sample_track.cpp - implementation of class sampleTrack, a track which
* provides arrangement of samples
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <QPushButton>
#include <QPainter>
#include <Qt/QtXml>
#else
#include <qpushbutton.h>
#include <qpainter.h>
#include <qdom.h>
#endif
#include "sample_track.h"
#include "song_editor.h"
#include "name_label.h"
#include "embed.h"
#include "templates.h"
#include "buffer_allocator.h"
#include "tooltip.h"
sampleTCO::sampleTCO( track * _track ) :
trackContentObject( _track ),
m_sampleBuffer()
{
#ifndef QT4
setBackgroundMode( Qt::NoBackground );
#endif
setSampleFile( "" );
// we need to receive bpm-change-events, because then we have to
// change length of this TCO
connect( songEditor::inst(), SIGNAL( bpmChanged( int ) ), this,
SLOT( updateLength( int ) ) );
}
sampleTCO::~sampleTCO()
{
}
void sampleTCO::changeLength( const midiTime & _length )
{
trackContentObject::changeLength( tMax( static_cast<Sint32>( _length ),
64 ) );
}
void FASTCALL sampleTCO::play( sampleFrame * _ab, Uint32 _start_frame,
Uint32 _frames )
{
_start_frame = static_cast<Uint32>( tMax( 0.0f, _start_frame -
startPosition() *
songEditor::inst()->framesPerTact() / 64 ) );
m_sampleBuffer.play( _ab, _start_frame, _frames );
}
const QString & sampleTCO::sampleFile( void ) const
{
return( m_sampleBuffer.audioFile() );
}
void sampleTCO::setSampleFile( const QString & _sf )
{
m_sampleBuffer.setAudioFile( _sf );
updateLength();
update();
// set tooltip to filename so that user can see what sample this
// sample-tco contains
toolTip::add( this, ( m_sampleBuffer.audioFile() != "" ) ?
m_sampleBuffer.audioFile() :
tr( "double-click to select sample" ) );
}
void sampleTCO::updateLength( int )
{
changeLength( getSampleLength() );
}
void sampleTCO::paintEvent( QPaintEvent * )
{
#ifdef QT4
QPainter p( this );
p.fillRect( rect(), QColor( 0, 64, 255 ) );
#else
// create pixmap for whole widget
QPixmap pm( rect().size() );
pm.fill( QColor( 0, 64, 255 ) );
// and a painter for it
QPainter p( &pm );
#endif
if( getTrack()->muted() )
{
p.setPen( QColor( 160, 160, 160 ) );
}
else
{
p.setPen( QColor( 0, 0, 128 ) );
}
p.drawRect( 0, 0, width(), height() );
m_sampleBuffer.drawWaves( p, QRect( 1, 1, tMax( tMin( width() - 3,
static_cast<int>( getSampleLength() *
pixelsPerTact() / 64 ) ), 1 ),
height() - 4 ) );
#ifndef QT4
bitBlt( this, rect().topLeft(), &pm );
#endif
}
void sampleTCO::mouseDoubleClickEvent( QMouseEvent * )
{
QString af = m_sampleBuffer.openAudioFile();
if( af != "" && af != m_sampleBuffer.audioFile() )
{
setSampleFile( af );
songEditor::inst()->setModified();
}
}
midiTime sampleTCO::getSampleLength( void ) const
{
return( static_cast<Sint32>( m_sampleBuffer.frames() /
songEditor::inst()->framesPerTact() *
64 ) );
}
void FASTCALL sampleTCO::saveSettings( QDomDocument & _doc, QDomElement & _parent )
{
QDomElement sampletco_de = _doc.createElement( nodeName() );
if( _parent.nodeName() == "clipboard" )
{
sampletco_de.setAttribute( "pos", QString::number( -1 ) );
}
else
{
sampletco_de.setAttribute( "pos", QString::number(
startPosition() ) );
}
sampletco_de.setAttribute( "len", QString::number( length() ) );
sampletco_de.setAttribute( "src", sampleFile() );
// TODO: start- and end-frame
_parent.appendChild( sampletco_de );
}
void FASTCALL sampleTCO::loadSettings( const QDomElement & _this )
{
if( _this.attribute( "pos" ).toInt() >= 0 )
{
movePosition( _this.attribute( "pos" ).toInt() );
}
changeLength( _this.attribute( "len" ).toInt() );
setSampleFile( _this.attribute( "src" ) );
}
/*
sampleTCOSettingsDialog::sampleTCOSettingsDialog( sampleTCO * _stco ) :
QDialog(),
m_sampleTCO( _stco )
{
resize( 400, 300 );
QVBoxWidget * vb0 = new QVBoxWidget( this );
vb0->resize( 400, 300 );
QHBoxWidget * hb00 = new QHBoxWidget( vb0 );
m_fileLbl = new QLabel( _stco->sampleFile(), hb00 );
QPushButton * open_file_btn = new QPushButton(
embed::getIconPixmap( "fileopen" ), "", hb00 );
connect( open_file_btn, SIGNAL( clicked() ), this,
SLOT( openSampleFile() ) );
QHBoxWidget * hb01 = new QHBoxWidget( vb0 );
QPushButton * ok_btn = new QPushButton( tr( "OK" ), hb01 );
ok_btn->setGeometry( 10, 0, 100, 32 );
connect( ok_btn, SIGNAL( clicked() ), this, SLOT( accept() ) );
QPushButton * cancel_btn = new QPushButton( tr( "Cancel" ), hb01 );
cancel_btn->setGeometry( 120, 0, 100, 32 );
connect( ok_btn, SIGNAL( clicked() ), this, SLOT( reject() ) );
}
sampleTCOSettingsDialog::~sampleTCOSettingsDialog()
{
}
void sampleTCOSettingsDialog::openSampleFile( void )
{
QString af = m_sampleTCO->m_sampleBuffer.openAudioFile();
if( af != "" )
{
setSampleFile( af );
}
}
void sampleTCOSettingsDialog::setSampleFile( const QString & _f )
{
m_fileLbl->setText( _f );
m_sampleTCO->setSampleFile( _f );
songEditor::inst()->setModified();
}
*/
sampleTrack::sampleTrack( trackContainer * _tc )
: track( _tc )
{
getTrackWidget()->setFixedHeight( 32 );
m_trackLabel = new nameLabel( tr( "Sample track" ),
getTrackSettingsWidget(),
embed::getIconPixmap(
"sample_track" ) );
m_trackLabel->setGeometry( 1, 1, DEFAULT_SETTINGS_WIDGET_WIDTH-2, 29 );
m_trackLabel->show();
_tc->updateAfterTrackAdd();
}
sampleTrack::~sampleTrack()
{
}
track::trackTypes sampleTrack::trackType( void ) const
{
return( SAMPLE_TRACK );
}
bool FASTCALL sampleTrack::play( const midiTime & _start, Uint32 _start_frame,
Uint32 _frames, Uint32 _frame_base,
Sint16 /*_tco_num*/ )
{
vlist<trackContentObject *> tcos;
getTCOsInRange( tcos, _start, _start+static_cast<Sint32>( _frames * 64 /
songEditor::inst()->framesPerTact() ) );
if ( tcos.size() == 0 )
{
return( FALSE );
}
sampleFrame * buf = bufferAllocator::alloc<sampleFrame>( _frames );
volumeVector v = { 1.0f, 1.0f
#ifndef DISABLE_SURROUND
, 1.0f, 1.0f
#endif
} ;
float fpt = songEditor::inst()->framesPerTact();
for( vlist<trackContentObject *>::iterator it = tcos.begin();
it != tcos.end(); ++it )
{
sampleTCO * st = dynamic_cast<sampleTCO *>( *it );
if( st != NULL )
{
st->play( buf, _start_frame +
static_cast<Uint32>( _start.getTact() *
fpt ),
_frames );
mixer::inst()->addBuffer( buf, _frames, _frame_base +
static_cast<Uint32>(
st->startPosition().getTact64th() *
fpt / 64.0f ), v );
}
}
bufferAllocator::free( buf );
return( TRUE );
}
trackContentObject * sampleTrack::createTCO( const midiTime & )
{
return( new sampleTCO( this ) );
}
void sampleTrack::saveTrackSpecificSettings( QDomDocument & _doc,
QDomElement & _parent )
{
QDomElement st_de = _doc.createElement( nodeName() );
st_de.setAttribute( "name", m_trackLabel->text() );
_parent.appendChild( st_de );
}
void sampleTrack::loadTrackSpecificSettings( const QDomElement & _this )
{
m_trackLabel->setText( _this.attribute( "name" ) );
}
#include "sample_track.moc"

234
src/widgets/group_box.cpp Normal file
View File

@@ -0,0 +1,234 @@
/*
* group_box.cpp - groupbox for LMMS
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <QPainter>
#include <QTimer>
#include <QMouseEvent>
#else
#include <qpainter.h>
#include <qtimer.h>
#include <qobjectlist.h>
#define setChecked setOn
#endif
#include <math.h>
#include "group_box.h"
#include "embed.h"
#include "spc_bg_hndl_widget.h"
#include "templates.h"
QPixmap * groupBox::s_ledBg = NULL;
groupBox::groupBox( const QString & _caption, QWidget * _parent ) :
QWidget( _parent ),
m_caption( _caption ),
m_origHeight( height() ),
m_animating( FALSE )
{
if( s_ledBg == NULL )
{
s_ledBg = new QPixmap( embed::getIconPixmap(
"groupbox_led_bg" ) );
}
updatePixmap();
m_led = new pixmapButton( this );
m_led->move( 2, 3 );
m_led->setActiveGraphic( embed::getIconPixmap( "led_green" ) );
m_led->setInactiveGraphic( embed::getIconPixmap( "led_off" ) );
m_led->setBgGraphic( specialBgHandlingWidget::getBackground( m_led ) );
connect( m_led, SIGNAL( toggled( bool ) ),
this, SLOT( setState( bool ) ) );
}
groupBox::~groupBox()
{
}
void groupBox::resizeEvent( QResizeEvent * )
{
updatePixmap();
if( m_animating == FALSE )
{
m_origHeight = height();
}
}
void groupBox::mousePressEvent( QMouseEvent * _me )
{
if( _me->y() > 1 && _me->y() < 13 )
{
setState( !isActive(), TRUE );
}
}
void groupBox::setState( bool _on, bool _anim )
{
m_led->setChecked( _on );
if( ( _anim == TRUE || ( _on == TRUE && height() < m_origHeight ) ) &&
m_animating == FALSE )
{
m_animating = TRUE;
animate();
}
}
void groupBox::animate( void )
{
float state = (float)( m_origHeight - height() ) /
(float)( m_origHeight - 19 );
int dy = static_cast<int>( 3 - 2 * cosf( state * 2 * M_PI ) );
if( isActive() && height() < m_origHeight )
{
}
else if( !isActive() && height() > 19 )
{
dy = -dy;
}
else
{
m_animating = FALSE;
return;
}
resize( width(), height() + dy );
QTimer::singleShot( 10, this, SLOT( animate() ) );
#ifdef QT4
QObjectList ch = parent()->children();
#else
QObjectList ch = *( parent()->children() );
#endif
for( csize i = 0; i < ch.count(); ++i )
{
QWidget * w = dynamic_cast<QWidget *>( ch.at( i ) );
if( w == NULL || w->y() < y() + height() )
{
continue;
}
w->move( w->x(), w->y() + dy );
}
#ifdef QT4
ch = children();
#else
ch = *children();
#endif
for( csize i = 0; i < ch.count(); ++i )
{
QWidget * w = dynamic_cast<QWidget *>( ch.at( i ) );
if( w == NULL || w == m_led )
{
continue;
}
w->move( w->x(), w->y() + dy );
if( w->y() < 14)
{
w->hide();
}
else if( w->isHidden() == TRUE )
{
w->show();
}
}
}
void groupBox::updatePixmap( void )
{
QPixmap pm( size() );
pm.fill( QColor( 96, 96, 96 ) );
QPainter p( &pm );
// outer rect
p.setPen( QColor( 64, 64, 64 ) );
p.drawRect( 0, 0, width(), height() );
// brighter line at bottom/right
p.setPen( QColor( 160, 160, 160 ) );
p.drawLine( width() - 1, 0, width() - 1, height() - 1 );
p.drawLine( 0, height() - 1, width() - 1, height() - 1 );
// draw our led-pixmap
p.drawPixmap( 2, 2, *s_ledBg );
// draw groupbox-titlebar
p.fillRect( 2, 2, width() - 4, 9, QColor( 30, 45, 60 ) );
// draw line below titlebar
p.setPen( QColor( 0, 0, 0 ) );
p.drawLine( 2 + s_ledBg->width(), 11, width() - 3, 11 );
// black inner rect
p.drawRect( 1, 1, width() - 2, height() - 2 );
p.setPen( QColor( 255, 255, 255 ) );
p.setFont( pointSize<7>( font() ) );
p.drawText( 22, 10, m_caption );
#ifdef QT4
QPalette pal = palette();
pal.setBrush( backgroundRole(), QBrush( pm ) );
pal.setColor( QPalette::Background, QColor( 96, 96, 96 ) );
setPalette( pal );
#else
setPaletteBackgroundColor( QColor( 96, 96, 96 ) );
setErasePixmap( pm );
#endif
}
#undef setChecked
#include "group_box.moc"

1148
src/widgets/kmultitabbar.cpp Normal file

File diff suppressed because it is too large Load Diff

812
src/widgets/knob.cpp Normal file
View File

@@ -0,0 +1,812 @@
/*
* knob.cpp - powerful knob-widget
*
* This file is based on the knob-widget of the Qwt Widget Library from
* Josef Wilgen
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <QPainter>
#include <QPalette>
#include <QBitmap>
#include <QLabel>
#include <QStatusBar>
#include <QMouseEvent>
#include <QMenu>
#include <QStatusBar>
#include <QFontMetrics>
#include <QApplication>
#else
#include <qpainter.h>
#include <qpalette.h>
#include <qbitmap.h>
#include <qlabel.h>
#include <qpopupmenu.h>
#include <qstatusbar.h>
#include <qfontmetrics.h>
#include <qapplication.h>
#define addSeparator insertSeparator
#endif
#ifndef __USE_XOPEN
#define __USE_XOPEN
#endif
#include <math.h>
#include "knob.h"
#include "song_editor.h"
#include "midi_device.h"
#include "embed.h"
#include "spc_bg_hndl_widget.h"
//#include "tooltip.h"
#include "config_mgr.h"
#include "text_float.h"
#include "mixer.h"
const int WHEEL_DELTA = 120;
static double MinRelStep = 1.0e-10;
static double DefaultRelStep = 1.0e-2;
static double MinEps = 1.0e-10;
float knob::s_copiedValue = 0.0f;
textFloat * knob::s_textFloat = NULL;
knob::knob( int _knob_num, QWidget * _parent, const QString & _name ) :
QWidget( _parent
#ifndef QT4
, _name.ascii()
#endif
),
m_scrollMode( ScrNone ),
m_mouseOffset( 0.0f ),
m_tracking( TRUE ),
m_angle( 0.0f ),
m_oldAngle( 0.0f ),
m_nTurns( 0.0f ),
m_knobNum( _knob_num ),
m_hintTextBeforeValue( "" ),
m_hintTextAfterValue( "" ),
m_label( "" ),
m_minValue( 0.0f ),
m_maxValue( 100.0f ),
m_value( 0.0f ),
m_exactValue( 0.0f ),
m_exactPrevValue( 0.0f ),
m_prevValue( 0.0f ),
m_initValue( 0.0f )
{
if( s_textFloat == NULL )
{
s_textFloat = new textFloat( this );
}
#ifdef QT4
setAccessibleName( _name );
#endif
setRange( 0.0, 100.0, 1.0 );
#ifdef QT4
m_knobPixmap = new QPixmap( embed::getIconPixmap( QString( "knob0" +
QString::number( m_knobNum + 1 ) ).toAscii().constData() ) );
#else
m_knobPixmap = new QPixmap( embed::getIconPixmap( "knob0" +
QString::number( m_knobNum + 1 ) ) );
#endif
#ifdef QT4
// setAttribute( Qt::WA_NoBackground );
#else
setBackgroundMode( Qt::NoBackground );
#endif
m_knobWidth = m_knobPixmap->width();
setFixedSize( m_knobPixmap->width(), m_knobPixmap->height() );
setTotalAngle( 270.0f );
recalcAngle();
}
// Destructor
knob::~knob()
{
// make sure pointer to this knob isn't used anymore in active
// midi-device-class
if( mixer::inst()->getMIDIDevice()->pitchBendKnob() == this )
{
mixer::inst()->getMIDIDevice()->setPitchBendKnob( NULL );
}
}
void knob::setHintText( const QString & _txt_before,
const QString & _txt_after )
{
m_hintTextBeforeValue = _txt_before;
m_hintTextAfterValue = _txt_after;
/* toolTip::add( this, m_hintTextBeforeValue + QString::number( value() ) +
m_hintTextAfterValue );*/
}
void knob::setLabel( const QString & _txt )
{
m_label = _txt;
setFixedSize( tMax<int>( m_knobPixmap->width(),
QFontMetrics( pointSize<6>( font()
) ).width( m_label ) ),
m_knobPixmap->height() + 10 );
update();
}
void knob::setTotalAngle( float _angle )
{
if( _angle < 10.0 )
{
m_totalAngle = 10.0;
}
else
{
m_totalAngle = _angle;
}
layoutKnob();
}
void knob::drawKnob( QPainter * _p )
{
_p->drawPixmap( 0, 0, specialBgHandlingWidget::getBackground( this ) );
const float radius = m_knobPixmap->width() / 2 - 1;
const float xm = m_knobPixmap->width() / 2;//radius + 1;
const float ym = m_knobPixmap->height() / 2;//radius+1;
const float rarc = m_angle * M_PI / 180.0;
const float ca = cos( rarc );
const float sa = -sin( rarc );
_p->drawPixmap( static_cast<int>( xm - m_knobPixmap->width() / 2 ), 0,
*m_knobPixmap );
_p->setPen( QPen( QColor( 200, 0, 0 ), 2 ) );
switch( m_knobNum )
{
case knobSmall_17:
{
_p->drawLine( (int)( xm-sa ), (int)( ym-ca ),
(int)( xm - sa*radius ),
(int)( ym - ca*radius ) );
break;
}
case knobBright_26:
{
_p->drawLine( (int)( xm-sa ), (int)( ym-ca ),
(int)( xm - sa*( radius-5 ) ),
(int)( ym - ca*( radius-5 ) ) );
break;
}
case knobDark_28:
{
const float rb = tMax<float>( ( radius - 10 ) / 3.0,
0.0 );
const float re = tMax<float>( ( radius - 4 ), 0.0 );
_p->drawLine( (int)( xm-sa*rb ) + 1,
(int)( ym - ca*rb ) + 1,
(int)( xm - sa*re ) + 1,
(int)( ym - ca*re ) + 1 );
break;
}
}
}
void knob::valueChange( void )
{
recalcAngle();
update();
/* toolTip::add( this, m_hintTextBeforeValue + QString::number( value() ) +
m_hintTextAfterValue );*/
if( m_tracking )
{
emit valueChanged( value() );
}
}
float knob::getValue( const QPoint & _p )
{
if( configManager::inst()->value( "knobs", "classicalusability"
).toInt() )
{
const float dx = float( ( rect().x() + rect().width() / 2 ) -
_p.x() );
const float dy = float( ( rect().y() + rect().height() / 2 ) -
_p.y() );
const float arc = atan2( -dx, dy ) * 180.0 / M_PI;
float new_value = 0.5 * ( m_minValue + m_maxValue ) +
( arc + m_nTurns * 360.0 ) *
( m_maxValue - m_minValue ) /
m_totalAngle;
const float oneTurn = tAbs<float>( m_maxValue - m_minValue ) *
360.0 / m_totalAngle;
const float eqValue = value() + m_mouseOffset;
if( tAbs<float>( new_value - eqValue ) > 0.5 * oneTurn )
{
if( new_value < eqValue )
{
new_value += oneTurn;
}
else
{
new_value -= oneTurn;
}
}
return( new_value );
}
return( ( _p.y() - m_origMousePos.y() ) * m_step );
}
void knob::getScrollMode( const QPoint &, int & _scroll_mode, int & _direction )
{
_scroll_mode = ScrMouse;
_direction = 0;
}
void knob::rangeChange()
{
layoutKnob();
recalcAngle();
}
void knob::resizeEvent( QResizeEvent * )
{
layoutKnob( FALSE );
}
// Recalculate the slider's geometry and layout based on
// the current rect and fonts.
void knob::layoutKnob( bool _update_geometry )
{
if( _update_geometry )
{
updateGeometry();
update();
}
}
void knob::paintEvent( QPaintEvent * _me )
{
// Use double-buffering
QRect ur = _me->rect();
#ifndef QT4
if( ur.isValid() )
{
#endif
#ifdef QT4
QPainter p( this );
#else
QPixmap pix( ur.size() );
pix.fill( this, ur.topLeft() );
QPainter p( &pix, this );
#endif
p.translate( -ur.x(), -ur.y() );
drawKnob( &p );
if( m_label != "" )
{
p.setFont( pointSize<6>( p.font() ) );
p.setPen( QColor( 255, 255, 255 ) );
p.drawText( width() / 2 -
QFontMetrics( p.font() ).width( m_label ) / 2,
height() - 2, m_label );
}
#ifndef QT4
p.end();
bitBlt( this, ur.topLeft(), &pix );
}
#endif
}
void knob::recalcAngle( void )
{
m_oldAngle = m_angle;
//
// calculate the angle corresponding to the value
//
if( m_maxValue == m_minValue )
{
m_angle = 0;
m_nTurns = 0;
}
else
{
m_angle = ( value() - 0.5 * ( m_minValue + m_maxValue ) ) /
( m_maxValue - m_minValue ) * m_totalAngle;
m_nTurns = floor( ( m_angle + 180.0 ) / 360.0 );
m_angle = m_angle - m_nTurns * 360.0;
}
}
//! Mouse press event handler
void knob::mousePressEvent( QMouseEvent * _me )
{
const QPoint & p = _me->pos();
m_origMousePos = p;
getScrollMode( p, m_scrollMode, m_direction );
switch( m_scrollMode )
{
case ScrMouse:
m_mouseOffset = getValue( p ) - value();
emit sliderPressed();
break;
default:
m_mouseOffset = 0;
m_direction = 0;
break;
}
if( _me->button() == Qt::LeftButton )
{
if( !configManager::inst()->value( "knobs", "classicalusability"
).toInt() )
{
QApplication::setOverrideCursor( Qt::BlankCursor );
}
s_textFloat->reparent( this );
s_textFloat->setText( m_hintTextBeforeValue +
QString::number( value() ) +
m_hintTextAfterValue );
s_textFloat->move( mapTo( topLevelWidget(), QPoint( 0, 0 ) ) +
QPoint( m_knobPixmap->width() + 2, 0 ) );
s_textFloat->show();
}
}
//! Emits a valueChanged() signal if necessary
void knob::buttonReleased( void )
{
if( ( !m_tracking ) || ( value() != m_prevValue ) )
{
emit valueChanged( value() );
}
}
//! Mouse Release Event handler
void knob::mouseReleaseEvent( QMouseEvent * _me )
{
m_scrollMode = ScrNone;
buttonReleased();
switch( m_scrollMode )
{
case ScrMouse:
setPosition( _me->pos() );
m_direction = 0;
m_mouseOffset = 0;
emit sliderReleased ();
break;
case ScrDirect:
setPosition( _me->pos() );
m_direction = 0;
m_mouseOffset = 0;
break;
default:
break;
}
if( !configManager::inst()->value( "knobs", "classicalusability"
).toInt() )
{
QApplication::restoreOverrideCursor();
}
s_textFloat->hide();
}
void knob::setPosition( const QPoint & _p )
{
if( configManager::inst()->value( "knobs", "classicalusability"
).toInt() )
{
setNewValue( getValue( _p ) - m_mouseOffset, 1 );
}
else
{
setNewValue( m_value - getValue( _p ), 1 );
}
}
void knob::setTracking( bool _enable )
{
m_tracking = _enable;
}
//! Mouse Move Event handler
void knob::mouseMoveEvent( QMouseEvent * _me )
{
if( m_scrollMode == ScrMouse )
{
setPosition( _me->pos() );
if( value() != m_prevValue )
{
emit sliderMoved( value() );
}
if( !configManager::inst()->value( "knobs", "classicalusability"
).toInt() )
{
QCursor::setPos( mapToGlobal( m_origMousePos ) );
}
}
songEditor::inst()->setModified();
s_textFloat->setText( m_hintTextBeforeValue +
QString::number( value() ) +
m_hintTextAfterValue );
}
//! Qt wheel event
void knob::wheelEvent( QWheelEvent * _me )
{
_me->accept();
const int inc = _me->delta() / WHEEL_DELTA;
incPages( inc );
songEditor::inst()->setModified();
s_textFloat->reparent( this );
s_textFloat->setText( m_hintTextBeforeValue +
QString::number( value() ) +
m_hintTextAfterValue );
s_textFloat->move( mapTo( topLevelWidget(), QPoint( 0, 0 ) ) +
QPoint( m_knobPixmap->width() + 2, 0 ) );
s_textFloat->setVisibilityTimeOut( 1000 );
/* toolTip::add( this, m_hintTextBeforeValue+QString::number( value() ) +
m_hintTextAfterValue );*/
if( value() != m_prevValue )
{
emit sliderMoved( value() );
}
}
void knob::setValue( float _val, bool _is_init_value )
{
if( _is_init_value )
{
m_initValue = _val;
}
setNewValue( _val, 0 );
}
void knob::fitValue( float _val )
{
setNewValue( _val, 1 );
}
void knob::incValue( int _steps )
{
setNewValue( m_value + float( _steps ) * m_step, 1 );
}
void knob::setRange( float _vmin, float _vmax, float _vstep, int _page_size )
{
int rchg = ( ( m_maxValue != _vmax ) || ( m_minValue != _vmin ) );
if( rchg )
{
m_minValue = _vmin;
m_maxValue = _vmax;
}
//
// look if the step width has an acceptable
// value or otherwise change it.
//
setStep( _vstep );
//
// limit page size
//
/* m_pageSize = tLimit( pageSize, 0, int( tAbs<float>( ( m_maxValue -
m_minValue ) / m_step ) ) ); */
m_pageSize = tMax<float>( ( m_maxValue - m_minValue ) / 40.0f, _vstep );
//
// If the value lies out of the range, it
// will be changed. Note that it will not be adjusted to
// the new step width.
setNewValue( m_value, 0 );
// call notifier after the step width has been
// adjusted.
if( rchg )
{
rangeChange();
}
}
void knob::setNewValue( float _x, int _align )
{
m_prevValue = m_value;
m_value = tLimit( _x, m_minValue, m_maxValue );
m_exactPrevValue = m_exactValue;
m_exactValue = m_value;
// align to grid
if( _align )
{
if( m_step != 0.0 )
{
m_value = floorf( m_value / m_step ) * m_step;
}
else
{
m_value = m_minValue;
}
// correct rounding error at the border
if( tAbs<float>( m_value - m_maxValue ) < MinEps *
tAbs<float>( m_step ) )
{
m_value = m_maxValue;
}
// correct rounding error if value = 0
if( tAbs<float>( m_value ) < MinEps * tAbs<float>( m_step ) )
{
m_value = 0.0;
}
}
if( m_prevValue != m_value )
{
valueChange();
}
}
void knob::setStep( float _vstep )
{
float intv = m_maxValue - m_minValue;
float newStep;
if( _vstep == 0.0 )
{
newStep = intv * DefaultRelStep;
}
else
{
if( ( intv > 0 ) && ( _vstep < 0 ) || ( intv < 0 ) &&
( _vstep > 0 ) )
{
newStep = -_vstep;
}
else
{
newStep = _vstep;
}
if( tAbs<float>( newStep ) <
tAbs<float>( MinRelStep * intv ) )
{
newStep = MinRelStep * intv;
}
}
if( newStep != m_step )
{
m_step = newStep;
}
}
void knob::contextMenuEvent( QContextMenuEvent * )
{
QMenu contextMenu( this );
#ifdef QT4
contextMenu.setTitle( accessibleName() );
#else
QLabel * caption = new QLabel( "<font color=white><b>" +
QString( accessibleName() ) + "</b></font>", this );
caption->setPaletteBackgroundColor( QColor( 0, 0, 192 ) );
caption->setAlignment( Qt::AlignCenter );
contextMenu.addAction( caption );
#endif
contextMenu.addAction( embed::getIconPixmap( "reload" ),
tr( "&Reset (%1%2)" ).arg( m_initValue ).arg(
m_hintTextAfterValue ),
this, SLOT( reset() ) );
contextMenu.addSeparator();
contextMenu.addAction( embed::getIconPixmap( "edit_copy" ),
tr( "&Copy value (%1%2)" ).arg( value() ).arg(
m_hintTextAfterValue ),
this, SLOT( copyValue() ) );
contextMenu.addAction( embed::getIconPixmap( "edit_paste" ),
tr( "&Paste value (%1%2)"
).arg( s_copiedValue ).arg(
m_hintTextAfterValue ),
this, SLOT( pasteValue() ) );
contextMenu.addSeparator();
contextMenu.addAction( tr( "Connect to MIDI-device" ), this,
SLOT( connectToMidiDevice() ) );
contextMenu.addSeparator();
contextMenu.addAction( embed::getIconPixmap( "help" ), tr( "&Help" ),
this, SLOT( displayHelp() ) );
contextMenu.exec( QCursor::pos() );
}
void knob::reset( void )
{
setValue( m_initValue );
}
void knob::copyValue( void )
{
s_copiedValue = value();
}
void knob::pasteValue( void )
{
setValue( s_copiedValue );
}
void knob::connectToMidiDevice( void )
{
mixer::inst()->getMIDIDevice()->setPitchBendKnob( this );
}
void knob::displayHelp( void )
{
#ifdef QT4
QWhatsThis::showText( mapToGlobal( rect().bottomRight() ),
whatsThis() );
#else
QWhatsThis::display( QWhatsThis::textFor( this ), mapToGlobal(
rect().bottomRight() ) );
#endif
}
#include "knob.moc"
#ifndef QT4
#undef addSeparator
#endif

176
src/widgets/lcd_spinbox.cpp Normal file
View File

@@ -0,0 +1,176 @@
/*
* lcd_spinbox.cpp - class lcdSpinBox, an improved QLCDNumber
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <QApplication>
#include <QMouseEvent>
#include <QCursor>
#include <QLabel>
#else
#include <qapplication.h>
#include <qcursor.h>
#include <qlabel.h>
#endif
#include "lcd_spinbox.h"
#include "templates.h"
lcdSpinBox::lcdSpinBox( int _min, int _max, int _num_digits,
QWidget * _parent ) :
QWidget( _parent ),
m_minValue( _min ),
m_maxValue( _max ),
m_step( 1 ),
m_label( NULL ),
m_origMousePos()
{
m_number = new QLCDNumber( _num_digits, this );
m_number->setFrameShape( QFrame::Panel );
m_number->setFrameShadow( QFrame::Sunken );
m_number->setSegmentStyle( QLCDNumber::Flat );
#ifdef QT4
QPalette pal = m_number->palette();
pal.setColor( QPalette::Background, QColor( 32, 32, 32 ) );
pal.setColor( QPalette::Foreground, QColor( 255, 180, 0 ) );
m_number->setPalette( pal );
#else
m_number->setPaletteBackgroundColor( QColor( 32, 32, 32 ) );
m_number->setPaletteForegroundColor( QColor( 255, 180, 0 ) );
#endif
// value is automatically limited to given range
setValue( 0 );
m_number->setFixedSize( m_number->sizeHint() * 0.9 );
setFixedSize( m_number->size() );
}
lcdSpinBox::~lcdSpinBox()
{
}
void lcdSpinBox::setStep( int _step )
{
m_step = tMax( _step, 1 );
}
void lcdSpinBox::setValue( int _value )
{
_value = ( ( tLimit( _value, m_minValue, m_maxValue ) - m_minValue ) /
m_step ) * m_step + m_minValue;
QString s = QString::number( _value );
while( (int) s.length() < m_number->numDigits() )
{
s = "0" + s;
}
m_number->display( s );
}
void lcdSpinBox::setLabel( const QString & _txt )
{
if( m_label == NULL )
{
m_label = new QLabel( _txt, this );
m_label->setFont( pointSize<6>( m_label->font() ) );
m_label->setGeometry( 0, y() + height(),
QFontMetrics( m_label->font() ).width( _txt ), 7 );
setFixedSize( tMax( width(), m_label->width() ),
height() + m_label->height() );
}
else
{
m_label->setText( _txt );
}
}
void lcdSpinBox::mousePressEvent( QMouseEvent * _me )
{
if( _me->button() == Qt::LeftButton && _me->y() < m_number->height() )
{
m_origMousePos = _me->globalPos();
QApplication::setOverrideCursor( Qt::BlankCursor );
}
}
void lcdSpinBox::mouseMoveEvent( QMouseEvent * _me )
{
if( _me->modifiers() == Qt::LeftButton )
{
int dy = _me->globalY() - m_origMousePos.y();
if( dy > 1 || dy < -1 )
{
setValue( value() - dy / 2 * m_step );
emit valueChanged( value() );
QCursor::setPos( m_origMousePos );
}
}
}
void lcdSpinBox::mouseReleaseEvent( QMouseEvent * _me )
{
QCursor::setPos( m_origMousePos );
QApplication::restoreOverrideCursor();
}
void lcdSpinBox::wheelEvent( QWheelEvent * _we )
{
setValue( value() + _we->delta() / 120 * m_step );
}
#include "lcd_spinbox.moc"

View File

@@ -0,0 +1,130 @@
/*
* led_checkbox.cpp - class ledCheckBox, an improved QCheckBox
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <QPaintEvent>
#include <QFontMetrics>
#include <QPainter>
#else
#include <qfontmetrics.h>
#include <qpainter.h>
#define setChecked setOn
#define isChecked isOn
#endif
#include "led_checkbox.h"
#include "embed.h"
#include "templates.h"
#include "spc_bg_hndl_widget.h"
static const QString names[ledCheckBox::TOTAL_COLORS] =
{
"led_yellow", "led_green"
} ;
ledCheckBox::ledCheckBox( const QString & _text, QWidget * _parent,
ledColors _color ) :
QCheckBox( _text, _parent )
{
if( _color >= TOTAL_COLORS || _color < YELLOW )
{
_color = YELLOW;
}
m_ledOnPixmap = new QPixmap( embed::getIconPixmap( names[_color]
#ifdef QT4
.toAscii().constData()
#endif
) );
m_ledOffPixmap = new QPixmap( embed::getIconPixmap( "led_off" ) );
#ifndef QT4
setBackgroundMode( Qt::NoBackground );
#endif
setFont( pointSize<7>( font() ) );
setFixedSize( m_ledOffPixmap->width() + 6 +
QFontMetrics( font() ).width( text() ),
m_ledOffPixmap->height() );
}
ledCheckBox::~ledCheckBox()
{
delete m_ledOnPixmap;
delete m_ledOffPixmap;
}
void ledCheckBox::paintEvent( QPaintEvent * )
{
#ifdef QT4
QPainter p( this );
#else
QPixmap draw_pm( rect().size() );
draw_pm.fill( this, rect().topLeft() );
QPainter p( &draw_pm, this );
#endif
p.drawPixmap( 0, 0, specialBgHandlingWidget::getBackground( this ) );
#ifdef QT4
if( checkState() == Qt::Checked )
#else
if( state() == On )
#endif
{
p.drawPixmap( 0, 0, *m_ledOnPixmap );
}
else
{
p.drawPixmap( 0, 0, *m_ledOffPixmap );
}
p.drawText( m_ledOffPixmap->width() + 2, 10, text() );
#ifndef QT4
// and blit all the drawn stuff on the screen...
bitBlt( this, rect().topLeft(), &draw_pm );
#endif
}
#undef setChecked
#undef isChecked

View File

@@ -0,0 +1,143 @@
/*
* nstate_button.cpp - implementation of n-state-button
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <QPainter>
#include <QMouseEvent>
#else
#include <qpainter.h>
#endif
#include "nstate_button.h"
#include "embed.h"
#include "tooltip.h"
nStateButton::nStateButton( QWidget * _parent ) :
QWidget( _parent ),
m_generalToolTip( "" ),
m_curState( -1 )
{
#ifndef QT4
setBackgroundMode( Qt::NoBackground );
#endif
}
nStateButton::~nStateButton()
{
while( m_states.size() )
{
delete m_states.first().first;
m_states.erase( m_states.begin() );
}
}
void nStateButton::addState( const QPixmap & _pm, const QString & _tooltip )
{
m_states.push_back( qMakePair( new QPixmap( _pm ), _tooltip ) );
// first inserted pixmap?
if( m_states.size() == 1 )
{
// then resize ourself
resize( _pm.width(), _pm.height() );
// and set state to first pixmap
changeState( 0 );
}
}
void nStateButton::changeState( int _n )
{
if( _n >= 0 && _n < (int) m_states.size() )
{
m_curState = _n;
const QString & _tooltip =
( m_states[m_curState].second != "" ) ?
m_states[m_curState].second :
m_generalToolTip;
toolTip::add( this, _tooltip );
emit stateChanged( m_curState );
update();
}
}
void nStateButton::paintEvent( QPaintEvent * )
{
#ifdef QT4
QPainter p( this );
#else
QPixmap draw_pm( rect().size() );
draw_pm.fill( this, rect().topLeft() );
QPainter p( &draw_pm, this );
#endif
if( m_curState >= 0 && m_curState < (int) m_states.size() )
{
p.drawPixmap( 0, 0, *m_states[m_curState].first );
}
#ifndef QT4
// and blit all the drawn stuff on the screen...
bitBlt( this, rect().topLeft(), &draw_pm );
#endif
}
void nStateButton::mousePressEvent( QMouseEvent * _me )
{
if( _me->button() == Qt::LeftButton && m_states.size() )
{
changeState( ( ++m_curState ) % m_states.size() );
}
}
#include "nstate_button.moc"

View File

@@ -0,0 +1,175 @@
/*
* pixmap_button.cpp - implementation of pixmap-button (often used as "themed"
* checkboxes/radiobuttons etc)
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <QPainter>
#include <QMouseEvent>
#else
#include <qpainter.h>
#endif
#include "pixmap_button.h"
#include "embed.h"
pixmapButton::pixmapButton( QWidget * _parent ) :
QPushButton( _parent ),
m_activePixmap( NULL ),
m_inactivePixmap( NULL ),
m_bgPixmap( NULL )
{
setActiveGraphic( embed::getIconPixmap( "led_yellow" ) );
setInactiveGraphic( embed::getIconPixmap( "led_off" ), FALSE );
#ifndef QT4
setBackgroundMode( Qt::NoBackground );
#endif
setCheckable( TRUE );
}
pixmapButton::~pixmapButton()
{
delete m_activePixmap;
delete m_inactivePixmap;
delete m_bgPixmap;
}
void pixmapButton::paintEvent( QPaintEvent * )
{
#ifdef QT4
QPainter p( this );
#else
QPixmap draw_pm( rect().size() );
draw_pm.fill( this, rect().topLeft() );
QPainter p( &draw_pm, this );
#endif
if( m_bgPixmap != NULL )
{
p.drawPixmap( 0, 0, *m_bgPixmap );
}
#ifdef QT4
if( isChecked() )
#else
if( isOn() )
#endif
{
if( m_activePixmap != NULL )
{
p.drawPixmap( 0, 0, *m_activePixmap );
}
}
else
{
if( m_inactivePixmap != NULL )
{
p.drawPixmap( 0, 0, *m_inactivePixmap );
}
}
#ifndef QT4
// and blit all the drawn stuff on the screen...
bitBlt( this, rect().topLeft(), &draw_pm );
#endif
}
void pixmapButton::mousePressEvent( QMouseEvent * _me)
{
if( _me->button() == Qt::RightButton )
{
emit( clickedRight() );
}
else
{
QPushButton::mousePressEvent( _me );
}
}
void pixmapButton::mouseDoubleClickEvent( QMouseEvent * )
{
emit doubleClicked();
}
void pixmapButton::setActiveGraphic( const QPixmap & _pm )
{
delete m_activePixmap;
m_activePixmap = new QPixmap( _pm );
resize( m_activePixmap->width(), m_activePixmap->height() );
}
void pixmapButton::setInactiveGraphic( const QPixmap & _pm, bool _update )
{
delete m_inactivePixmap;
m_inactivePixmap = new QPixmap( _pm );
if( _update )
{
update();
}
}
void pixmapButton::setBgGraphic( const QPixmap & _pm )
{
delete m_bgPixmap;
m_bgPixmap = new QPixmap( _pm );
}
#include "pixmap_button.moc"

View File

@@ -0,0 +1,571 @@
/*
* project_notes.h - header for project-notes-editor
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <Qt/QtXml>
#include <QApplication>
#include <QTextEdit>
#include <QLineEdit>
#include <QAction>
#include <QToolBar>
#include <QFontDatabase>
#include <QComboBox>
#include <QColorDialog>
#else
#include <qdom.h>
#include <qapplication.h>
#include <qtextedit.h>
#include <qaction.h>
#include <qlineedit.h>
#include <qtoolbar.h>
#include <qfontdatabase.h>
#include <qcombobox.h>
#include <qcolordialog.h>
#define isChecked isOn
#define setChecked setOn
#define setFontWeight setBold
#define setFontUnderline setUnderline
#define setFontItalic setItalic
#define setFontFamily setFamily
#define setFontPointSize setPointSize
#define setTextColor setColor
#define textColor color
#define setHtml setText
#define toHtml text
#endif
#include "project_notes.h"
#include "embed.h"
#include "lmms_main_win.h"
#include "song_editor.h"
projectNotes::projectNotes() :
QMainWindow( lmmsMainWin::inst()->workspace()
#ifndef QT4
, 0, Qt::WStyle_Title
#endif
)
{
#ifdef QT4
lmmsMainWin::inst()->workspace()->addWindow( this );
#endif
m_edit = new QTextEdit( this );
#ifdef QT4
QPalette pal;
pal.setColor( m_edit->backgroundRole(), QColor( 64, 64, 64 ) );
m_edit->setPalette( pal );
#else
m_edit->setTextFormat( RichText );
m_edit->setPaletteBackgroundColor( QColor( 64, 64, 64 ) );
#endif
clear();
connect( m_edit, SIGNAL( currentFontChanged( const QFont & ) ),
this, SLOT( fontChanged( const QFont & ) ) );
connect( m_edit, SIGNAL( currentColorChanged( const QColor & ) ),
this, SLOT( colorChanged( const QColor & ) ) );
connect( m_edit, SIGNAL( currentAlignmentChanged( int ) ),
this, SLOT( alignmentChanged( int ) ) );
connect( m_edit, SIGNAL( textChanged() ),
songEditor::inst(), SLOT( setModified() ) );
setupActions();
setCentralWidget( m_edit );
setWindowTitle( tr( "Project notes" ) );
setWindowIcon( embed::getIconPixmap( "project_notes" ) );
}
void projectNotes::clear( void )
{
m_edit->setHtml( tr( "Put down your project notes here." ) );
}
void projectNotes::setupActions()
{
QToolBar * tb = new QToolBar( tr( "Edit Actions" ), this );
QAction * a;
// changes between qt3's toolbar-system and this of qt4 are too
// big, so we completely implement two versions
#ifdef QT4
a = new QAction( embed::getIconPixmap( "edit_undo" ), tr( "&Undo" ),
tb );
a->setShortcut( tr( "Ctrl+Z" ) );
connect( a, SIGNAL( activated() ), m_edit, SLOT( undo() ) );
a = new QAction( embed::getIconPixmap( "edit_redo" ), tr( "&Redo" ),
tb );
a->setShortcut( tr( "Ctrl+Y" ) );
connect( a, SIGNAL( activated() ), m_edit, SLOT( redo() ) );
a = new QAction( embed::getIconPixmap( "edit_copy" ), tr( "&Copy" ),
tb );
a->setShortcut( tr( "Ctrl+C" ) );
connect( a, SIGNAL( activated() ), m_edit, SLOT( copy() ) );
a = new QAction( embed::getIconPixmap( "edit_cut" ), tr( "Cu&t" ),
tb );
a->setShortcut( tr( "Ctrl+X" ) );
connect( a, SIGNAL( activated() ), m_edit, SLOT( cut() ) );
a = new QAction( embed::getIconPixmap( "edit_paste" ), tr( "&Paste" ),
tb );
a->setShortcut( tr( "Ctrl+V" ) );
connect( a, SIGNAL( activated() ), m_edit, SLOT( paste() ) );
tb = new QToolBar( tr( "Format Actions" ), this );
m_comboFont = new QComboBox( tb );
m_comboFont->setEditable( TRUE );
QFontDatabase db;
m_comboFont->addItems( db.families() );
connect( m_comboFont, SIGNAL( activated( const QString & ) ),
m_edit, SLOT( setFontFamily( const QString & ) ) );
m_comboFont->lineEdit()->setText( QApplication::font().family() );
m_comboSize = new QComboBox( tb );
m_comboSize->setEditable( TRUE );
vlist<int> sizes = db.standardSizes();
vlist<int>::Iterator it = sizes.begin();
for ( ; it != sizes.end(); ++it )
{
m_comboSize->addItem( QString::number( *it ) );
}
connect( m_comboSize, SIGNAL( activated( const QString & ) ),
this, SLOT( textSize( const QString & ) ) );
m_comboSize->lineEdit()->setText( QString::number(
QApplication::font().pointSize() ) );
m_actionTextBold = new QAction( embed::getIconPixmap( "text_bold" ),
tr( "&Bold" ), tb );
m_actionTextBold->setShortcut( tr( "Ctrl+B" ) );
connect( m_actionTextBold, SIGNAL( activated() ), this,
SLOT( textBold() ) );
m_actionTextItalic = new QAction( embed::getIconPixmap( "text_italic" ),
tr( "&Italic" ), tb );
m_actionTextItalic->setShortcut( tr( "Ctrl+I" ) );
connect( m_actionTextItalic, SIGNAL( activated() ), this,
SLOT( textItalic() ) );
m_actionTextUnderline = new QAction( embed::getIconPixmap(
"text_under" ),
tr( "&Underline" ), tb );
m_actionTextUnderline->setShortcut( tr( "Ctrl+U" ) );
connect( m_actionTextUnderline, SIGNAL( activated() ), this,
SLOT( textUnderline() ) );
QActionGroup * grp = new QActionGroup( tb );
connect( grp, SIGNAL( selected( QAction* ) ), this,
SLOT( textAlign( QAction* ) ) );
m_actionAlignLeft = new QAction( embed::getIconPixmap( "text_left" ),
tr( "&Left" ), grp );
m_actionAlignLeft->setShortcut( tr( "Ctrl+L" ) );
m_actionAlignCenter = new QAction( embed::getIconPixmap(
"text_center" ),
tr( "C&enter" ), grp );
m_actionAlignCenter->setShortcut( tr( "Ctrl+E" ) );
m_actionAlignRight = new QAction( embed::getIconPixmap( "text_right" ),
tr( "&Right" ), grp );
m_actionAlignRight->setShortcut( tr( "Ctrl+R" ) );
m_actionAlignJustify = new QAction( embed::getIconPixmap(
"text_block" ),
tr( "&Justify" ), grp );
m_actionAlignJustify->setShortcut( tr( "Ctrl+J" ) );
QPixmap pix( 16, 16 );
pix.fill( Qt::black );
m_actionTextColor = new QAction( pix, tr( "&Color..." ), tb );
connect( m_actionTextColor, SIGNAL( activated() ), this,
SLOT( textColor() ) );
#else
#if QT_VERSION >= 0x030100
a = new QAction(
#if QT_VERSION < 0x030200
"",
#endif
embed::getIconPixmap( "edit_undo" ), tr( "&Undo" ),
CTRL + Key_Z, this );
connect( a, SIGNAL( activated() ), m_edit, SLOT( undo() ) );
a->addTo( tb );
a = new QAction(
#if QT_VERSION < 0x030200
"",
#endif
embed::getIconPixmap( "edit_redo" ), tr( "&Redo" ),
CTRL + Key_Y, this );
connect( a, SIGNAL( activated() ), m_edit, SLOT( redo() ) );
a->addTo( tb );
a = new QAction(
#if QT_VERSION < 0x030200
"",
#endif
embed::getIconPixmap( "edit_copy" ), tr( "&Copy" ),
CTRL + Key_C, this );
connect( a, SIGNAL( activated() ), m_edit, SLOT( copy() ) );
a->addTo( tb );
a = new QAction(
#if QT_VERSION < 0x030200
"",
#endif
embed::getIconPixmap( "edit_cut" ), tr( "Cu&t" ),
CTRL + Key_X, this );
connect( a, SIGNAL( activated() ), m_edit, SLOT( cut() ) );
a->addTo( tb );
a = new QAction(
#if QT_VERSION < 0x030200
"",
#endif
embed::getIconPixmap( "edit_paste" ), tr( "&Paste" ),
CTRL + Key_V, this );
connect( a, SIGNAL( activated() ), m_edit, SLOT( paste() ) );
a->addTo( tb );
tb = new QToolBar( this );
tb->setLabel( tr( "Format Actions" ) );
m_comboFont = new QComboBox( TRUE, tb );
QFontDatabase db;
m_comboFont->insertStringList( db.families() );
connect( m_comboFont, SIGNAL( activated( const QString & ) ),
m_edit, SLOT( setFamily( const QString & ) ) );
m_comboFont->lineEdit()->setText( QApplication::font().family() );
m_comboSize = new QComboBox( TRUE, tb );
vlist<int> sizes = db.standardSizes();
vlist<int>::Iterator it = sizes.begin();
for ( ; it != sizes.end(); ++it )
{
m_comboSize->insertItem( QString::number( *it ) );
}
connect( m_comboSize, SIGNAL( activated( const QString & ) ),
this, SLOT( textSize( const QString & ) ) );
m_comboSize->lineEdit()->setText( QString::number(
QApplication::font().pointSize() ) );
m_actionTextBold = new QAction(
#if QT_VERSION < 0x030200
"",
#endif
embed::getIconPixmap( "text_bold" ),
tr( "&Bold" ), CTRL + Key_B, this );
connect( m_actionTextBold, SIGNAL( activated() ), this,
SLOT( textBold() ) );
m_actionTextBold->addTo( tb );
m_actionTextBold->setToggleAction( TRUE );
m_actionTextItalic = new QAction(
#if QT_VERSION < 0x030200
"",
#endif
embed::getIconPixmap( "text_italic" ),
tr( "&Italic" ), CTRL + Key_I, this );
connect( m_actionTextItalic, SIGNAL( activated() ), this,
SLOT( textItalic() ) );
m_actionTextItalic->addTo( tb );
m_actionTextItalic->setToggleAction( TRUE );
m_actionTextUnderline = new QAction(
#if QT_VERSION < 0x030200
"",
#endif
embed::getIconPixmap(
"text_under" ),
tr( "&Underline" ),
CTRL + Key_U, this );
connect( m_actionTextUnderline, SIGNAL( activated() ), this,
SLOT( textUnderline() ) );
m_actionTextUnderline->addTo( tb );
m_actionTextUnderline->setToggleAction( TRUE );
QActionGroup * grp = new QActionGroup( this );
connect( grp, SIGNAL( selected( QAction* ) ), this,
SLOT( textAlign( QAction* ) ) );
m_actionAlignLeft = new QAction(
#if QT_VERSION < 0x030200
"",
#endif
embed::getIconPixmap( "text_left" ),
tr( "&Left" ), CTRL + Key_L,
grp );
m_actionAlignLeft->setToggleAction( TRUE );
m_actionAlignCenter = new QAction(
#if QT_VERSION < 0x030200
"",
#endif
embed::getIconPixmap(
"text_center" ),
tr( "C&enter" ), CTRL + Key_E,
grp );
m_actionAlignCenter->setToggleAction( TRUE );
m_actionAlignRight = new QAction(
#if QT_VERSION < 0x030200
"",
#endif
embed::getIconPixmap( "text_right" ),
tr( "&Right" ), CTRL + Key_R,
grp );
m_actionAlignRight->setToggleAction( TRUE );
m_actionAlignJustify = new QAction(
#if QT_VERSION < 0x030200
"",
#endif
embed::getIconPixmap(
"text_block" ),
tr( "&Justify" ), CTRL + Key_J,
grp );
m_actionAlignJustify->setToggleAction( TRUE );
grp->addTo( tb );
QPixmap pix( 16, 16 );
pix.fill( Qt::black );
m_actionTextColor = new QAction(
#if QT_VERSION < 0x030200
"",
#endif
pix, tr( "&Color..." ), 0, this );
connect( m_actionTextColor, SIGNAL( activated() ), this,
SLOT( textColor() ) );
m_actionTextColor->addTo( tb );
#endif
#endif
}
void projectNotes::textBold()
{
m_edit->setFontWeight( m_actionTextBold->isChecked() );
songEditor::inst()->setModified();
}
void projectNotes::textUnderline()
{
m_edit->setFontUnderline( m_actionTextUnderline->isChecked() );
songEditor::inst()->setModified();
}
void projectNotes::textItalic()
{
m_edit->setFontItalic( m_actionTextItalic->isChecked() );
songEditor::inst()->setModified();
}
void projectNotes::textFamily( const QString & _f )
{
m_edit->setFontFamily( _f );
m_edit->viewport()->setFocus();
songEditor::inst()->setModified();
}
void projectNotes::textSize( const QString & _p )
{
m_edit->setFontPointSize( _p.toInt() );
m_edit->viewport()->setFocus();
songEditor::inst()->setModified();
}
void projectNotes::textColor()
{
QColor col = QColorDialog::getColor( m_edit->textColor(), this );
if ( !col.isValid() )
{
return;
}
m_edit->setTextColor( col );
QPixmap pix( 16, 16 );
pix.fill( Qt::black );
#ifdef QT4
m_actionTextColor->setIcon( pix );
#else
m_actionTextColor->setIconSet( pix );
#endif
}
void projectNotes::textAlign( QAction * _a )
{
if( _a == m_actionAlignLeft )
{
m_edit->setAlignment( Qt::AlignLeft );
}
else if( _a == m_actionAlignCenter )
{
m_edit->setAlignment( Qt::AlignHCenter );
}
else if( _a == m_actionAlignRight )
{
m_edit->setAlignment( Qt::AlignRight );
}
else if( _a == m_actionAlignJustify )
{
m_edit->setAlignment( Qt::AlignJustify );
}
}
void projectNotes::fontChanged( const QFont & _f )
{
m_comboFont->lineEdit()->setText( _f.family() );
m_comboSize->lineEdit()->setText( QString::number( _f.pointSize() ) );
m_actionTextBold->setChecked( _f.bold() );
m_actionTextItalic->setChecked( _f.italic() );
m_actionTextUnderline->setChecked( _f.underline() );
songEditor::inst()->setModified();
}
void projectNotes::colorChanged( const QColor & _c )
{
QPixmap pix( 16, 16 );
pix.fill( _c );
#ifdef QT4
m_actionTextColor->setIcon( pix );
#else
m_actionTextColor->setIconSet( pix );
#endif
songEditor::inst()->setModified();
}
void projectNotes::alignmentChanged( int _a )
{
if (
#ifndef QT4
( _a == Qt::AlignAuto ) ||
#endif
( _a & Qt::AlignLeft ) )
{
m_actionAlignLeft->setChecked( TRUE );
}
else if ( ( _a & Qt::AlignHCenter ) )
{
m_actionAlignCenter->setChecked( TRUE );
}
else if ( ( _a & Qt::AlignRight ) )
{
m_actionAlignRight->setChecked( TRUE );
}
else if ( ( _a & Qt::AlignJustify ) )
{
m_actionAlignJustify->setChecked( TRUE );
}
songEditor::inst()->setModified();
}
void projectNotes::saveSettings( QDomDocument & _doc, QDomElement & _parent )
{
QDomElement pn_de = _doc.createElement( nodeName() );
QDomCDATASection ds = _doc.createCDATASection( m_edit->toHtml() );
pn_de.appendChild( ds );
_parent.appendChild( pn_de );
}
void projectNotes::loadSettings( const QDomElement & _this )
{
m_edit->setHtml( _this.text() );
}
#include "project_notes.moc"
#undef isChecked
#undef setChecked
#undef setFontWeight
#undef setFontUnderline
#undef setFontItalic
#undef setFontFamily
#undef setFontPointSize
#undef textColor
#undef setTextColor
#undef setHtml
#undef toHtml

View File

@@ -0,0 +1,89 @@
/*
* rename_dialog.cpp - implementation of dialog for renaming something
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <QLineEdit>
#include <QKeyEvent>
#else
#include <qlineedit.h>
#endif
#include "rename_dialog.h"
renameDialog::renameDialog( QString & _string ) :
QDialog(),
m_stringToEdit( _string ),
m_originalString( _string )
{
setWindowTitle( tr("Rename...") );
m_stringLE = new QLineEdit( this );
m_stringLE->setText( _string );
m_stringLE->setGeometry ( 10, 5, 220, 20 );
connect( m_stringLE, SIGNAL( textChanged( const QString & ) ), this,
SLOT( textChanged( const QString & ) ) );
connect( m_stringLE, SIGNAL( returnPressed() ), this,
SLOT( accept() ) );
}
renameDialog::~renameDialog()
{
}
void renameDialog::keyPressEvent( QKeyEvent * _ke )
{
if( _ke->key() == Qt::Key_Escape )
{
m_stringLE->setText( m_originalString );
accept();
}
}
void renameDialog::textChanged( const QString & _new_string )
{
m_stringToEdit = _new_string;
}
#include "rename_dialog.moc"

View File

@@ -0,0 +1,123 @@
/*
* side_bar_widget.cpp - implementation of base-widget for side-bar
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <QApplication>
#include <QPainter>
#include <QFontMetrics>
#else
#include <qapplication.h>
#include <qpainter.h>
#include <qfontmetrics.h>
#endif
#include "side_bar_widget.h"
#include "types.h"
#include "templates.h"
sideBarWidget::sideBarWidget( const QString & _title, const QPixmap & _icon,
QWidget * _parent ) :
QWidget( _parent ),
m_title( _title ),
m_icon( _icon )
{
m_contents = new QWidget( this );
m_layout = new QVBoxLayout( m_contents );
m_layout->setSpacing( 5 );
}
sideBarWidget::~sideBarWidget()
{
}
void sideBarWidget::paintEvent( QPaintEvent * )
{
const Uint16 TITLE_FONT_HEIGHT = 16;
#ifdef QT4
QPainter p( this );
p.fillRect( 0, 0, width(), 27, palette().highlight().color() );
#else
QPixmap draw_pm( rect().size() );
draw_pm.fill( QApplication::palette().color( QPalette::Normal,
QColorGroup::Background ) );
QPainter p( &draw_pm, this );
p.fillRect( 0, 0, width(), 27, QApplication::palette().color(
QPalette::Normal,
QColorGroup::Highlight ) );
#endif
QFont f = p.font();
f.setBold( TRUE );
p.setFont( pointSize<TITLE_FONT_HEIGHT>( f ) );
#ifdef QT4
p.setPen( palette().highlightedText().color() );
#else
p.setPen( QApplication::palette().color( QPalette::Normal,
QColorGroup::HighlightedText ) );
#endif
const Uint16 tx = m_icon.width()+4;
const Uint16 ty = 2+TITLE_FONT_HEIGHT;
p.drawText( tx, ty, m_title );
p.drawLine( tx, ty+4, width()-4, ty+4 );
p.drawPixmap( 2, 2, m_icon );
#ifndef QT4
// and blit all drawn stuff on the screen...
bitBlt( this, rect().topLeft(), &draw_pm );
#endif
}
void sideBarWidget::resizeEvent( QResizeEvent * )
{
const Uint16 MARGIN = 6;
m_contents->setGeometry( MARGIN, 40 + MARGIN, width() - MARGIN * 2,
height() - MARGIN * 2 - 40 );
}
#include "side_bar.moc"
#include "side_bar_widget.moc"

260
src/widgets/tab_bar.cpp Normal file
View File

@@ -0,0 +1,260 @@
/*
* tab_bar.cpp - implementation of tab-bar
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "tab_bar.h"
#include "tab_button.h"
#include "templates.h"
#include "tooltip.h"
#ifndef QT4
#define value data
#define setChecked setOn
#define isChecked isOn
#define removeWidget remove
#endif
tabBar::tabBar( QWidget * _parent, QBoxLayout::Direction _dir ) :
QWidget( _parent ),
#ifdef QT4
m_layout( new QBoxLayout( _dir, this ) ),
#else
m_layout( new QBoxLayout( this, _dir ) ),
#endif
m_exclusive( FALSE )
{
}
tabBar::~tabBar()
{
}
tabButton * tabBar::addTab( QWidget * _w, const QString & _text, int _id,
bool _add_stretch, bool _text_is_tooltip )
{
// already tab with id?
if( m_tabs.contains( _id ) )
{
// then remove it
removeTab( _id );
}
QString caption = ( _text_is_tooltip ) ? "" : _text;
// create tab-button
tabButton * b = new tabButton( caption, _id, this );
connect( b, SIGNAL( clicked( int ) ), this, SLOT( tabClicked( int ) ) );
b->show();
if( _text_is_tooltip )
{
toolTip::add( b, _text );
}
// small workaround, because QBoxLayout::addWidget(...) doesn't
// work properly, so we first have to remove all tabs from the
// layout and them add them in the correct order
QMap<int, QPair<tabButton *, QWidget *> >::iterator it;
for( it = m_tabs.begin(); it != m_tabs.end(); ++it )
{
#if QT_VERSION >= 0x030100
m_layout->removeWidget( it.value().first );
#endif
}
m_tabs.insert( _id, qMakePair( b, _w ) );
for( it = m_tabs.begin(); it != m_tabs.end(); ++it )
{
m_layout->addWidget( it.value().first );
}
if( _add_stretch )
{
m_layout->addStretch();
}
// we assume, parent-widget is a widget acting as widget-stack so all
// widgets have the same size and only the one on the top is visible
_w->setFixedSize( _w->parentWidget()->size() );
b->setFont( pointSize<7>( b->font() ) );
return( b );
}
void tabBar::removeTab( int _id )
{
// find tab-button and delete it
if( m_tabs.find( _id ) != m_tabs.end() )
{
delete m_tabs[_id].first;
m_tabs.erase( m_tabs.find( _id ) );
}
}
void tabBar::setActiveTab( int _id )
{
setTabState( _id, TRUE );
hideAll( _id );
if( allHidden() )
{
emit allWidgetsHidden();
}
else
{
emit widgetShown();
}
}
int tabBar::activeTab( void )
{
QMap<int, QPair<tabButton *, QWidget *> >::iterator it;
for( it = m_tabs.begin(); it != m_tabs.end(); ++it )
{
if( tabState( it.key() ) == TRUE )
{
return( it.key() );
}
}
return( -1 );
}
bool tabBar::tabState( int _id )
{
if( m_tabs.find( _id ) == m_tabs.end() )
{
return( FALSE );
}
return( m_tabs[_id].first->isChecked() );
}
void tabBar::setTabState( int _id, bool _checked )
{
if( m_tabs.find( _id ) != m_tabs.end() )
{
m_tabs[_id].first->setChecked( _checked );
}
}
void tabBar::hideAll( int _exception )
{
QMap<int, QPair<tabButton *, QWidget *> >::iterator it;
for( it = m_tabs.begin(); it != m_tabs.end(); ++it )
{
if( it.key() != _exception )
{
setTabState( it.key(), FALSE );
}
it.value().second->hide();
}
if( m_tabs.find( _exception ) != m_tabs.end() )
{
if( tabState( _exception ) )
{
m_tabs[_exception].second->show();
}
else
{
m_tabs[_exception].second->hide();
}
}
}
void tabBar::tabClicked( int _id )
{
if( m_exclusive == TRUE && activeTab() == -1 )
{
setActiveTab( _id );
}
else
{
bool all_hidden_before = allHidden();
// disable tabbar-buttons except the one clicked
hideAll( _id );
bool now_hidden = allHidden();
if( all_hidden_before == TRUE && now_hidden == FALSE )
{
emit widgetShown();
}
else if( all_hidden_before == FALSE && now_hidden == TRUE )
{
emit allWidgetsHidden();
}
}
}
bool tabBar::allHidden( void )
{
QMap<int, QPair<tabButton *, QWidget *> >::iterator it;
for( it = m_tabs.begin(); it != m_tabs.end(); ++it )
{
if( !it.value().second->isHidden() )
{
return( FALSE );
}
}
return( TRUE );
}
#undef value
#undef setChecked
#undef isChecked
#undef removeWidget
#include "tab_bar.moc"
#include "tab_button.moc"

177
src/widgets/tab_widget.cpp Normal file
View File

@@ -0,0 +1,177 @@
/*
* tabwidget.cpp - tabwidget for LMMS
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <QPainter>
#include <QPixmap>
#include <QMouseEvent>
#else
#include <qpainter.h>
#include <qpixmap.h>
#endif
#include "tab_widget.h"
#include "templates.h"
tabWidget::tabWidget( const QString & _caption, QWidget * _parent ) :
QWidget( _parent ),
m_curWidget( 0 ),
m_caption( _caption )
{
setFont( pointSize<7>( font() ) );
#ifdef QT4
QPalette pal = palette();
pal.setColor( QPalette::Background, QColor( 96, 96, 96 ) );
setPalette( pal );
#else
setPaletteBackgroundColor( QColor( 96, 96, 96 ) );
//setBackgroundMode( Qt::NoBackground );
#endif
}
tabWidget::~tabWidget()
{
}
void tabWidget::addTab( QWidget * _w, const QString & _name )
{
widgetDesc d = { _w, _name, fontMetrics().width( _name ) + 10 } ;
m_widgets.push_back( d );
// make sure new tab doesn't overlap current widget
m_widgets[m_curWidget].w->raise();
_w->setFixedSize( width() - 4, height() - 14 );
_w->move( 2, 12 );
}
void tabWidget::mousePressEvent( QMouseEvent * _me )
{
if( _me->y() > 1 && _me->y() < 13 )
{
int cx = 14 + fontMetrics().width( m_caption );
for( widgetStack::iterator it = m_widgets.begin();
it != m_widgets.end(); ++it )
{
if( _me->x() >= cx && _me->x() <= cx + it->nwidth )
{
it->w->raise();
m_curWidget = it - m_widgets.begin();
update();
return;
}
cx += it->nwidth;
}
}
}
void tabWidget::resizeEvent( QResizeEvent * )
{
for( widgetStack::iterator it = m_widgets.begin();
it != m_widgets.end(); ++it )
{
it->w->setFixedSize( width() - 4, height() - 14 );
}
}
void tabWidget::paintEvent( QPaintEvent * _pe )
{
#ifdef QT4
QPainter p( this );
#else
QPixmap pm( size() );
pm.fill( QColor( 96, 96, 96 ) );
QPainter p( &pm );
#endif
p.setPen( QColor( 64, 64, 64 ) );
p.drawRect( 0, 0, width(), height() );
p.setPen( QColor( 160, 160, 160 ) );
p.drawLine( width() - 1, 0, width() - 1, height() - 1 );
p.drawLine( 0, height() - 1, width() - 1, height() - 1 );
p.setPen( QColor( 0, 0, 0 ) );
p.drawRect( 1, 1, width() - 2, height() - 2 );
p.fillRect( 2, 2, width() - 4, 9, QColor( 30, 45, 60 ) );
p.drawLine( 2, 11, width() - 3, 11 );
p.setPen( QColor( 255, 255, 255 ) );
p.setFont( font() );
p.drawText( 5, 10, m_caption );
int cx = 14 + fontMetrics().width( m_caption );
p.setFont( pointSize<6>( p.font() ) );
p.setPen( QColor( 160, 160, 160 ) );
for( widgetStack::iterator it = m_widgets.begin();
it != m_widgets.end(); ++it )
{
if( it - m_widgets.begin() == m_curWidget )
{
p.setPen( QColor( 32, 48, 64 ) );
p.fillRect( cx, 2, it->nwidth - 6, 9,
QColor( 160, 160, 160 ) );
}
p.drawText( cx + 3, 9, it->name );
p.setPen( QColor( 160, 160, 160 ) );
cx += it->nwidth;
}
#ifndef QT4
bitBlt( this, rect().topLeft(), &pm );
#endif
}
#include "tab_widget.moc"

152
src/widgets/text_float.cpp Normal file
View File

@@ -0,0 +1,152 @@
/*
* text_float.cpp - class textFloat, a floating text-label
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <QPainter>
#include <QTimer>
#else
#include <qpainter.h>
#include <qpixmap.h>
#include <qtimer.h>
#define setParent reparent
#endif
#include "text_float.h"
#include "templates.h"
textFloat::textFloat( QWidget * _parent ) :
QWidget( _parent
#ifndef QT4
, "textFloat", WStyle_Customize | WStyle_NoBorder | WStyle_StaysOnTop
#endif
),
m_text( "" )
{
#ifndef QT4
setBackgroundMode( Qt::NoBackground );
#endif
reparent( parentWidget() );
resize( 20, 20 );
hide();
}
void textFloat::reparent( QWidget * _new_parent )
{
QPoint position = _new_parent->pos();
// Get position and reparent to either top level or dialog
//
while( _new_parent->parentWidget() && !_new_parent->isTopLevel()
&&
#ifdef QT4
!_new_parent->windowType() == Qt::Dialog
#else
!_new_parent->isDialog()
#endif
)
{
_new_parent = _new_parent->parentWidget();
position += _new_parent->pos();
}
// Position this widget to the right of the parent
//
//move(pos + QPoint(parent->width() + 5, 5));
QWidget::setParent( _new_parent,
#ifdef QT4
Qt::FramelessWindowHint |
Qt::WindowStaysOnTopHint );
#else
WStyle_Customize | WStyle_NoBorder |
WStyle_StaysOnTop,
position + QPoint( 20, 5 ) );
#endif
}
void textFloat::setVisibilityTimeOut( int _msecs )
{
QTimer::singleShot( _msecs, this, SLOT( hide() ) );
show();
}
void textFloat::paintEvent( QPaintEvent * _pe )
{
#ifdef QT4
QPainter p( this );
#else
QPixmap draw_pm( size() );
QPainter p( &draw_pm );
#endif
p.setPen( QColor( 0, 0, 0 ) );
p.setBrush( QColor( 255, 255, 255 ) );
p.setFont( pointSize<8>( p.font() ) );
QFontMetrics metrics( p.fontMetrics() );
QRect textBound = metrics.boundingRect( m_text );
resize( textBound.width() + 5, textBound.height() + 5 );
p.drawRect( rect() );
p.setPen( Qt::black );
p.drawText( 2, 10, m_text );
#ifndef QT4
bitBlt( this, rect().topLeft(), &draw_pm );
#endif
}
void textFloat::setText( const QString & _text )
{
m_text = _text;
repaint();
}
#undef setParent

59
src/widgets/tooltip.cpp Normal file
View File

@@ -0,0 +1,59 @@
/*
* tooltip.cpp - namespace toolTip, a tooltip-wrapper for LMMS
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <QToolTip>
#else
#include <qtooltip.h>
#endif
#include "tooltip.h"
#include "config_mgr.h"
void toolTip::add( QWidget * _w, const QString & _txt )
{
if( !configManager::inst()->value( "tooltips", "disabled" ).toInt() )
{
#ifdef QT4
//_w->setToolTip( _txt );
#else
QToolTip::add( _w, _txt );
#endif
}
}
/*
void toolTip::remove( QWidget * _w )
{
QToolTip::remove( _w );
}
*/

View File

@@ -0,0 +1,221 @@
/*
* visualization_widget.cpp - widget for visualization of waves
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <QPainter>
#include <QPixmap>
#include <QTimer>
#include <QMouseEvent>
#else
#include <qpainter.h>
#include <qpixmap.h>
#include <qtimer.h>
#endif
#include "visualization_widget.h"
#include "embed.h"
#include "buffer_allocator.h"
#include "templates.h"
#include "tooltip.h"
const int UPDATE_TIME = 1000 / 20; // 20 fps
visualizationWidget::visualizationWidget( const QPixmap & _bg, QWidget * _p,
visualizationTypes _vtype ) :
QWidget( _p ),
s_background( _bg ),
m_enabled( FALSE )
{
#ifndef QT4
setBackgroundMode( Qt::NoBackground );
#endif
const Uint32 frames = mixer::inst()->framesPerAudioBuffer();
m_buffer = bufferAllocator::alloc<surroundSampleFrame>( frames );
for( Uint32 frame = 0; frame < frames; ++frame )
{
for( Uint8 chnl = 0; chnl < SURROUND_CHANNELS; ++chnl )
{
m_buffer[frame][chnl] = 0.0f;
}
}
setFixedSize( s_background.width(), s_background.height() );
m_updateTimer = new QTimer( this );
connect( m_updateTimer, SIGNAL( timeout() ), this, SLOT( update() ) );
if( m_enabled )
{
m_updateTimer->start( UPDATE_TIME );
}
connect( mixer::inst(), SIGNAL( nextAudioBuffer(
const surroundSampleFrame *, Uint32 ) ),
this, SLOT( setAudioBuffer(
const surroundSampleFrame *, Uint32 ) ) );
toolTip::add( this, tr( "click to enable/disable visualization of "
"master-output" ) );
}
visualizationWidget::~visualizationWidget()
{
}
void visualizationWidget::setAudioBuffer( const surroundSampleFrame * _ab,
Uint32 _frames )
{
if( m_enabled )
{
memcpy( m_buffer, *_ab, _frames * BYTES_PER_SURROUND_FRAME);
}
}
void visualizationWidget::paintEvent( QPaintEvent * )
{
#ifdef QT4
QPainter p( this );
#else
QPixmap draw_pm( rect().size() );
//draw_pm.fill( this, rect().topLeft() );
QPainter p( &draw_pm, this );
#endif
p.drawPixmap( 0, 0, s_background );
if( m_enabled )
{
float master_output = mixer::inst()->masterOutput();
Uint16 w = width()-4;
float half_h = -( height() - 6 ) / 3.0 * master_output - 1;
Uint16 x_base = 2;
Uint16 y_base = height()/2 - 1;
Uint16 old_y[DEFAULT_CHANNELS] = { y_base + (int)(
m_buffer[0][0]*half_h ),
y_base + (int)(
m_buffer[0][1]*half_h )
} ;
p.setClipRect( 2, 2, w, height()-4 );
float max_level = 0.0;
const Uint32 frames = mixer::inst()->framesPerAudioBuffer();
// analyse wave-stream for max-level
for( Uint32 frame = 0; frame < frames; ++frame )
{
for( Uint8 chnl = 0; chnl < SURROUND_CHANNELS; ++chnl )
{
if( tAbs<float>( m_buffer[frame][chnl] ) >
max_level )
{
max_level = tAbs<float>(
m_buffer[frame][chnl] );
}
}
}
// and set color according to that...
if( max_level * master_output < 0.9 )
{
p.setPen( QColor( 96, 255, 96 ) );
}
else if( max_level * master_output < 1.1 )
{
p.setPen( QColor( 255, 192, 64 ) );
}
else
{
p.setPen( QColor( 255, 64, 64 ) );
}
// now draw all that stuff
for( Uint32 frame = 0; frame < frames; ++frame )
{
for( Uint8 chnl = 0; chnl < DEFAULT_CHANNELS; ++chnl )
{
Uint16 cur_y = y_base +
(Uint16)( m_buffer[frame][chnl] *
half_h );
Uint16 xp = x_base + frame * w / frames;
p.drawLine( xp, old_y[chnl], xp, cur_y );
old_y[chnl] = cur_y;
}
}
}
#ifndef QT4
// and blit all drawn stuff on the screen...
bitBlt( this, rect().topLeft(), &draw_pm );
#endif
}
void visualizationWidget::mousePressEvent( QMouseEvent * _me )
{
if( _me->button() == Qt::LeftButton )
{
m_enabled = !m_enabled;
if( m_enabled )
{
m_updateTimer->start( UPDATE_TIME );
}
else
{
m_updateTimer->stop();
// we have to update (remove last waves),
// because timer doesn't do that anymore
update();
}
}
}
#include <visualization_widget.moc>