patman, reworked resampling, sample extensions
git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@471 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
65
ChangeLog
65
ChangeLog
@@ -1,3 +1,68 @@
|
||||
2007-04-07 Javier Serrano Polo <jasp00/at/terra/dot/es>
|
||||
|
||||
* plugins/patman/artwork.png:
|
||||
* plugins/patman/logo.png:
|
||||
* plugins/patman/loop_off.png:
|
||||
* plugins/patman/loop_on.png:
|
||||
* plugins/patman/Makefile.am:
|
||||
* plugins/patman/patman.cpp:
|
||||
* plugins/patman/patman.h:
|
||||
* plugins/patman/tune_off.png:
|
||||
* plugins/patman/tune_on.png:
|
||||
initial release, PatMan instrument plugin
|
||||
|
||||
* include/sample_buffer.h:
|
||||
* src/lib/sample_buffer.cpp:
|
||||
- added start/end loop points, different from start/end sample points
|
||||
- added sample frequency
|
||||
- reworked resampling, fixes resampling underruns/clicks
|
||||
- reused try-to-make-relative and try-to-make-absolute file handling
|
||||
- reused samplerate conversion
|
||||
|
||||
* include/sample_buffer.h:
|
||||
* include/sample_play_handle.h:
|
||||
* plugins/audio_file_processor/audio_file_processor.cpp:
|
||||
* plugins/audio_file_processor/audio_file_processor.h:
|
||||
* plugins/singerbot/singerbot.cpp:
|
||||
* src/core/sample_play_handle.cpp:
|
||||
* src/lib/sample_buffer.cpp:
|
||||
added per handle state
|
||||
|
||||
* include/engine.h:
|
||||
* include/file_browser.h:
|
||||
* include/plugin.h:
|
||||
* plugins/audio_file_processor/audio_file_processor.cpp:
|
||||
* plugins/audio_file_processor/audio_file_processor.h:
|
||||
* src/core/engine.cpp:
|
||||
* src/core/file_browser.cpp:
|
||||
* src/core/main_window.cpp:
|
||||
modularized sample extensions
|
||||
|
||||
* plugins/audio_file_processor/audio_file_processor.cpp:
|
||||
- check dragged file extension
|
||||
- accept dragged files from desktop
|
||||
- fit displayed file name in the background box
|
||||
|
||||
* src/core/track_container.cpp:
|
||||
fixed track swapping
|
||||
|
||||
* src/tracks/bb_track.cpp:
|
||||
fixed loading last bb-track name
|
||||
|
||||
* include/pattern.h:
|
||||
* src/tracks/pattern.cpp:
|
||||
removed obsolete method
|
||||
|
||||
* plugins/polyb302/polyb302.cpp:
|
||||
* plugins/polyb302/polyb302.h:
|
||||
simplified inclusions and comments
|
||||
|
||||
* include/main_window.h:
|
||||
cosmetic, grouped methods
|
||||
|
||||
* data/locale/ca.ts:
|
||||
updated translation
|
||||
|
||||
2007-04-01 Tobias Doerffel <tobydox/at/users/dot/sourceforge/dot/net>
|
||||
|
||||
* src/lmms_single_source.cpp:
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.50)
|
||||
AC_INIT(lmms, 0.2.1-svn20070328, lmms-devel/at/lists/dot/sf/dot/net)
|
||||
AM_INIT_AUTOMAKE(lmms, 0.2.1-svn20070328)
|
||||
AC_INIT(lmms, 0.2.1-svn20070407, lmms-devel/at/lists/dot/sf/dot/net)
|
||||
AM_INIT_AUTOMAKE(lmms, 0.2.1-svn20070407)
|
||||
|
||||
AM_CONFIG_HEADER(config.h)
|
||||
|
||||
@@ -590,8 +590,9 @@ AC_CONFIG_FILES([Makefile
|
||||
plugins/live_tool/Makefile
|
||||
plugins/midi_import/Makefile
|
||||
plugins/organic/Makefile
|
||||
plugins/polyb302/Makefile
|
||||
plugins/patman/Makefile
|
||||
plugins/plucked_string_synth/Makefile
|
||||
plugins/polyb302/Makefile
|
||||
plugins/singerbot/Makefile
|
||||
plugins/stk/Makefile
|
||||
plugins/stk/mallets/Makefile
|
||||
|
||||
Binary file not shown.
@@ -2703,6 +2703,45 @@ Per favor, visita http://wiki.mindrules.net per a documentació sobre LMMS.</tra
|
||||
<translation>Aleatoritza</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>patmanSynth</name>
|
||||
<message>
|
||||
<source>Open other patch</source>
|
||||
<translation>Obre altre pedaç</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Click here to open another patch-file. Loop and Tune settings are not reset.</source>
|
||||
<translation>Pica aquí per a obrir un altre fitxer pedaç. La configuració de Bucle i Afina no es reinicia.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Loop mode</source>
|
||||
<translation>Mode Bucle</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Here you can toggle the Loop mode. If enabled, PatMan will use the loop information available in the file.</source>
|
||||
<translation>Aquí pots canviar el mode Bucle. Si és actiu, PatMan farà servir la informació de bucle disponible al fitxer.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Tune mode</source>
|
||||
<translation>Mode Afina</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Here you can toggle the Tune mode. If enabled, PatMan will tune the sample to match the note's frequency.</source>
|
||||
<translation>Aquí pots canviar el mode Afina. Si és actiu, PatMan afinarà la mostra a la freqüència de la nota.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>No file selected</source>
|
||||
<translation>Cap fitxer seleccionat</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open patch file</source>
|
||||
<translation>Obre fitxer pedaç</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Patch-Files (*.pat)</source>
|
||||
<translation>Fitxers Pedaç (*.pat)</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>pattern</name>
|
||||
<message>
|
||||
@@ -3006,6 +3045,10 @@ usa la roda del ratolí per a ajustar el volum d'un pas</translation>
|
||||
<source>Incomplete polyphonic immitation tb303</source>
|
||||
<translation>Imitació polifònica incompleta tb303</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>GUS-compatible patch instrument</source>
|
||||
<translation>Instrument de pedaç compatible GUS</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>polyb302Synth</name>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* engine.h - engine-system of LMMS
|
||||
*
|
||||
* Copyright (c) 2006 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
* Copyright (c) 2006-2007 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
@@ -30,6 +30,16 @@
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef QT4
|
||||
|
||||
#include <QtCore/QMap>
|
||||
|
||||
#else
|
||||
|
||||
#include <qmap.h>
|
||||
|
||||
#endif
|
||||
|
||||
class automationEditor;
|
||||
class bbEditor;
|
||||
class projectJournal;
|
||||
@@ -124,6 +134,11 @@ public:
|
||||
}
|
||||
void updateFramesPerTact64th( void );
|
||||
|
||||
const QMap<QString, QString> & sampleExtensions( void )
|
||||
{
|
||||
return( m_sample_extensions );
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
bool m_hasGUI;
|
||||
@@ -141,7 +156,11 @@ private:
|
||||
#ifdef LADSPA_SUPPORT
|
||||
ladspa2LMMS * m_ladspaManager;
|
||||
#endif
|
||||
|
||||
|
||||
QMap<QString, QString> m_sample_extensions;
|
||||
|
||||
void load_extensions( void );
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
@@ -133,13 +133,15 @@ private:
|
||||
|
||||
|
||||
|
||||
class directory : public Q3ListViewItem
|
||||
class directory : public Q3ListViewItem, public engineObject
|
||||
{
|
||||
public:
|
||||
directory( Q3ListView * _parent, const QString & _filename,
|
||||
const QString & _path, const QString & _filter );
|
||||
const QString & _path, const QString & _filter,
|
||||
engine * _engine );
|
||||
directory( directory * _parent, const QString & _filename,
|
||||
const QString & _path, const QString & _filter );
|
||||
const QString & _path, const QString & _filter,
|
||||
engine * _engine );
|
||||
|
||||
void setOpen( bool );
|
||||
void setup( void );
|
||||
@@ -187,13 +189,15 @@ private:
|
||||
|
||||
|
||||
|
||||
class fileItem : public Q3ListViewItem
|
||||
class fileItem : public Q3ListViewItem, public engineObject
|
||||
{
|
||||
public:
|
||||
fileItem( Q3ListView * _parent, const QString & _name,
|
||||
const QString & _path );
|
||||
const QString & _path,
|
||||
engine * _engine );
|
||||
fileItem( Q3ListViewItem * _parent, const QString & _name,
|
||||
const QString & _path );
|
||||
const QString & _path,
|
||||
engine * _engine );
|
||||
|
||||
inline QString fullName( void ) const
|
||||
{
|
||||
@@ -216,6 +220,9 @@ public:
|
||||
return( m_type );
|
||||
}
|
||||
|
||||
QString extension( void );
|
||||
static QString extension( const QString & _file );
|
||||
|
||||
|
||||
private:
|
||||
void initPixmapStuff( void );
|
||||
|
||||
@@ -144,6 +144,8 @@ private:
|
||||
|
||||
void finalize( void );
|
||||
|
||||
bool have_www_browser( void );
|
||||
|
||||
|
||||
QWorkspace * m_workspace;
|
||||
|
||||
@@ -169,8 +171,6 @@ private:
|
||||
QMenu * m_tools_menu;
|
||||
vlist<tool *> m_tools;
|
||||
|
||||
bool have_www_browser( void );
|
||||
|
||||
|
||||
friend class engine;
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* pattern.h - declaration of class pattern, which contains all informations
|
||||
* about a pattern
|
||||
*
|
||||
* Copyright (c) 2004-2006 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
* Copyright (c) 2004-2007 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
@@ -144,12 +144,6 @@ public:
|
||||
return( m_frozenPattern );
|
||||
}
|
||||
|
||||
// if channel-track recognizes that this pattern is frozen, it calls
|
||||
// this instead of playing all the notes
|
||||
void FASTCALL playFrozenData( sampleFrame * _ab,
|
||||
const f_cnt_t _start_frame,
|
||||
const fpab_t _frames );
|
||||
|
||||
// settings-management
|
||||
virtual void FASTCALL saveSettings( QDomDocument & _doc,
|
||||
QDomElement & _parent );
|
||||
|
||||
@@ -144,6 +144,13 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
virtual const QStringList & supportedExtensions( void )
|
||||
{
|
||||
static QStringList no_extensions;
|
||||
return( no_extensions );
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
const plugin::pluginTypes m_type;
|
||||
}
|
||||
|
||||
@@ -70,6 +70,26 @@ public:
|
||||
DOTS
|
||||
} ;
|
||||
|
||||
|
||||
class handleState
|
||||
{
|
||||
public:
|
||||
handleState( bool _varying_pitch = FALSE );
|
||||
virtual ~handleState();
|
||||
|
||||
|
||||
private:
|
||||
f_cnt_t m_frame_index;
|
||||
const bool m_varying_pitch;
|
||||
#ifdef HAVE_SAMPLERATE_H
|
||||
SRC_STATE * m_resampling_data;
|
||||
#endif
|
||||
|
||||
friend class sampleBuffer;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
// constructor which either loads sample _audio_file or decodes
|
||||
// base64-data out of string
|
||||
sampleBuffer( engine * _engine, const QString & _audio_file = "",
|
||||
@@ -80,11 +100,10 @@ public:
|
||||
|
||||
virtual ~sampleBuffer();
|
||||
|
||||
bool FASTCALL play( sampleFrame * _ab, const f_cnt_t _start_frame,
|
||||
bool FASTCALL play( sampleFrame * _ab, handleState * _state,
|
||||
const fpab_t _frames,
|
||||
const float _freq = BASE_FREQ,
|
||||
const bool _looped = FALSE,
|
||||
void * * _resampling_data = NULL );
|
||||
const bool _looped = FALSE );
|
||||
|
||||
void FASTCALL visualize( QPainter & _p, const QRect & _dr,
|
||||
const QRect & _clip,
|
||||
@@ -110,6 +129,16 @@ public:
|
||||
return( m_endFrame );
|
||||
}
|
||||
|
||||
void setLoopStartFrame( f_cnt_t _start )
|
||||
{
|
||||
m_loop_startFrame = _start;
|
||||
}
|
||||
|
||||
void setLoopEndFrame( f_cnt_t _end )
|
||||
{
|
||||
m_loop_endFrame = _end;
|
||||
}
|
||||
|
||||
inline f_cnt_t frames( void ) const
|
||||
{
|
||||
return( m_frames );
|
||||
@@ -125,13 +154,21 @@ public:
|
||||
return( m_reversed );
|
||||
}
|
||||
|
||||
inline float frequency( void ) const
|
||||
{
|
||||
return( m_frequency );
|
||||
}
|
||||
|
||||
inline void setFrequency( float _freq )
|
||||
{
|
||||
m_frequency = _freq;
|
||||
}
|
||||
|
||||
inline const sampleFrame * data( void ) const
|
||||
{
|
||||
return( m_data );
|
||||
}
|
||||
|
||||
static void FASTCALL deleteResamplingData( void * * _ptr );
|
||||
|
||||
QString openAudioFile( void ) const;
|
||||
|
||||
QString & toBase64( QString & _dst ) const;
|
||||
@@ -152,6 +189,9 @@ public:
|
||||
_dst_sr, _buf->eng() ) );
|
||||
}
|
||||
|
||||
void normalize_sample_rate( const sample_rate_t _src_sr,
|
||||
bool _keep_settings = FALSE );
|
||||
|
||||
inline sample_t userWaveSample( const float _sample )
|
||||
{
|
||||
// Precise implementation
|
||||
@@ -182,6 +222,9 @@ public:
|
||||
m_dataMutex.unlock();
|
||||
}
|
||||
|
||||
static QString tryToMakeRelative( const QString & _file );
|
||||
static QString tryToMakeAbsolute( const QString & _file );
|
||||
|
||||
|
||||
public slots:
|
||||
void setAudioFile( const QString & _audio_file );
|
||||
@@ -195,8 +238,6 @@ public slots:
|
||||
private:
|
||||
void FASTCALL update( bool _keep_settings = FALSE );
|
||||
|
||||
static QString tryToMakeRelative( const QString & _file );
|
||||
|
||||
|
||||
#ifdef SDL_SDL_SOUND_H
|
||||
f_cnt_t FASTCALL decodeSampleSDL( const char * _f,
|
||||
@@ -224,20 +265,24 @@ private:
|
||||
f_cnt_t m_frames;
|
||||
f_cnt_t m_startFrame;
|
||||
f_cnt_t m_endFrame;
|
||||
f_cnt_t m_loop_startFrame;
|
||||
f_cnt_t m_loop_endFrame;
|
||||
float m_amplification;
|
||||
bool m_reversed;
|
||||
float m_frequency;
|
||||
QMutex m_dataMutex;
|
||||
|
||||
#ifdef HAVE_SAMPLERATE_H
|
||||
void initResampling( void );
|
||||
void quitResampling( void );
|
||||
SRC_STATE * createResamplingContext( void );
|
||||
static void FASTCALL destroyResamplingContext( SRC_STATE * _context );
|
||||
|
||||
SRC_DATA m_srcData;
|
||||
SRC_STATE * m_srcState;
|
||||
#endif
|
||||
|
||||
sampleFrame * m_sample_fragment;
|
||||
sampleFrame * getSampleFragment( f_cnt_t _start, f_cnt_t _frames,
|
||||
bool _looped );
|
||||
f_cnt_t getLoopedIndex( f_cnt_t _index );
|
||||
|
||||
|
||||
signals:
|
||||
void sampleUpdated( void );
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* sample_play_handle.h - play-handle for playing a sample
|
||||
*
|
||||
* Copyright (c) 2005-2006 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
* Copyright (c) 2005-2007 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
@@ -29,12 +29,12 @@
|
||||
#include <qobject.h>
|
||||
|
||||
#include "play_handle.h"
|
||||
#include "sample_buffer.h"
|
||||
#include "types.h"
|
||||
#include "engine.h"
|
||||
|
||||
class bbTrack;
|
||||
class pattern;
|
||||
class sampleBuffer;
|
||||
class sampleTCO;
|
||||
class track;
|
||||
class audioPort;
|
||||
@@ -79,6 +79,7 @@ private:
|
||||
bool m_doneMayReturnTrue;
|
||||
|
||||
f_cnt_t m_frame;
|
||||
sampleBuffer::handleState m_state;
|
||||
|
||||
audioPort * m_audioPort;
|
||||
const bool m_ownAudioPort;
|
||||
|
||||
@@ -25,6 +25,7 @@ SUBDIRS = \
|
||||
live_tool \
|
||||
midi_import \
|
||||
organic \
|
||||
patman \
|
||||
plucked_string_synth \
|
||||
polyb302 \
|
||||
$(SINGERBOT_DIR) \
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
#include "note_play_handle.h"
|
||||
#include "interpolation.h"
|
||||
#include "buffer_allocator.h"
|
||||
#include "file_browser.h"
|
||||
#include "pixmap_button.h"
|
||||
#include "knob.h"
|
||||
#include "tooltip.h"
|
||||
@@ -78,7 +79,7 @@ plugin::descriptor audiofileprocessor_plugin_descriptor =
|
||||
0x0100,
|
||||
plugin::Instrument,
|
||||
new QPixmap( PLUGIN_NAME::getIconPixmap( "logo" ) ),
|
||||
NULL
|
||||
new audioFileProcessor::subPluginFeatures( plugin::Instrument )
|
||||
} ;
|
||||
|
||||
}
|
||||
@@ -400,10 +401,15 @@ void audioFileProcessor::playNote( notePlayHandle * _n, bool )
|
||||
const float note_freq = getInstrumentTrack()->frequency( _n ) /
|
||||
( eng()->getMixer()->sampleRate() /
|
||||
DEFAULT_SAMPLE_RATE );
|
||||
if( m_sampleBuffer.play( buf, _n->totalFramesPlayed(),
|
||||
|
||||
if( !_n->m_pluginData )
|
||||
{
|
||||
_n->m_pluginData = new handleState( _n->hasDetuningInfo() );
|
||||
}
|
||||
|
||||
if( m_sampleBuffer.play( buf, (handleState *)_n->m_pluginData,
|
||||
frames, note_freq,
|
||||
m_loopButton->isChecked(),
|
||||
&_n->m_pluginData ) == TRUE )
|
||||
m_loopButton->isChecked() ) == TRUE )
|
||||
{
|
||||
getInstrumentTrack()->processAudioBuffer( buf, frames, _n );
|
||||
}
|
||||
@@ -415,7 +421,7 @@ void audioFileProcessor::playNote( notePlayHandle * _n, bool )
|
||||
|
||||
void audioFileProcessor::deleteNotePluginData( notePlayHandle * _n )
|
||||
{
|
||||
m_sampleBuffer.deleteResamplingData( &_n->m_pluginData );
|
||||
delete (handleState *)_n->m_pluginData;
|
||||
}
|
||||
|
||||
|
||||
@@ -423,12 +429,63 @@ void audioFileProcessor::deleteNotePluginData( notePlayHandle * _n )
|
||||
|
||||
void audioFileProcessor::dragEnterEvent( QDragEnterEvent * _dee )
|
||||
{
|
||||
if( stringPairDrag::processDragEnterEvent( _dee,
|
||||
QString( "samplefile,tco_%1" ).arg( track::SAMPLE_TRACK ) ) ==
|
||||
FALSE )
|
||||
#ifdef QT4
|
||||
if( _dee->mimeData()->hasFormat( "lmms/stringpair" ) )
|
||||
{
|
||||
QString txt = _dee->mimeData()->data( "lmms/stringpair" );
|
||||
if( txt.section( ':', 0, 0 ) == QString( "tco_%1" ).arg(
|
||||
track::SAMPLE_TRACK ) )
|
||||
{
|
||||
_dee->acceptProposedAction();
|
||||
}
|
||||
else if( txt.section( ':', 0, 0 ) == "samplefile" )
|
||||
{
|
||||
_dee->acceptProposedAction();
|
||||
}
|
||||
else
|
||||
{
|
||||
_dee->ignore();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_dee->ignore();
|
||||
}
|
||||
#else
|
||||
QString txt = _dee->encodedData( "lmms/stringpair" );
|
||||
if( txt != "" )
|
||||
{
|
||||
if( txt.section( ':', 0, 0 ) == QString( "tco_%1" ).arg(
|
||||
track::SAMPLE_TRACK ) )
|
||||
{
|
||||
_dee->accept();
|
||||
return;
|
||||
}
|
||||
if( txt.section( ':', 0, 0 ) == "samplefile"
|
||||
&& subPluginFeatures::supported_extensions().contains(
|
||||
fileItem::extension( txt.section( ':', 1 ) ) ) )
|
||||
{
|
||||
_dee->accept();
|
||||
return;
|
||||
}
|
||||
_dee->ignore();
|
||||
return;
|
||||
}
|
||||
|
||||
txt = QString( _dee->encodedData( "text/plain" ) );
|
||||
if( txt != "" )
|
||||
{
|
||||
QString file = QUriDrag::uriToLocalFile(
|
||||
txt.stripWhiteSpace() );
|
||||
if( file && subPluginFeatures::supported_extensions().contains(
|
||||
fileItem::extension( file ) ) )
|
||||
{
|
||||
_dee->accept();
|
||||
return;
|
||||
}
|
||||
}
|
||||
_dee->ignore();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -442,6 +499,7 @@ void audioFileProcessor::dropEvent( QDropEvent * _de )
|
||||
{
|
||||
setAudioFile( value );
|
||||
_de->accept();
|
||||
return;
|
||||
}
|
||||
else if( type == QString( "tco_%1" ).arg( track::SAMPLE_TRACK ) )
|
||||
{
|
||||
@@ -449,11 +507,21 @@ void audioFileProcessor::dropEvent( QDropEvent * _de )
|
||||
setAudioFile( mmp.content().firstChild().toElement().
|
||||
attribute( "src" ) );
|
||||
_de->accept();
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
#ifndef QT4
|
||||
QString txt = _de->encodedData( "text/plain" );
|
||||
if( txt != "" )
|
||||
{
|
||||
_de->ignore();
|
||||
setAudioFile( QUriDrag::uriToLocalFile(
|
||||
txt.stripWhiteSpace() ) );
|
||||
_de->accept();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
_de->ignore();
|
||||
}
|
||||
|
||||
|
||||
@@ -476,18 +544,18 @@ void audioFileProcessor::paintEvent( QPaintEvent * )
|
||||
QString file_name = "";
|
||||
Uint16 idx = m_sampleBuffer.audioFile().length();
|
||||
|
||||
p.setFont( pointSize<8>( p.font() ) );
|
||||
p.setFont( pointSize<8>( font() ) );
|
||||
|
||||
QFontMetrics fm( font() );
|
||||
QFontMetrics fm( p.font() );
|
||||
|
||||
// simple algorithm for creating a text from the filename that
|
||||
// matches in the white rectangle
|
||||
#ifdef QT4
|
||||
while( idx > 0 &&
|
||||
fm.size( Qt::TextSingleLine, file_name + "..." ).width() < 225 )
|
||||
fm.size( Qt::TextSingleLine, file_name + "..." ).width() < 210 )
|
||||
#else
|
||||
while( idx > 0 &&
|
||||
fm.size( Qt::SingleLine, file_name + "..." ).width() < 225 )
|
||||
fm.size( Qt::SingleLine, file_name + "..." ).width() < 210 )
|
||||
#endif
|
||||
{
|
||||
file_name = m_sampleBuffer.audioFile()[--idx] + file_name;
|
||||
@@ -666,6 +734,31 @@ void audioFileProcessor::openAudioFile( void )
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
audioFileProcessor::subPluginFeatures::subPluginFeatures(
|
||||
plugin::pluginTypes _type ) :
|
||||
plugin::descriptor::subPluginFeatures( _type )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const QStringList & audioFileProcessor::subPluginFeatures::supported_extensions(
|
||||
void )
|
||||
{
|
||||
static QStringList extensions = QStringList()
|
||||
<< "wav" << "ogg" << "spx" << "au" << "voc"
|
||||
<< "aif" << "aiff" << "flac" << "raw";
|
||||
return( extensions );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* audio_file_processor.h - declaration of class audioFileProcessor
|
||||
* (instrument-plugin for using audio-files)
|
||||
*
|
||||
* Copyright (c) 2004-2006 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
* Copyright (c) 2004-2007 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
@@ -53,6 +53,21 @@ class audioFileProcessor : public instrument, public specialBgHandlingWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
class subPluginFeatures : public plugin::descriptor::subPluginFeatures
|
||||
{
|
||||
public:
|
||||
subPluginFeatures( plugin::pluginTypes _type );
|
||||
|
||||
virtual const QStringList & supportedExtensions( void )
|
||||
{
|
||||
return( supported_extensions() );
|
||||
}
|
||||
|
||||
static const QStringList & supported_extensions( void );
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
audioFileProcessor( instrumentTrack * _channel_track );
|
||||
virtual ~audioFileProcessor();
|
||||
|
||||
@@ -94,6 +109,8 @@ protected:
|
||||
|
||||
|
||||
private:
|
||||
typedef sampleBuffer::handleState handleState;
|
||||
|
||||
static QPixmap * s_artwork;
|
||||
|
||||
|
||||
|
||||
33
plugins/patman/Makefile.am
Normal file
33
plugins/patman/Makefile.am
Normal file
@@ -0,0 +1,33 @@
|
||||
AUTOMAKE_OPTIONS = foreign 1.4
|
||||
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/src/lib -I.
|
||||
|
||||
|
||||
AM_CXXFLAGS := $(AM_CXXFLAGS) $(QT_CXXFLAGS) -DPLUGIN_NAME="patman"
|
||||
|
||||
|
||||
%.moc: ./%.h
|
||||
$(MOC) -o $@ $<
|
||||
|
||||
|
||||
MOC_FILES = ./patman.moc
|
||||
|
||||
BUILT_SOURCES = $(MOC_FILES) ./embedded_resources.h
|
||||
EMBEDDED_RESOURCES = $(wildcard *png)
|
||||
|
||||
./embedded_resources.h: $(EMBEDDED_RESOURCES)
|
||||
$(BIN2RES) $(EMBEDDED_RESOURCES) > $@
|
||||
|
||||
EXTRA_DIST = $(EMBEDDED_RESOURCES)
|
||||
|
||||
|
||||
CLEANFILES = $(MOC_FILES) ./embedded_resources.h
|
||||
|
||||
|
||||
|
||||
pkglib_LTLIBRARIES = libpatman.la
|
||||
|
||||
libpatman_la_SOURCES = patman.cpp patman.h
|
||||
|
||||
$(libpatman_la_SOURCES): ./embedded_resources.h
|
||||
BIN
plugins/patman/artwork.png
Normal file
BIN
plugins/patman/artwork.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 46 KiB |
BIN
plugins/patman/logo.png
Normal file
BIN
plugins/patman/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
BIN
plugins/patman/loop_off.png
Normal file
BIN
plugins/patman/loop_off.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 554 B |
BIN
plugins/patman/loop_on.png
Normal file
BIN
plugins/patman/loop_on.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 934 B |
693
plugins/patman/patman.cpp
Normal file
693
plugins/patman/patman.cpp
Normal file
@@ -0,0 +1,693 @@
|
||||
/*
|
||||
* patman.cpp - a GUS-compatible patch instrument plugin
|
||||
*
|
||||
* Copyright (c) 2007 Javier Serrano Polo <jasp00/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifdef QT4
|
||||
|
||||
#include <QtGui/QFileDialog>
|
||||
|
||||
#else
|
||||
|
||||
#include <qcursor.h>
|
||||
#include <qfiledialog.h>
|
||||
#include <qwhatsthis.h>
|
||||
|
||||
#endif
|
||||
|
||||
#include "patman.h"
|
||||
#include "buffer_allocator.h"
|
||||
#include "endian_handling.h"
|
||||
#include "file_browser.h"
|
||||
#include "note_play_handle.h"
|
||||
#include "pixmap_button.h"
|
||||
#include "song_editor.h"
|
||||
#include "string_pair_drag.h"
|
||||
#include "tooltip.h"
|
||||
|
||||
#undef SINGLE_SOURCE_COMPILE
|
||||
#include "embed.cpp"
|
||||
|
||||
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
plugin::descriptor patman_plugin_descriptor =
|
||||
{
|
||||
STRINGIFY_PLUGIN_NAME( PLUGIN_NAME ),
|
||||
"PatMan",
|
||||
QT_TRANSLATE_NOOP( "pluginBrowser",
|
||||
"GUS-compatible patch instrument" ),
|
||||
"Javier Serrano Polo <jasp00/at/users.sourceforge.net>",
|
||||
0x0100,
|
||||
plugin::Instrument,
|
||||
new QPixmap( PLUGIN_NAME::getIconPixmap( "logo" ) ),
|
||||
new patmanSynth::subPluginFeatures( plugin::Instrument )
|
||||
} ;
|
||||
|
||||
|
||||
// necessary for getting instance out of shared lib
|
||||
plugin * lmms_plugin_main( void * _data )
|
||||
{
|
||||
return( new patmanSynth( static_cast<instrumentTrack *>( _data ) ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
patmanSynth::patmanSynth( instrumentTrack * _track ) :
|
||||
instrument( _track, &patman_plugin_descriptor ),
|
||||
specialBgHandlingWidget( PLUGIN_NAME::getIconPixmap( "artwork" ) )
|
||||
{
|
||||
setPaletteBackgroundPixmap( PLUGIN_NAME::getIconPixmap( "artwork" ) );
|
||||
|
||||
m_openFileButton = new pixmapButton( this, NULL, eng(), NULL );
|
||||
m_openFileButton->setCursor( QCursor( Qt::PointingHandCursor ) );
|
||||
m_openFileButton->move( 200, 90 );
|
||||
m_openFileButton->setActiveGraphic( embed::getIconPixmap(
|
||||
"project_open_down" ) );
|
||||
m_openFileButton->setInactiveGraphic( embed::getIconPixmap(
|
||||
"project_open" ) );
|
||||
m_openFileButton->setBgGraphic( getBackground(
|
||||
m_openFileButton ) );
|
||||
connect( m_openFileButton, SIGNAL( clicked() ), this,
|
||||
SLOT( openFile() ) );
|
||||
toolTip::add( m_openFileButton, tr( "Open other patch" ) );
|
||||
|
||||
#ifdef QT4
|
||||
m_openFileButton->setWhatsThis(
|
||||
#else
|
||||
QWhatsThis::add( m_openFileButton,
|
||||
#endif
|
||||
tr( "Click here to open another patch-file. Loop and Tune "
|
||||
"settings are not reset." ) );
|
||||
|
||||
m_loopButton = new pixmapButton( this, NULL, eng(), NULL );
|
||||
m_loopButton->setCheckable( TRUE );
|
||||
m_loopButton->move( 160, 160 );
|
||||
m_loopButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
|
||||
"loop_on" ) );
|
||||
m_loopButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
|
||||
"loop_off" ) );
|
||||
m_loopButton->setBgGraphic( getBackground( m_loopButton ) );
|
||||
toolTip::add( m_loopButton, tr( "Loop mode" ) );
|
||||
#ifdef QT4
|
||||
m_loopButton->setWhatsThis(
|
||||
#else
|
||||
QWhatsThis::add( m_loopButton,
|
||||
#endif
|
||||
tr( "Here you can toggle the Loop mode. If enabled, PatMan "
|
||||
"will use the loop information available in the "
|
||||
"file." ) );
|
||||
|
||||
m_tuneButton = new pixmapButton( this, NULL, eng(), NULL );
|
||||
m_tuneButton->setCheckable( TRUE );
|
||||
m_tuneButton->setValue( TRUE );
|
||||
m_tuneButton->move( 180, 160 );
|
||||
m_tuneButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
|
||||
"tune_on" ) );
|
||||
m_tuneButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
|
||||
"tune_off" ) );
|
||||
m_tuneButton->setBgGraphic( getBackground( m_tuneButton ) );
|
||||
toolTip::add( m_tuneButton, tr( "Tune mode" ) );
|
||||
#ifdef QT4
|
||||
m_tuneButton->setWhatsThis(
|
||||
#else
|
||||
QWhatsThis::add( m_tuneButton,
|
||||
#endif
|
||||
tr( "Here you can toggle the Tune mode. If enabled, PatMan "
|
||||
"will tune the sample to match the note's "
|
||||
"frequency." ) );
|
||||
|
||||
m_display_filename = tr( "No file selected" );
|
||||
|
||||
setAcceptDrops( TRUE );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
patmanSynth::~patmanSynth()
|
||||
{
|
||||
unload_current_patch();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void patmanSynth::saveSettings( QDomDocument & _doc, QDomElement & _this )
|
||||
{
|
||||
_this.setAttribute( "src", m_patchFile );
|
||||
m_loopButton->saveSettings( _doc, _this, "looped" );
|
||||
m_tuneButton->saveSettings( _doc, _this, "tuned" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void patmanSynth::loadSettings( const QDomElement & _this )
|
||||
{
|
||||
setFile( _this.attribute( "src" ), FALSE );
|
||||
m_loopButton->loadSettings( _this, "looped" );
|
||||
m_tuneButton->loadSettings( _this, "tuned" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void patmanSynth::setParameter( const QString & _param, const QString & _value )
|
||||
{
|
||||
if( _param == "samplefile" )
|
||||
{
|
||||
setFile( _value );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
QString patmanSynth::nodeName( void ) const
|
||||
{
|
||||
return( patman_plugin_descriptor.name );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void patmanSynth::playNote( notePlayHandle * _n, bool )
|
||||
{
|
||||
const Uint32 frames = eng()->getMixer()->framesPerAudioBuffer();
|
||||
sampleFrame * buf = bufferAllocator::alloc<sampleFrame>( frames );
|
||||
|
||||
float freq = getInstrumentTrack()->frequency( _n ) /
|
||||
( eng()->getMixer()->sampleRate() /
|
||||
DEFAULT_SAMPLE_RATE );
|
||||
|
||||
if( !_n->m_pluginData )
|
||||
{
|
||||
select_sample( _n );
|
||||
}
|
||||
handle_data * hdata = (handle_data *)_n->m_pluginData;
|
||||
|
||||
float play_freq = hdata->tuned ? freq : hdata->sample->frequency();
|
||||
|
||||
if( hdata->sample->play( buf, hdata->state, frames, play_freq,
|
||||
m_loopButton->isChecked() ) )
|
||||
{
|
||||
getInstrumentTrack()->processAudioBuffer( buf, frames, _n );
|
||||
}
|
||||
bufferAllocator::free( buf );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void patmanSynth::deleteNotePluginData( notePlayHandle * _n )
|
||||
{
|
||||
handle_data * hdata = (handle_data *)_n->m_pluginData;
|
||||
sharedObject::unref( hdata->sample );
|
||||
delete hdata->state;
|
||||
delete hdata;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void patmanSynth::dragEnterEvent( QDragEnterEvent * _dee )
|
||||
{
|
||||
#ifdef QT4
|
||||
if( _dee->mimeData()->hasFormat( "lmms/stringpair" ) )
|
||||
{
|
||||
QString txt = _dee->mimeData()->data( "lmms/stringpair" );
|
||||
if( txt.section( ':', 0, 0 ) == "samplefile" )
|
||||
{
|
||||
_dee->acceptProposedAction();
|
||||
}
|
||||
else
|
||||
{
|
||||
_dee->ignore();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_dee->ignore();
|
||||
}
|
||||
#else
|
||||
QString txt = _dee->encodedData( "lmms/stringpair" );
|
||||
if( txt != "" )
|
||||
{
|
||||
if( txt.section( ':', 0, 0 ) == "samplefile"
|
||||
&& subPluginFeatures::supported_extensions().contains(
|
||||
fileItem::extension( txt.section( ':', 1 ) ) ) )
|
||||
{
|
||||
_dee->accept();
|
||||
return;
|
||||
}
|
||||
_dee->ignore();
|
||||
return;
|
||||
}
|
||||
|
||||
txt = QString( _dee->encodedData( "text/plain" ) );
|
||||
if( txt != "" )
|
||||
{
|
||||
QString file = QUriDrag::uriToLocalFile(
|
||||
txt.stripWhiteSpace() );
|
||||
if( file && subPluginFeatures::supported_extensions().contains(
|
||||
fileItem::extension( file ) ) )
|
||||
{
|
||||
_dee->accept();
|
||||
return;
|
||||
}
|
||||
}
|
||||
_dee->ignore();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void patmanSynth::dropEvent( QDropEvent * _de )
|
||||
{
|
||||
QString type = stringPairDrag::decodeKey( _de );
|
||||
QString value = stringPairDrag::decodeValue( _de );
|
||||
if( type == "samplefile" )
|
||||
{
|
||||
setFile( value );
|
||||
_de->accept();
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef QT4
|
||||
QString txt = _de->encodedData( "text/plain" );
|
||||
if( txt != "" )
|
||||
{
|
||||
setFile( QUriDrag::uriToLocalFile( txt.stripWhiteSpace() ) );
|
||||
_de->accept();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
_de->ignore();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void patmanSynth::paintEvent( QPaintEvent * )
|
||||
{
|
||||
#ifdef QT4
|
||||
QPainter p( this );
|
||||
#else
|
||||
QPixmap pm( rect().size() );
|
||||
pm.fill( this, rect().topLeft() );
|
||||
|
||||
QPainter p( &pm, this );
|
||||
#endif
|
||||
|
||||
p.setFont( pointSize<8>( font() ) );
|
||||
p.setPen( QColor( 0x66, 0xFF, 0x66 ) );
|
||||
p.drawText( 8, 140, m_display_filename );
|
||||
|
||||
#ifndef QT4
|
||||
bitBlt( this, rect().topLeft(), &pm );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void patmanSynth::openFile( void )
|
||||
{
|
||||
#ifdef QT4
|
||||
QFileDialog ofd( NULL, tr( "Open patch file" ) );
|
||||
#else
|
||||
QFileDialog ofd( QString::null, QString::null, NULL, "", TRUE );
|
||||
ofd.setWindowTitle( tr( "Open patch file" ) );
|
||||
#endif
|
||||
ofd.setFileMode( QFileDialog::ExistingFiles );
|
||||
|
||||
// set filters
|
||||
#ifdef QT4
|
||||
QStringList types;
|
||||
types << tr( "Patch-Files (*.pat)" );
|
||||
ofd.setFilters( types );
|
||||
#else
|
||||
ofd.addFilter( tr( "Patch-Files (*.pat)" ) );
|
||||
#endif
|
||||
|
||||
if( m_patchFile == "" )
|
||||
{
|
||||
ofd.setDirectory( configManager::inst()->userSamplesDir() );
|
||||
}
|
||||
else if( QFileInfo( m_patchFile ).isRelative() )
|
||||
{
|
||||
QString f = configManager::inst()->userSamplesDir()
|
||||
+ m_patchFile;
|
||||
if( QFileInfo( f ).exists() == FALSE )
|
||||
{
|
||||
f = configManager::inst()->factorySamplesDir()
|
||||
+ m_patchFile;
|
||||
}
|
||||
|
||||
ofd.selectFile( f );
|
||||
}
|
||||
else
|
||||
{
|
||||
ofd.selectFile( m_patchFile );
|
||||
}
|
||||
|
||||
if( ofd.exec() == QDialog::Accepted && !ofd.selectedFiles().isEmpty() )
|
||||
{
|
||||
QString f = ofd.selectedFiles()[0];
|
||||
if( f != "" )
|
||||
{
|
||||
setFile( f );
|
||||
eng()->getSongEditor()->setModified();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void patmanSynth::setFile( const QString & _patch_file, bool _rename )
|
||||
{
|
||||
// is current channel-name equal to previous-filename??
|
||||
if( _rename &&
|
||||
( getInstrumentTrack()->name() ==
|
||||
QFileInfo( m_patchFile ).fileName() ||
|
||||
m_patchFile == "" ) )
|
||||
{
|
||||
// then set it to new one
|
||||
getInstrumentTrack()->setName( QFileInfo( _patch_file
|
||||
).fileName() );
|
||||
}
|
||||
// else we don't touch the channel-name, because the user named it self
|
||||
|
||||
m_patchFile = sampleBuffer::tryToMakeRelative( _patch_file );
|
||||
load_error error = load_patch( sampleBuffer::tryToMakeAbsolute(
|
||||
_patch_file ) );
|
||||
if( error )
|
||||
{
|
||||
printf("Load error\n");
|
||||
}
|
||||
|
||||
m_display_filename = "";
|
||||
Uint16 idx = m_patchFile.length();
|
||||
|
||||
QFontMetrics fm( pointSize<8>( font() ) );
|
||||
|
||||
// simple algorithm for creating a text from the filename that
|
||||
// matches in the white rectangle
|
||||
while( idx > 0 && fm.size(
|
||||
#ifdef QT4
|
||||
Qt::TextSingleLine,
|
||||
#else
|
||||
Qt::SingleLine,
|
||||
#endif
|
||||
m_display_filename + "..." ).width() < 225 )
|
||||
{
|
||||
m_display_filename = m_patchFile[--idx] + m_display_filename;
|
||||
}
|
||||
|
||||
if( idx > 0 )
|
||||
{
|
||||
m_display_filename = "..." + m_display_filename;
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
patmanSynth::load_error patmanSynth::load_patch( const QString & _filename )
|
||||
{
|
||||
unload_current_patch();
|
||||
|
||||
FILE * fd = fopen( _filename, "rb" );
|
||||
if( !fd )
|
||||
{
|
||||
perror( "fopen" );
|
||||
return( LOAD_OPEN );
|
||||
}
|
||||
|
||||
unsigned char header[239];
|
||||
|
||||
if( fread( header, 1, 239, fd ) != 239 ||
|
||||
( memcmp( header, "GF1PATCH110\0ID#000002", 22 )
|
||||
&& memcmp( header, "GF1PATCH100\0ID#000002", 22 ) ) )
|
||||
{
|
||||
fclose( fd );
|
||||
return( LOAD_NOT_GUS );
|
||||
}
|
||||
|
||||
if( header[82] != 1 && header[82] != 0 )
|
||||
{
|
||||
fclose( fd );
|
||||
return( LOAD_INSTRUMENTS );
|
||||
}
|
||||
|
||||
if( header[151] != 1 && header[151] != 0 )
|
||||
{
|
||||
fclose( fd );
|
||||
return( LOAD_LAYERS );
|
||||
}
|
||||
|
||||
int sample_count = header[198];
|
||||
for( int i = 0; i < sample_count; ++i )
|
||||
{
|
||||
unsigned short tmpshort;
|
||||
|
||||
#define SKIP_BYTES( x ) \
|
||||
if ( fseek( fd, x, SEEK_CUR ) == -1 ) \
|
||||
{ \
|
||||
fclose( fd ); \
|
||||
return( LOAD_IO ); \
|
||||
}
|
||||
|
||||
#define READ_SHORT( x ) \
|
||||
if ( fread( &tmpshort, 2, 1, fd ) != 1 ) \
|
||||
{ \
|
||||
fclose( fd ); \
|
||||
return( LOAD_IO ); \
|
||||
} \
|
||||
x = (unsigned short)swap16IfBE( tmpshort );
|
||||
|
||||
#define READ_LONG( x ) \
|
||||
if ( fread( &x, 4, 1, fd ) != 1 ) \
|
||||
{ \
|
||||
fclose( fd ); \
|
||||
return( LOAD_IO ); \
|
||||
} \
|
||||
x = (unsigned)swap32IfBE( x );
|
||||
|
||||
// skip wave name, fractions
|
||||
SKIP_BYTES( 7 + 1 );
|
||||
unsigned data_length;
|
||||
READ_LONG( data_length );
|
||||
unsigned loop_start;
|
||||
READ_LONG( loop_start );
|
||||
unsigned loop_end;
|
||||
READ_LONG( loop_end );
|
||||
unsigned sample_rate;
|
||||
READ_SHORT( sample_rate );
|
||||
// skip low_freq, high_freq
|
||||
SKIP_BYTES( 4 + 4 );
|
||||
unsigned root_freq;
|
||||
READ_LONG( root_freq );
|
||||
// skip tuning, panning, envelope, tremolo, vibrato
|
||||
SKIP_BYTES( 2 + 1 + 12 + 3 + 3 );
|
||||
unsigned char modes;
|
||||
if ( fread( &modes, 1, 1, fd ) != 1 )
|
||||
{
|
||||
fclose( fd );
|
||||
return( LOAD_IO );
|
||||
}
|
||||
// skip scale frequency, scale factor, reserved space
|
||||
SKIP_BYTES( 2 + 2 + 36 );
|
||||
|
||||
f_cnt_t frames;
|
||||
sample_t * wave_samples;
|
||||
if( modes & MODES_16BIT )
|
||||
{
|
||||
frames = data_length >> 1;
|
||||
wave_samples = new sample_t[frames];
|
||||
for( f_cnt_t frame = 0; frame < frames; ++frame )
|
||||
{
|
||||
short sample;
|
||||
if ( fread( &sample, 2, 1, fd ) != 1 )
|
||||
{
|
||||
delete wave_samples;
|
||||
fclose( fd );
|
||||
return( LOAD_IO );
|
||||
}
|
||||
sample = swap16IfBE( sample );
|
||||
if( modes & MODES_UNSIGNED )
|
||||
{
|
||||
sample ^= 0x8000;
|
||||
}
|
||||
wave_samples[frame] = sample / 32767.0f;
|
||||
}
|
||||
|
||||
loop_start >>= 1;
|
||||
loop_end >>= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
frames = data_length;
|
||||
wave_samples = new sample_t[frames];
|
||||
for( f_cnt_t frame = 0; frame < frames; ++frame )
|
||||
{
|
||||
char sample;
|
||||
if ( fread( &sample, 1, 1, fd ) != 1 )
|
||||
{
|
||||
delete wave_samples;
|
||||
fclose( fd );
|
||||
return( LOAD_IO );
|
||||
}
|
||||
if( modes & MODES_UNSIGNED )
|
||||
{
|
||||
sample ^= 0x80;
|
||||
}
|
||||
wave_samples[frame] = sample / 127.0f;
|
||||
}
|
||||
}
|
||||
|
||||
sampleFrame * data = new sampleFrame[frames];
|
||||
|
||||
for( f_cnt_t frame = 0; frame < frames; ++frame )
|
||||
{
|
||||
for( ch_cnt_t chnl = 0; chnl < DEFAULT_CHANNELS;
|
||||
++chnl )
|
||||
{
|
||||
data[frame][chnl] = wave_samples[frame];
|
||||
}
|
||||
}
|
||||
|
||||
sampleBuffer * psample = new sampleBuffer( data, frames,
|
||||
eng() );
|
||||
psample->setFrequency( root_freq / 1000.0f );
|
||||
psample->normalize_sample_rate( sample_rate );
|
||||
|
||||
if( modes & MODES_LOOPING )
|
||||
{
|
||||
psample->setLoopStartFrame( loop_start
|
||||
* SAMPLE_RATES[DEFAULT_QUALITY_LEVEL]
|
||||
/ sample_rate );
|
||||
psample->setLoopEndFrame( loop_end
|
||||
* SAMPLE_RATES[DEFAULT_QUALITY_LEVEL]
|
||||
/ sample_rate );
|
||||
}
|
||||
|
||||
m_patch_samples.push_back( psample );
|
||||
|
||||
delete[] wave_samples;
|
||||
delete[] data;
|
||||
}
|
||||
fclose( fd );
|
||||
return( LOAD_OK );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void patmanSynth::unload_current_patch( void )
|
||||
{
|
||||
while( !m_patch_samples.empty() )
|
||||
{
|
||||
sharedObject::unref( m_patch_samples.back() );
|
||||
m_patch_samples.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void patmanSynth::select_sample( notePlayHandle * _n )
|
||||
{
|
||||
float freq = getInstrumentTrack()->frequency( _n ) /
|
||||
( eng()->getMixer()->sampleRate() /
|
||||
DEFAULT_SAMPLE_RATE );
|
||||
|
||||
float min_dist = HUGE_VALF;
|
||||
sampleBuffer * sample = NULL;
|
||||
|
||||
for( vvector<sampleBuffer *>::iterator it = m_patch_samples.begin();
|
||||
it != m_patch_samples.end(); ++it )
|
||||
{
|
||||
float patch_freq = ( *it )->frequency();
|
||||
float dist = freq >= patch_freq ? freq / patch_freq :
|
||||
patch_freq / freq;
|
||||
|
||||
if( dist < min_dist )
|
||||
{
|
||||
min_dist = dist;
|
||||
sample = *it;
|
||||
}
|
||||
}
|
||||
|
||||
handle_data * hdata = new handle_data;
|
||||
hdata->tuned = m_tuneButton->isChecked();
|
||||
if( sample )
|
||||
{
|
||||
hdata->sample = sharedObject::ref( sample );
|
||||
}
|
||||
else
|
||||
{
|
||||
hdata->sample = new sampleBuffer( NULL, 0, eng() );
|
||||
}
|
||||
hdata->state = new sampleBuffer::handleState( _n->hasDetuningInfo() );
|
||||
|
||||
_n->m_pluginData = hdata;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
patmanSynth::subPluginFeatures::subPluginFeatures( plugin::pluginTypes _type ) :
|
||||
plugin::descriptor::subPluginFeatures( _type )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const QStringList & patmanSynth::subPluginFeatures::supported_extensions( void )
|
||||
{
|
||||
static QStringList extension( "pat" );
|
||||
return( extension );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#include "patman.moc"
|
||||
130
plugins/patman/patman.h
Normal file
130
plugins/patman/patman.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* patman.h - header for a GUS-compatible patch instrument plugin
|
||||
*
|
||||
* Copyright (c) 2007 Javier Serrano Polo <jasp00/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _PATMAN_H_
|
||||
#define _PATMAN_H_
|
||||
|
||||
|
||||
#include "instrument.h"
|
||||
#include "sample_buffer.h"
|
||||
#include "spc_bg_hndl_widget.h"
|
||||
|
||||
|
||||
class pixmapButton;
|
||||
|
||||
|
||||
#define MODES_16BIT ( 1 << 0 )
|
||||
#define MODES_UNSIGNED ( 1 << 1 )
|
||||
#define MODES_LOOPING ( 1 << 2 )
|
||||
#define MODES_PINGPONG ( 1 << 3 )
|
||||
#define MODES_REVERSE ( 1 << 4 )
|
||||
#define MODES_SUSTAIN ( 1 << 5 )
|
||||
#define MODES_ENVELOPE ( 1 << 6 )
|
||||
#define MODES_CLAMPED ( 1 << 7 )
|
||||
|
||||
|
||||
class patmanSynth : public instrument, public specialBgHandlingWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
class subPluginFeatures : public plugin::descriptor::subPluginFeatures
|
||||
{
|
||||
public:
|
||||
subPluginFeatures( plugin::pluginTypes _type );
|
||||
|
||||
virtual const QStringList & supportedExtensions( void )
|
||||
{
|
||||
return( supported_extensions() );
|
||||
}
|
||||
|
||||
static const QStringList & supported_extensions( void );
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
patmanSynth( instrumentTrack * _track );
|
||||
virtual ~patmanSynth();
|
||||
|
||||
virtual void FASTCALL playNote( notePlayHandle * _n,
|
||||
bool _try_parallelizing );
|
||||
virtual void FASTCALL deleteNotePluginData( notePlayHandle * _n );
|
||||
|
||||
|
||||
virtual void FASTCALL saveSettings( QDomDocument & _doc,
|
||||
QDomElement & _parent );
|
||||
virtual void FASTCALL loadSettings( const QDomElement & _this );
|
||||
|
||||
virtual void FASTCALL setParameter( const QString & _param,
|
||||
const QString & _value );
|
||||
|
||||
virtual QString nodeName( void ) const;
|
||||
|
||||
|
||||
public slots:
|
||||
void openFile( void );
|
||||
void setFile( const QString & _patch_file, bool _rename = TRUE );
|
||||
|
||||
|
||||
protected:
|
||||
virtual void dragEnterEvent( QDragEnterEvent * _dee );
|
||||
virtual void dropEvent( QDropEvent * _de );
|
||||
virtual void paintEvent( QPaintEvent * );
|
||||
|
||||
|
||||
private:
|
||||
typedef struct
|
||||
{
|
||||
sampleBuffer::handleState * state;
|
||||
bool tuned;
|
||||
sampleBuffer * sample;
|
||||
} handle_data;
|
||||
|
||||
QString m_patchFile;
|
||||
vvector<sampleBuffer *> m_patch_samples;
|
||||
|
||||
pixmapButton * m_openFileButton;
|
||||
pixmapButton * m_loopButton;
|
||||
pixmapButton * m_tuneButton;
|
||||
QString m_display_filename;
|
||||
|
||||
enum load_error
|
||||
{
|
||||
LOAD_OK,
|
||||
LOAD_OPEN,
|
||||
LOAD_NOT_GUS,
|
||||
LOAD_INSTRUMENTS,
|
||||
LOAD_LAYERS,
|
||||
LOAD_IO
|
||||
} ;
|
||||
|
||||
load_error load_patch( const QString & _filename );
|
||||
void unload_current_patch( void );
|
||||
|
||||
void select_sample( notePlayHandle * _n );
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
#endif
|
||||
BIN
plugins/patman/tune_off.png
Normal file
BIN
plugins/patman/tune_off.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 611 B |
BIN
plugins/patman/tune_on.png
Normal file
BIN
plugins/patman/tune_on.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 623 B |
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* polyb302.cpp - implementation of class polyb302 which is a bass synth
|
||||
* attempting to emulate the Roland TB303 bass synth
|
||||
* polyb302.cpp - implementation of instrument polyb302, an attempt to emulate
|
||||
* the Roland TB303 bass synth
|
||||
*
|
||||
* Copyright (c) 2006-2007 Paul Giblock <pgib/at/users.sourceforge.net>
|
||||
*
|
||||
@@ -28,28 +28,12 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qt3support.h"
|
||||
|
||||
#ifdef QT4
|
||||
|
||||
#include <Qt/QtXml>
|
||||
|
||||
#else
|
||||
|
||||
#include <qdom.h>
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#include "polyb302.h"
|
||||
#include "audio_device.h"
|
||||
#include "instrument_track.h"
|
||||
#include "instrument_play_handle.h"
|
||||
#include "led_checkbox.h"
|
||||
#include "note_play_handle.h"
|
||||
#include "templates.h"
|
||||
#include "buffer_allocator.h"
|
||||
#include "knob.h"
|
||||
#include "led_checkbox.h"
|
||||
#include "note_play_handle.h"
|
||||
|
||||
#undef SINGLE_SOURCE_COMPILE
|
||||
#include "embed.cpp"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* polyb302.h - declaration of class polyb302 which is a bass synth attempting
|
||||
* to emulate the Roland TB303 bass synth
|
||||
* polyb302.h - declaration of instrument polyb302, an attempt to emulate the
|
||||
* Roland TB303 bass synth
|
||||
*
|
||||
* Copyright (c) 2006-2007 Paul Giblock <pgib/at/users.sourceforge.net>
|
||||
*
|
||||
|
||||
@@ -147,7 +147,9 @@ void singerBot::playNote( notePlayHandle * _n, bool )
|
||||
sampleBuffer * sample_buffer = hdata->remaining_frames ?
|
||||
readWave( hdata ) : new sampleBuffer( NULL, 0, eng() );
|
||||
|
||||
if( sample_buffer->play( buf, 0, frames ) )
|
||||
sampleBuffer::handleState hstate;
|
||||
|
||||
if( sample_buffer->play( buf, &hstate, frames ) )
|
||||
{
|
||||
getInstrumentTrack()->processAudioBuffer( buf, frames, _n );
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* engine.cpp - implementation of LMMS' engine-system
|
||||
*
|
||||
* Copyright (c) 2006 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
* Copyright (c) 2006-2007 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
@@ -52,6 +52,8 @@ engine::engine( const bool _has_gui ) :
|
||||
m_pianoRoll( NULL ),
|
||||
m_projectJournal( NULL )
|
||||
{
|
||||
load_extensions();
|
||||
|
||||
m_projectJournal = new projectJournal( this );
|
||||
m_mainWindow = new mainWindow( this );
|
||||
m_mixer = new mixer( this );
|
||||
@@ -123,6 +125,35 @@ void engine::updateFramesPerTact64th( void )
|
||||
|
||||
|
||||
|
||||
void engine::load_extensions( void )
|
||||
{
|
||||
vvector<plugin::descriptor> pluginDescriptors;
|
||||
plugin::getDescriptorsOfAvailPlugins( pluginDescriptors );
|
||||
for( vvector<plugin::descriptor>::iterator it =
|
||||
pluginDescriptors.begin();
|
||||
it != pluginDescriptors.end(); ++it )
|
||||
{
|
||||
if( it->sub_plugin_features )
|
||||
{
|
||||
if( it->type == plugin::Instrument )
|
||||
{
|
||||
const QStringList & ext =
|
||||
it->sub_plugin_features
|
||||
->supportedExtensions();
|
||||
for( QStringList::const_iterator itExt =
|
||||
ext.begin();
|
||||
itExt != ext.end(); ++itExt )
|
||||
{
|
||||
m_sample_extensions[*itExt] = it->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
engineObject::engineObject( engine * _engine ) :
|
||||
m_engine( _engine )
|
||||
|
||||
@@ -179,7 +179,7 @@ void fileBrowser::addItems( const QString & _path )
|
||||
{
|
||||
// remove existing file-items
|
||||
delete m_l->findItem( cur_file, 0 );
|
||||
(void) new fileItem( m_l, cur_file, _path );
|
||||
(void) new fileItem( m_l, cur_file, _path, eng() );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ void fileBrowser::addItems( const QString & _path )
|
||||
if( item == NULL )
|
||||
{
|
||||
(void) new directory( m_l, cur_file, _path,
|
||||
m_filter );
|
||||
m_filter, eng() );
|
||||
}
|
||||
else if( dynamic_cast<directory *>( item ) != NULL )
|
||||
{
|
||||
@@ -333,7 +333,9 @@ void fileBrowser::sendToActiveInstrumentTrack( void )
|
||||
fileItem::SAMPLE_FILE )
|
||||
{
|
||||
instrument * afp = ct->loadInstrument(
|
||||
"audiofileprocessor" );
|
||||
eng()->sampleExtensions()
|
||||
[m_contextMenuItem
|
||||
->extension()] );
|
||||
if( afp != NULL )
|
||||
{
|
||||
afp->setParameter( "samplefile",
|
||||
@@ -372,7 +374,9 @@ void fileBrowser::openInNewInstrumentTrack( trackContainer * _tc )
|
||||
#ifdef LMMS_DEBUG
|
||||
assert( ct != NULL );
|
||||
#endif
|
||||
instrument * afp = ct->loadInstrument( "audiofileprocessor" );
|
||||
instrument * afp = ct->loadInstrument( eng()->sampleExtensions()
|
||||
[m_contextMenuItem
|
||||
->extension()] );
|
||||
if( afp != NULL )
|
||||
{
|
||||
afp->setParameter( "samplefile",
|
||||
@@ -461,7 +465,7 @@ void listView::contentsMouseDoubleClickEvent( QMouseEvent * _me )
|
||||
assert( it != NULL );
|
||||
#endif
|
||||
instrument * afp = it->loadInstrument(
|
||||
"audiofileprocessor" );
|
||||
eng()->sampleExtensions()[f->extension()] );
|
||||
if( afp != NULL )
|
||||
{
|
||||
afp->setParameter( "samplefile",
|
||||
@@ -649,8 +653,10 @@ QPixmap * directory::s_folderLockedPixmap = NULL;
|
||||
|
||||
|
||||
directory::directory( directory * _parent, const QString & _name,
|
||||
const QString & _path, const QString & _filter ) :
|
||||
const QString & _path, const QString & _filter,
|
||||
engine * _engine ) :
|
||||
Q3ListViewItem( _parent, _name ),
|
||||
engineObject( _engine ),
|
||||
m_p( _parent ),
|
||||
m_pix( NULL ),
|
||||
m_directories( _path ),
|
||||
@@ -663,8 +669,10 @@ directory::directory( directory * _parent, const QString & _name,
|
||||
|
||||
|
||||
directory::directory( Q3ListView * _parent, const QString & _name,
|
||||
const QString & _path, const QString & _filter ) :
|
||||
const QString & _path, const QString & _filter,
|
||||
engine * _engine ) :
|
||||
Q3ListViewItem( _parent, _name ),
|
||||
engineObject( _engine ),
|
||||
m_p( NULL ),
|
||||
m_pix( NULL ),
|
||||
m_directories( _path ),
|
||||
@@ -789,7 +797,7 @@ bool directory::addItems( const QString & _path )
|
||||
#endif
|
||||
/*QDir::match( FILE_FILTER, cur_file )*/ )
|
||||
{
|
||||
(void) new fileItem( this, cur_file, _path );
|
||||
(void) new fileItem( this, cur_file, _path, eng() );
|
||||
added_something = TRUE;
|
||||
}
|
||||
}
|
||||
@@ -806,7 +814,7 @@ bool directory::addItems( const QString & _path )
|
||||
#endif
|
||||
cur_file, m_filter ) )
|
||||
{
|
||||
new directory( this, cur_file, _path, m_filter );
|
||||
new directory( this, cur_file, _path, m_filter, eng() );
|
||||
added_something = TRUE;
|
||||
#if 0
|
||||
if( firstChild() == NULL )
|
||||
@@ -852,8 +860,10 @@ QPixmap * fileItem::s_unknownFilePixmap = NULL;
|
||||
|
||||
|
||||
fileItem::fileItem( Q3ListView * _parent, const QString & _name,
|
||||
const QString & _path ) :
|
||||
const QString & _path,
|
||||
engine * _engine ) :
|
||||
Q3ListViewItem( _parent, _name ),
|
||||
engineObject( _engine ),
|
||||
m_pix( NULL ),
|
||||
m_path( _path )
|
||||
{
|
||||
@@ -866,8 +876,10 @@ fileItem::fileItem( Q3ListView * _parent, const QString & _name,
|
||||
|
||||
|
||||
fileItem::fileItem( Q3ListViewItem * _parent, const QString & _name,
|
||||
const QString & _path ) :
|
||||
const QString & _path,
|
||||
engine * _engine ) :
|
||||
Q3ListViewItem( _parent, _name ),
|
||||
engineObject( _engine ),
|
||||
m_pix( NULL ),
|
||||
m_path( _path )
|
||||
{
|
||||
@@ -936,11 +948,7 @@ void fileItem::initPixmapStuff( void )
|
||||
|
||||
void fileItem::determineFileType( void )
|
||||
{
|
||||
#ifdef QT4
|
||||
QString ext = QFileInfo( fullName() ).suffix().toLower();
|
||||
#else
|
||||
QString ext = QFileInfo( fullName() ).extension( FALSE ).toLower();
|
||||
#endif
|
||||
QString ext = extension();
|
||||
if( ext == "mmp" || ext == "mpt" || ext == "mmpz" )
|
||||
{
|
||||
m_type = PROJECT_FILE;
|
||||
@@ -966,10 +974,7 @@ void fileItem::determineFileType( void )
|
||||
{
|
||||
m_type = PRESET_FILE;
|
||||
}
|
||||
else if( ext == "wav" || ext == "ogg" || ext == "mp3" ||
|
||||
ext == "aiff" || ext == "aif" || ext == "voc" ||
|
||||
ext == "au" || ext == "raw" || ext == "flac" ||
|
||||
ext == "spx" )
|
||||
else if( eng()->sampleExtensions().contains( ext ) )
|
||||
{
|
||||
m_type = SAMPLE_FILE;
|
||||
}
|
||||
@@ -990,6 +995,25 @@ void fileItem::determineFileType( void )
|
||||
|
||||
|
||||
|
||||
QString fileItem::extension( void )
|
||||
{
|
||||
return( extension( fullName() ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
QString fileItem::extension( const QString & _file )
|
||||
{
|
||||
#ifdef QT4
|
||||
return( QFileInfo( _file ).suffix().toLower() );
|
||||
#else
|
||||
return( QFileInfo( _file ).extension( FALSE ).toLower() );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#include "file_browser.moc"
|
||||
|
||||
|
||||
@@ -128,6 +128,14 @@ mainWindow::mainWindow( engine * _engine ) :
|
||||
splitter->setChildrenCollapsible( FALSE );
|
||||
#endif
|
||||
|
||||
QString sample_filter;
|
||||
vlist<QString> ext_keys = eng()->sampleExtensions().keys();
|
||||
for( vlist<QString>::iterator it = ext_keys.begin();
|
||||
it != ext_keys.end(); ++it )
|
||||
{
|
||||
sample_filter += " *." + *it;
|
||||
}
|
||||
|
||||
int id = 0;
|
||||
QString wdir = configManager::inst()->workingDir();
|
||||
side_bar->appendTab( new pluginBrowser( splitter, eng() ), ++id );
|
||||
@@ -142,9 +150,7 @@ mainWindow::mainWindow( engine * _engine ) :
|
||||
side_bar->appendTab( new fileBrowser(
|
||||
configManager::inst()->factorySamplesDir() + "*" +
|
||||
configManager::inst()->userSamplesDir(),
|
||||
"*.wav *.ogg *.spx *.au"
|
||||
"*.voc *.aif *.aiff *.flac *.raw",
|
||||
tr( "My samples" ),
|
||||
sample_filter, tr( "My samples" ),
|
||||
embed::getIconPixmap( "sound_file" ),
|
||||
splitter, eng() ),
|
||||
++id );
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* sample_play_handle.cpp - implementation of class samplePlayHandle
|
||||
*
|
||||
* Copyright (c) 2005-2006 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
* Copyright (c) 2005-2007 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
@@ -144,7 +144,7 @@ void samplePlayHandle::play( const fpab_t _frame_base, bool )
|
||||
, m_volume, m_volume
|
||||
#endif
|
||||
} } ;
|
||||
m_sampleBuffer->play( buf, m_frame, frames );
|
||||
m_sampleBuffer->play( buf, &m_state, frames );
|
||||
eng()->getMixer()->bufferToPort( buf, frames, _frame_base, v,
|
||||
m_audioPort );
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* track_container.cpp - implementation of base-class for all track-containers
|
||||
* like Song-Editor, BB-Editor...
|
||||
*
|
||||
* Copyright (c) 2004-2006 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
* Copyright (c) 2004-2007 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
@@ -345,13 +345,14 @@ void trackContainer::clearAllTracks( void )
|
||||
|
||||
const trackWidget * trackContainer::trackWidgetAt( const int _y ) const
|
||||
{
|
||||
const int abs_y = _y + m_scrollArea->contentsY();
|
||||
int y_cnt = 0;
|
||||
for( trackWidgetVector::const_iterator it = m_trackWidgets.begin();
|
||||
it != m_trackWidgets.end(); ++it )
|
||||
{
|
||||
const int y_cnt1 = y_cnt;
|
||||
y_cnt += ( *it )->height();
|
||||
if( _y >= y_cnt1 && _y < y_cnt )
|
||||
if( abs_y >= y_cnt1 && abs_y < y_cnt )
|
||||
{
|
||||
return( *it );
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* sample_buffer.cpp - container-class sampleBuffer
|
||||
*
|
||||
* Copyright (c) 2005-2006 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
* Copyright (c) 2005-2007 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
@@ -111,9 +111,13 @@ sampleBuffer::sampleBuffer( engine * _engine, const QString & _audio_file,
|
||||
m_frames( 0 ),
|
||||
m_startFrame( 0 ),
|
||||
m_endFrame( 0 ),
|
||||
m_loop_startFrame( 0 ),
|
||||
m_loop_endFrame( 0 ),
|
||||
m_amplification( 1.0f ),
|
||||
m_reversed( FALSE ),
|
||||
m_dataMutex()
|
||||
m_frequency( BASE_FREQ ),
|
||||
m_dataMutex(),
|
||||
m_sample_fragment( NULL )
|
||||
{
|
||||
#ifdef SDL_SDL_SOUND_H
|
||||
// init sound-file-system of SDL
|
||||
@@ -143,9 +147,13 @@ sampleBuffer::sampleBuffer( const sampleFrame * _data, const f_cnt_t _frames,
|
||||
m_frames( 0 ),
|
||||
m_startFrame( 0 ),
|
||||
m_endFrame( 0 ),
|
||||
m_loop_startFrame( 0 ),
|
||||
m_loop_endFrame( 0 ),
|
||||
m_amplification( 1.0f ),
|
||||
m_reversed( FALSE ),
|
||||
m_dataMutex()
|
||||
m_frequency( BASE_FREQ ),
|
||||
m_dataMutex(),
|
||||
m_sample_fragment( NULL )
|
||||
{
|
||||
m_origData = new sampleFrame[_frames];
|
||||
memcpy( m_origData, _data, _frames * BYTES_PER_FRAME );
|
||||
@@ -173,9 +181,13 @@ sampleBuffer::sampleBuffer( const f_cnt_t _frames, engine * _engine ) :
|
||||
m_frames( 0 ),
|
||||
m_startFrame( 0 ),
|
||||
m_endFrame( 0 ),
|
||||
m_loop_startFrame( 0 ),
|
||||
m_loop_endFrame( 0 ),
|
||||
m_amplification( 1.0f ),
|
||||
m_reversed( FALSE ),
|
||||
m_dataMutex()
|
||||
m_frequency( BASE_FREQ ),
|
||||
m_dataMutex(),
|
||||
m_sample_fragment( NULL )
|
||||
{
|
||||
m_origData = new sampleFrame[_frames];
|
||||
memset( m_origData, 0, _frames * BYTES_PER_FRAME );
|
||||
@@ -201,11 +213,12 @@ sampleBuffer::~sampleBuffer()
|
||||
delete[] m_data;
|
||||
m_data = NULL;
|
||||
|
||||
#ifdef HAVE_SAMPLERATE_H
|
||||
quitResampling();
|
||||
#endif
|
||||
|
||||
m_dataMutex.unlock();
|
||||
|
||||
if( m_sample_fragment )
|
||||
{
|
||||
delete[] m_sample_fragment;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -230,32 +243,13 @@ void sampleBuffer::update( bool _keep_settings )
|
||||
if( _keep_settings == FALSE )
|
||||
{
|
||||
m_frames = m_origFrames;
|
||||
m_startFrame = 0;
|
||||
if( m_frames > 0 )
|
||||
{
|
||||
m_endFrame = m_frames - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_endFrame = 0;
|
||||
}
|
||||
m_loop_startFrame = m_startFrame = 0;
|
||||
m_loop_endFrame = m_endFrame = m_frames;
|
||||
}
|
||||
}
|
||||
else if( m_audioFile != "" )
|
||||
{
|
||||
QString file = m_audioFile;
|
||||
// if there's not an absolute filename, we assume that we made
|
||||
// it relative before and so we have to add sample-dir to file-
|
||||
// name
|
||||
if( file[0] != '/' )
|
||||
{
|
||||
file = configManager::inst()->userSamplesDir() + file;
|
||||
if( QFileInfo( file ).exists() == FALSE )
|
||||
{
|
||||
file =
|
||||
configManager::inst()->factorySamplesDir() + m_audioFile;
|
||||
}
|
||||
}
|
||||
QString file = tryToMakeAbsolute( m_audioFile );
|
||||
const char * f =
|
||||
#ifdef QT4
|
||||
file.toAscii().constData();
|
||||
@@ -328,34 +322,7 @@ m_data[frame][chnl] = buf[idx] * fac;
|
||||
|
||||
delete[] buf;
|
||||
|
||||
// do samplerate-conversion if sample-decoder didn't
|
||||
// convert sample-rate to our default-samplerate
|
||||
if( samplerate != SAMPLE_RATES[DEFAULT_QUALITY_LEVEL] )
|
||||
{
|
||||
sampleBuffer * resampled = resample( this,
|
||||
samplerate,
|
||||
SAMPLE_RATES[DEFAULT_QUALITY_LEVEL] );
|
||||
delete[] m_data;
|
||||
m_frames = resampled->frames();
|
||||
m_data = new sampleFrame[m_frames];
|
||||
memcpy( m_data, resampled->data(), m_frames *
|
||||
sizeof( sampleFrame ) );
|
||||
delete resampled;
|
||||
}
|
||||
|
||||
if( _keep_settings == FALSE )
|
||||
{
|
||||
// update frame-variables
|
||||
m_startFrame = 0;
|
||||
if( m_frames > 0 )
|
||||
{
|
||||
m_endFrame = m_frames - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_endFrame = 0;
|
||||
}
|
||||
}
|
||||
normalize_sample_rate( samplerate, _keep_settings );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -364,8 +331,8 @@ m_data[frame][chnl] = buf[idx] * fac;
|
||||
m_data = new sampleFrame[1];
|
||||
memset( m_data, 0, sizeof( *m_data ) );
|
||||
m_frames = 1;
|
||||
m_startFrame = 0;
|
||||
m_endFrame = 1;
|
||||
m_loop_startFrame = m_startFrame = 0;
|
||||
m_loop_endFrame = m_endFrame = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -375,8 +342,8 @@ m_data[frame][chnl] = buf[idx] * fac;
|
||||
m_data = new sampleFrame[1];
|
||||
memset( m_data, 0, sizeof( *m_data ) * 1 );
|
||||
m_frames = 1;
|
||||
m_startFrame = 0;
|
||||
m_endFrame = 1;
|
||||
m_loop_startFrame = m_startFrame = 0;
|
||||
m_loop_endFrame = m_endFrame = 1;
|
||||
}
|
||||
|
||||
m_dataMutex.unlock();
|
||||
@@ -387,6 +354,33 @@ m_data[frame][chnl] = buf[idx] * fac;
|
||||
|
||||
|
||||
|
||||
void sampleBuffer::normalize_sample_rate( const sample_rate_t _src_sr,
|
||||
bool _keep_settings )
|
||||
{
|
||||
// do samplerate-conversion to our default-samplerate
|
||||
if( _src_sr != SAMPLE_RATES[DEFAULT_QUALITY_LEVEL] )
|
||||
{
|
||||
sampleBuffer * resampled = resample( this, _src_sr,
|
||||
SAMPLE_RATES[DEFAULT_QUALITY_LEVEL] );
|
||||
delete[] m_data;
|
||||
m_frames = resampled->frames();
|
||||
m_data = new sampleFrame[m_frames];
|
||||
memcpy( m_data, resampled->data(), m_frames *
|
||||
sizeof( sampleFrame ) );
|
||||
delete resampled;
|
||||
}
|
||||
|
||||
if( _keep_settings == FALSE )
|
||||
{
|
||||
// update frame-variables
|
||||
m_loop_startFrame = m_startFrame = 0;
|
||||
m_loop_endFrame = m_endFrame = m_frames;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef SDL_SDL_SOUND_H
|
||||
f_cnt_t sampleBuffer::decodeSampleSDL( const char * _f,
|
||||
int_sample_t * & _buf,
|
||||
@@ -617,54 +611,17 @@ f_cnt_t sampleBuffer::decodeSampleOGGVorbis( const char * _f,
|
||||
#ifdef HAVE_SAMPLERATE_H
|
||||
void sampleBuffer::initResampling( void )
|
||||
{
|
||||
m_srcState = createResamplingContext();
|
||||
m_srcData.end_of_input = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void sampleBuffer::quitResampling( void )
|
||||
{
|
||||
destroyResamplingContext( m_srcState );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
SRC_STATE * sampleBuffer::createResamplingContext( void )
|
||||
{
|
||||
int error;
|
||||
SRC_STATE * state;
|
||||
if( ( state = src_new(/*
|
||||
( eng()->getMixer()->highQuality() == TRUE ) ?
|
||||
SRC_SINC_FASTEST :*/
|
||||
SRC_LINEAR,
|
||||
DEFAULT_CHANNELS, &error ) ) == NULL )
|
||||
{
|
||||
printf( "Error: src_new() failed in sample_buffer.cpp!\n" );
|
||||
}
|
||||
return( state );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void sampleBuffer::destroyResamplingContext( SRC_STATE * _context )
|
||||
{
|
||||
src_delete( _context );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
bool FASTCALL sampleBuffer::play( sampleFrame * _ab,
|
||||
const f_cnt_t _start_frame,
|
||||
bool FASTCALL sampleBuffer::play( sampleFrame * _ab, handleState * _state,
|
||||
const fpab_t _frames,
|
||||
const float _freq,
|
||||
const bool _looped,
|
||||
void * * _resampling_data )
|
||||
const bool _looped )
|
||||
{
|
||||
eng()->getMixer()->clearAudioBuffer( _ab, _frames );
|
||||
|
||||
@@ -673,10 +630,7 @@ bool FASTCALL sampleBuffer::play( sampleFrame * _ab,
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
const double freq_factor = (double) _freq / (double) BASE_FREQ;
|
||||
const Sint16 freq_diff = static_cast<Sint16>( BASE_FREQ - _freq );
|
||||
|
||||
fpab_t frames_to_process = _frames;
|
||||
const double freq_factor = (double) _freq / (double) m_frequency;
|
||||
|
||||
// calculate how many frames we have in requested pitch
|
||||
const f_cnt_t total_frames_for_current_pitch = static_cast<f_cnt_t>( (
|
||||
@@ -687,31 +641,41 @@ bool FASTCALL sampleBuffer::play( sampleFrame * _ab,
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
// do we have frames left?? this is only important when not in
|
||||
// looping-mode because in looping-mode we loop to start-frame...
|
||||
if( _start_frame >= total_frames_for_current_pitch && _looped == FALSE )
|
||||
// this holds the number of the first frame to play
|
||||
f_cnt_t play_frame = _state->m_frame_index;
|
||||
if( play_frame < m_startFrame )
|
||||
{
|
||||
return( FALSE );
|
||||
play_frame = m_startFrame;
|
||||
}
|
||||
|
||||
// this holds the number of the first frame to play
|
||||
const f_cnt_t play_frame = m_startFrame + ( _start_frame %
|
||||
total_frames_for_current_pitch );
|
||||
|
||||
// this holds the number of remaining frames in current loop
|
||||
f_cnt_t frames_for_loop = total_frames_for_current_pitch -
|
||||
( play_frame - m_startFrame );
|
||||
f_cnt_t frames_for_loop;
|
||||
if( _looped )
|
||||
{
|
||||
play_frame = getLoopedIndex( play_frame );
|
||||
frames_for_loop = static_cast<f_cnt_t>(
|
||||
( m_loop_endFrame - play_frame ) /
|
||||
freq_factor );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( play_frame >= m_endFrame )
|
||||
{
|
||||
return( FALSE );
|
||||
}
|
||||
frames_for_loop = static_cast<f_cnt_t>(
|
||||
( m_endFrame - play_frame ) /
|
||||
freq_factor );
|
||||
if( frames_for_loop == 0 )
|
||||
{
|
||||
return( FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
// make sure, data isn't accessed in any other way (e.g. deleting
|
||||
// of this buffer...)
|
||||
m_dataMutex.lock();
|
||||
|
||||
if( _looped == FALSE && frames_for_loop < frames_to_process )
|
||||
{
|
||||
frames_to_process = frames_for_loop;
|
||||
}
|
||||
const f_cnt_t f1 = static_cast<f_cnt_t>( m_startFrame +
|
||||
( play_frame - m_startFrame ) * freq_factor );
|
||||
/* Uint32 f2 = 0;
|
||||
while( f2 < f1 )
|
||||
{
|
||||
@@ -723,76 +687,40 @@ bool FASTCALL sampleBuffer::play( sampleFrame * _ab,
|
||||
}*/
|
||||
// static int foo = 0;
|
||||
// calc pointer of first frame
|
||||
sampleFrame * start_frame = (sampleFrame *) m_data + f1;
|
||||
//printf("diff:%d %f %d f2: %d input: %d\n", f2 -foo, play_frame * freq_factor, static_cast<Uint32>( play_frame * freq_factor ), f2, (Uint32)( frames_for_loop * freq_factor ) );
|
||||
// foo = f2;
|
||||
sampleFrame * loop_start = (sampleFrame *) m_data + m_startFrame;
|
||||
|
||||
// check whether we have to change pitch...
|
||||
if( freq_diff != 0 )
|
||||
if( _freq != m_frequency || _state->m_varying_pitch )
|
||||
{
|
||||
#ifdef HAVE_SAMPLERATE_H
|
||||
SRC_STATE * state = m_srcState;
|
||||
if( _resampling_data != NULL )
|
||||
// Generate output
|
||||
const f_cnt_t margin = 64;
|
||||
f_cnt_t fragment_size = (f_cnt_t)( _frames * freq_factor )
|
||||
+ margin;
|
||||
m_srcData.data_in = getSampleFragment( play_frame,
|
||||
fragment_size, _looped )[0];
|
||||
m_srcData.data_out = _ab[0];
|
||||
m_srcData.input_frames = fragment_size;
|
||||
m_srcData.output_frames = _frames;
|
||||
m_srcData.src_ratio = 1.0 / freq_factor;
|
||||
int error = src_process( _state->m_resampling_data,
|
||||
&m_srcData );
|
||||
if( error )
|
||||
{
|
||||
if( *_resampling_data == NULL )
|
||||
{
|
||||
*_resampling_data = createResamplingContext();
|
||||
}
|
||||
state = static_cast<SRC_STATE *>( *_resampling_data );
|
||||
}
|
||||
|
||||
// Check loop
|
||||
if( _looped && frames_for_loop < frames_to_process )
|
||||
{
|
||||
f_cnt_t total_frames_copied = 0;
|
||||
while( total_frames_copied < frames_to_process )
|
||||
{
|
||||
// Generate output
|
||||
m_srcData.data_in = start_frame[0];
|
||||
m_srcData.data_out = _ab[total_frames_copied];
|
||||
m_srcData.input_frames = static_cast<f_cnt_t>(
|
||||
frames_for_loop * freq_factor );
|
||||
m_srcData.output_frames = frames_for_loop;
|
||||
m_srcData.src_ratio = 1.0 / freq_factor;
|
||||
int error = src_process( state, &m_srcData );
|
||||
if( error )
|
||||
{
|
||||
printf( "sampleBuffer: error while "
|
||||
"resampling: %s\n",
|
||||
printf( "sampleBuffer: error while resampling: %s\n",
|
||||
src_strerror( error ) );
|
||||
}
|
||||
// Advance
|
||||
total_frames_copied += frames_for_loop;
|
||||
|
||||
// reset start_frame to start
|
||||
start_frame = loop_start;
|
||||
// and calculate frames for next loop
|
||||
frames_for_loop = frames_to_process
|
||||
- total_frames_copied;
|
||||
if( frames_for_loop
|
||||
> total_frames_for_current_pitch )
|
||||
{
|
||||
frames_for_loop =
|
||||
total_frames_for_current_pitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if( m_srcData.output_frames_gen != _frames )
|
||||
{
|
||||
// Generate output
|
||||
m_srcData.data_in = start_frame[0];
|
||||
m_srcData.data_out = _ab[0];
|
||||
m_srcData.input_frames = static_cast<f_cnt_t>(
|
||||
frames_for_loop * freq_factor );
|
||||
m_srcData.output_frames = frames_to_process;
|
||||
m_srcData.src_ratio = 1.0 / freq_factor;
|
||||
int error = src_process( state, &m_srcData );
|
||||
if( error )
|
||||
{
|
||||
printf( "sampleBuffer: error while resampling: "
|
||||
"%s\n", src_strerror( error ) );
|
||||
}
|
||||
printf( "sampleBuffer: not enough frames: %ld / %d\n",
|
||||
m_srcData.output_frames_gen, _frames );
|
||||
}
|
||||
// Advance
|
||||
play_frame += m_srcData.input_frames_used;
|
||||
if( _looped )
|
||||
{
|
||||
play_frame = getLoopedIndex( play_frame );
|
||||
}
|
||||
#else
|
||||
f_cnt_t src_frame_base = 0;
|
||||
@@ -876,41 +804,21 @@ bool FASTCALL sampleBuffer::play( sampleFrame * _ab,
|
||||
// we don't have to pitch, so we just copy the sample-data
|
||||
// as is into pitched-copy-buffer
|
||||
|
||||
// Check loop
|
||||
if( _looped && frames_for_loop < frames_to_process )
|
||||
// Generate output
|
||||
memcpy( _ab, getSampleFragment( play_frame, _frames, _looped ),
|
||||
_frames * BYTES_PER_FRAME );
|
||||
// Advance
|
||||
play_frame += _frames;
|
||||
if( _looped )
|
||||
{
|
||||
f_cnt_t total_frames_copied = 0;
|
||||
while( total_frames_copied < frames_to_process )
|
||||
{
|
||||
// Generate output
|
||||
memcpy( _ab[total_frames_copied], start_frame,
|
||||
frames_for_loop * BYTES_PER_FRAME );
|
||||
// Advance
|
||||
total_frames_copied += frames_for_loop;
|
||||
|
||||
// reset start_frame to start
|
||||
start_frame = loop_start;
|
||||
// and calculate frames for next loop
|
||||
frames_for_loop = frames_to_process
|
||||
- total_frames_copied;
|
||||
if( frames_for_loop
|
||||
> total_frames_for_current_pitch )
|
||||
{
|
||||
frames_for_loop =
|
||||
total_frames_for_current_pitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Generate output
|
||||
memcpy( _ab, start_frame,
|
||||
frames_to_process * BYTES_PER_FRAME );
|
||||
play_frame = getLoopedIndex( play_frame );
|
||||
}
|
||||
}
|
||||
|
||||
m_dataMutex.unlock();
|
||||
|
||||
_state->m_frame_index = play_frame;
|
||||
|
||||
return( TRUE );
|
||||
|
||||
}
|
||||
@@ -918,6 +826,73 @@ bool FASTCALL sampleBuffer::play( sampleFrame * _ab,
|
||||
|
||||
|
||||
|
||||
sampleFrame * sampleBuffer::getSampleFragment( f_cnt_t _start,
|
||||
f_cnt_t _frames, bool _looped )
|
||||
{
|
||||
if( _looped )
|
||||
{
|
||||
if( _start + _frames <= m_loop_endFrame )
|
||||
{
|
||||
return( m_data + _start );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( _start + _frames <= m_endFrame )
|
||||
{
|
||||
return( m_data + _start );
|
||||
}
|
||||
}
|
||||
|
||||
if( m_sample_fragment )
|
||||
{
|
||||
delete[] m_sample_fragment;
|
||||
}
|
||||
m_sample_fragment = new sampleFrame[_frames];
|
||||
|
||||
if( _looped )
|
||||
{
|
||||
f_cnt_t copied = m_loop_endFrame - _start;
|
||||
memcpy( m_sample_fragment, m_data + _start, copied
|
||||
* BYTES_PER_FRAME );
|
||||
f_cnt_t loop_frames = m_loop_endFrame - m_loop_startFrame;
|
||||
while( _frames - copied > 0 )
|
||||
{
|
||||
f_cnt_t todo = tMin( _frames - copied, loop_frames );
|
||||
memcpy( m_sample_fragment + copied,
|
||||
m_data + m_loop_startFrame,
|
||||
todo * BYTES_PER_FRAME );
|
||||
copied += todo;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
f_cnt_t available = m_endFrame - _start;
|
||||
memcpy( m_sample_fragment, m_data + _start, available
|
||||
* BYTES_PER_FRAME );
|
||||
memset( m_sample_fragment + available, 0, ( _frames -
|
||||
available ) * BYTES_PER_FRAME );
|
||||
}
|
||||
|
||||
return( m_sample_fragment );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
f_cnt_t sampleBuffer::getLoopedIndex( f_cnt_t _index )
|
||||
{
|
||||
if( _index < m_loop_endFrame )
|
||||
{
|
||||
return( _index );
|
||||
}
|
||||
return( m_loop_startFrame + ( _index - m_loop_startFrame )
|
||||
% ( m_loop_endFrame - m_loop_startFrame ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void sampleBuffer::visualize( QPainter & _p, const QRect & _dr,
|
||||
const QRect & _clip, drawMethods _dm )
|
||||
{
|
||||
@@ -1459,7 +1434,7 @@ void sampleBuffer::setStartFrame( const f_cnt_t _s )
|
||||
{
|
||||
// don't set this parameter while playing
|
||||
m_dataMutex.lock();
|
||||
m_startFrame = _s;
|
||||
m_loop_startFrame = m_startFrame = _s;
|
||||
m_dataMutex.unlock();
|
||||
}
|
||||
|
||||
@@ -1470,7 +1445,7 @@ void sampleBuffer::setEndFrame( const f_cnt_t _e )
|
||||
{
|
||||
// don't set this parameter while playing
|
||||
m_dataMutex.lock();
|
||||
m_endFrame = _e;
|
||||
m_loop_endFrame = m_endFrame = _e;
|
||||
m_dataMutex.unlock();
|
||||
}
|
||||
|
||||
@@ -1495,34 +1470,19 @@ void sampleBuffer::setReversed( bool _on )
|
||||
|
||||
|
||||
|
||||
void sampleBuffer::deleteResamplingData( void * * _ptr )
|
||||
{
|
||||
#ifdef HAVE_SAMPLERATE_H
|
||||
#ifdef LMMS_DEBUG
|
||||
assert( _ptr != NULL );
|
||||
assert( *_ptr != NULL );
|
||||
#endif
|
||||
destroyResamplingContext( static_cast<SRC_STATE *>( *_ptr ) );
|
||||
#endif
|
||||
*_ptr = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
QString sampleBuffer::tryToMakeRelative( const QString & _file )
|
||||
{
|
||||
if( QFileInfo( _file ).isRelative() == FALSE )
|
||||
{
|
||||
QString fsd = configManager::inst()->factorySamplesDir();
|
||||
QString usd = configManager::inst()->userSamplesDir();
|
||||
if( _file.contains( fsd ) )
|
||||
if( _file.startsWith( fsd ) )
|
||||
{
|
||||
return( QString( _file ).replace( fsd, "" ) );
|
||||
return( QString( _file ).mid( fsd.length() ) );
|
||||
}
|
||||
else if( _file.contains( usd ) )
|
||||
else if( _file.startsWith( usd ) )
|
||||
{
|
||||
return( QString( _file ).replace( usd, "" ) );
|
||||
return( QString( _file ).mid( usd.length() ) );
|
||||
}
|
||||
}
|
||||
return( _file );
|
||||
@@ -1530,6 +1490,60 @@ QString sampleBuffer::tryToMakeRelative( const QString & _file )
|
||||
|
||||
|
||||
|
||||
|
||||
QString sampleBuffer::tryToMakeAbsolute( const QString & _file )
|
||||
{
|
||||
if( _file[0] == '/' )
|
||||
{
|
||||
return( _file );
|
||||
}
|
||||
|
||||
QString f = configManager::inst()->userSamplesDir() + _file;
|
||||
if( QFileInfo( f ).exists() )
|
||||
{
|
||||
return( f );
|
||||
}
|
||||
|
||||
return( configManager::inst()->factorySamplesDir() + _file );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
sampleBuffer::handleState::handleState( bool _varying_pitch ) :
|
||||
m_frame_index( 0 ),
|
||||
m_varying_pitch( _varying_pitch )
|
||||
{
|
||||
#ifdef HAVE_SAMPLERATE_H
|
||||
int error;
|
||||
if( ( m_resampling_data = src_new(/*
|
||||
( eng()->getMixer()->highQuality() == TRUE ) ?
|
||||
SRC_SINC_FASTEST :*/
|
||||
SRC_LINEAR,
|
||||
DEFAULT_CHANNELS, &error ) ) == NULL )
|
||||
{
|
||||
printf( "Error: src_new() failed in sample_buffer.cpp!\n" );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
sampleBuffer::handleState::~handleState()
|
||||
{
|
||||
#ifdef HAVE_SAMPLERATE_H
|
||||
src_delete( m_resampling_data );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#undef write
|
||||
#undef read
|
||||
#undef pos
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* bb_track.cpp - implementation of class bbTrack and bbTCO
|
||||
*
|
||||
* Copyright (c) 2004-2006 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
* Copyright (c) 2004-2007 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
@@ -508,6 +508,8 @@ void bbTrack::loadTrackSpecificSettings( const QDomElement & _this )
|
||||
{
|
||||
m_trackLabel->setPixmapFile( _this.attribute( "icon" ) );
|
||||
}
|
||||
eng()->getBBEditor()->updateComboBox();
|
||||
|
||||
QDomNode node = _this.namedItem( trackContainer::classNodeName() );
|
||||
if( node.isElement() )
|
||||
{
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
/*
|
||||
* pattern.cpp - implementation of class pattern which holds notes
|
||||
*
|
||||
* Copyright (c) 2004-2006 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
* Copyright (c) 2005 Danny McRae <khjklujn/at/yahoo.com>
|
||||
* Copyright (c) 2004-2007 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
* Copyright (c) 2005-2007 Danny McRae <khjklujn/at/yahoo.com>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
@@ -88,6 +88,7 @@ pattern::pattern ( instrumentTrack * _instrument_track ) :
|
||||
m_patternType( BEAT_PATTERN ),
|
||||
m_name( _instrument_track->name() ),
|
||||
m_steps( DEFAULT_STEPS_PER_TACT ),
|
||||
//TODO: check mutex
|
||||
m_frozenPatternMutex(),
|
||||
m_frozenPattern( NULL ),
|
||||
m_freezing( FALSE ),
|
||||
@@ -399,21 +400,6 @@ void pattern::checkType( void )
|
||||
|
||||
|
||||
|
||||
//TODO: remove this method, check mutex
|
||||
void pattern::playFrozenData( sampleFrame * _ab, const f_cnt_t _start_frame,
|
||||
const fpab_t _frames )
|
||||
{
|
||||
m_frozenPatternMutex.lock();
|
||||
if( m_frozenPattern != NULL )
|
||||
{
|
||||
m_frozenPattern->play( _ab, _start_frame, _frames );
|
||||
}
|
||||
m_frozenPatternMutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void pattern::saveSettings( QDomDocument & _doc, QDomElement & _this )
|
||||
{
|
||||
_this.setAttribute( "type", m_patternType );
|
||||
|
||||
Reference in New Issue
Block a user