diff --git a/ChangeLog b/ChangeLog index 431d931e35..fc11e4b225 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,68 @@ +2007-04-07 Javier Serrano Polo + + * 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 * src/lmms_single_source.cpp: diff --git a/configure.in b/configure.in index c5a3ab63b0..10c0e87673 100644 --- a/configure.in +++ b/configure.in @@ -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 diff --git a/data/locale/ca.qm b/data/locale/ca.qm index 6d81a77672..9285e681aa 100644 Binary files a/data/locale/ca.qm and b/data/locale/ca.qm differ diff --git a/data/locale/ca.ts b/data/locale/ca.ts index 91f70f2fd8..8196519fc0 100644 --- a/data/locale/ca.ts +++ b/data/locale/ca.ts @@ -2703,6 +2703,45 @@ Per favor, visita http://wiki.mindrules.net per a documentació sobre LMMS.Aleatoritza + + patmanSynth + + Open other patch + Obre altre pedaç + + + Click here to open another patch-file. Loop and Tune settings are not reset. + Pica aquí per a obrir un altre fitxer pedaç. La configuració de Bucle i Afina no es reinicia. + + + Loop mode + Mode Bucle + + + Here you can toggle the Loop mode. If enabled, PatMan will use the loop information available in the file. + Aquí pots canviar el mode Bucle. Si és actiu, PatMan farà servir la informació de bucle disponible al fitxer. + + + Tune mode + Mode Afina + + + Here you can toggle the Tune mode. If enabled, PatMan will tune the sample to match the note's frequency. + Aquí pots canviar el mode Afina. Si és actiu, PatMan afinarà la mostra a la freqüència de la nota. + + + No file selected + Cap fitxer seleccionat + + + Open patch file + Obre fitxer pedaç + + + Patch-Files (*.pat) + Fitxers Pedaç (*.pat) + + pattern @@ -3006,6 +3045,10 @@ usa la roda del ratolí per a ajustar el volum d'un pas Incomplete polyphonic immitation tb303 Imitació polifònica incompleta tb303 + + GUS-compatible patch instrument + Instrument de pedaç compatible GUS + polyb302Synth diff --git a/include/engine.h b/include/engine.h index f52c52a99a..a577474549 100644 --- a/include/engine.h +++ b/include/engine.h @@ -1,7 +1,7 @@ /* * engine.h - engine-system of LMMS * - * Copyright (c) 2006 Tobias Doerffel + * Copyright (c) 2006-2007 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -30,6 +30,16 @@ #include #endif +#ifdef QT4 + +#include + +#else + +#include + +#endif + class automationEditor; class bbEditor; class projectJournal; @@ -124,6 +134,11 @@ public: } void updateFramesPerTact64th( void ); + const QMap & sampleExtensions( void ) + { + return( m_sample_extensions ); + } + private: bool m_hasGUI; @@ -141,7 +156,11 @@ private: #ifdef LADSPA_SUPPORT ladspa2LMMS * m_ladspaManager; #endif - + + QMap m_sample_extensions; + + void load_extensions( void ); + } ; diff --git a/include/file_browser.h b/include/file_browser.h index 28933c93fa..0948d2b9ff 100644 --- a/include/file_browser.h +++ b/include/file_browser.h @@ -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 ); diff --git a/include/main_window.h b/include/main_window.h index a68ea71bad..5e3691f91f 100644 --- a/include/main_window.h +++ b/include/main_window.h @@ -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 m_tools; - bool have_www_browser( void ); - friend class engine; diff --git a/include/pattern.h b/include/pattern.h index 904c4c7d46..c680502bd9 100644 --- a/include/pattern.h +++ b/include/pattern.h @@ -2,7 +2,7 @@ * pattern.h - declaration of class pattern, which contains all informations * about a pattern * - * Copyright (c) 2004-2006 Tobias Doerffel + * Copyright (c) 2004-2007 Tobias Doerffel * * 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 ); diff --git a/include/plugin.h b/include/plugin.h index 3ad0da6560..c54ea3091c 100644 --- a/include/plugin.h +++ b/include/plugin.h @@ -144,6 +144,13 @@ public: { } + virtual const QStringList & supportedExtensions( void ) + { + static QStringList no_extensions; + return( no_extensions ); + } + + protected: const plugin::pluginTypes m_type; } diff --git a/include/sample_buffer.h b/include/sample_buffer.h index 5af02eff72..9071b0a4be 100644 --- a/include/sample_buffer.h +++ b/include/sample_buffer.h @@ -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 ); diff --git a/include/sample_play_handle.h b/include/sample_play_handle.h index cd9dfd3c0b..e639459a86 100644 --- a/include/sample_play_handle.h +++ b/include/sample_play_handle.h @@ -1,7 +1,7 @@ /* * sample_play_handle.h - play-handle for playing a sample * - * Copyright (c) 2005-2006 Tobias Doerffel + * Copyright (c) 2005-2007 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -29,12 +29,12 @@ #include #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; diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 69cdc45caa..815e5b7101 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -25,6 +25,7 @@ SUBDIRS = \ live_tool \ midi_import \ organic \ + patman \ plucked_string_synth \ polyb302 \ $(SINGERBOT_DIR) \ diff --git a/plugins/audio_file_processor/audio_file_processor.cpp b/plugins/audio_file_processor/audio_file_processor.cpp index 1a36fce673..6756ce7492 100644 --- a/plugins/audio_file_processor/audio_file_processor.cpp +++ b/plugins/audio_file_processor/audio_file_processor.cpp @@ -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" { diff --git a/plugins/audio_file_processor/audio_file_processor.h b/plugins/audio_file_processor/audio_file_processor.h index d57a4866fb..9e2ae6efad 100644 --- a/plugins/audio_file_processor/audio_file_processor.h +++ b/plugins/audio_file_processor/audio_file_processor.h @@ -2,7 +2,7 @@ * audio_file_processor.h - declaration of class audioFileProcessor * (instrument-plugin for using audio-files) * - * Copyright (c) 2004-2006 Tobias Doerffel + * Copyright (c) 2004-2007 Tobias Doerffel * * 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; diff --git a/plugins/patman/Makefile.am b/plugins/patman/Makefile.am new file mode 100644 index 0000000000..e46770eff8 --- /dev/null +++ b/plugins/patman/Makefile.am @@ -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 diff --git a/plugins/patman/artwork.png b/plugins/patman/artwork.png new file mode 100644 index 0000000000..4e2782bc6e Binary files /dev/null and b/plugins/patman/artwork.png differ diff --git a/plugins/patman/logo.png b/plugins/patman/logo.png new file mode 100644 index 0000000000..b27ade7b62 Binary files /dev/null and b/plugins/patman/logo.png differ diff --git a/plugins/patman/loop_off.png b/plugins/patman/loop_off.png new file mode 100644 index 0000000000..7bf5cccc94 Binary files /dev/null and b/plugins/patman/loop_off.png differ diff --git a/plugins/patman/loop_on.png b/plugins/patman/loop_on.png new file mode 100644 index 0000000000..b1f15089ce Binary files /dev/null and b/plugins/patman/loop_on.png differ diff --git a/plugins/patman/patman.cpp b/plugins/patman/patman.cpp new file mode 100644 index 0000000000..9d886a1256 --- /dev/null +++ b/plugins/patman/patman.cpp @@ -0,0 +1,693 @@ +/* + * patman.cpp - a GUS-compatible patch instrument plugin + * + * Copyright (c) 2007 Javier Serrano Polo + * + * 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 + +#else + +#include +#include +#include + +#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 ", + 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( _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( 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::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" diff --git a/plugins/patman/patman.h b/plugins/patman/patman.h new file mode 100644 index 0000000000..07dc3f2a91 --- /dev/null +++ b/plugins/patman/patman.h @@ -0,0 +1,130 @@ +/* + * patman.h - header for a GUS-compatible patch instrument plugin + * + * Copyright (c) 2007 Javier Serrano Polo + * + * 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 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 diff --git a/plugins/patman/tune_off.png b/plugins/patman/tune_off.png new file mode 100644 index 0000000000..a5bd16162b Binary files /dev/null and b/plugins/patman/tune_off.png differ diff --git a/plugins/patman/tune_on.png b/plugins/patman/tune_on.png new file mode 100644 index 0000000000..c1777c52a5 Binary files /dev/null and b/plugins/patman/tune_on.png differ diff --git a/plugins/polyb302/polyb302.cpp b/plugins/polyb302/polyb302.cpp index 5da52fc1b7..4a6c295126 100644 --- a/plugins/polyb302/polyb302.cpp +++ b/plugins/polyb302/polyb302.cpp @@ -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 * @@ -28,28 +28,12 @@ * */ -#include "qt3support.h" - -#ifdef QT4 - -#include - -#else - -#include - -#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" diff --git a/plugins/polyb302/polyb302.h b/plugins/polyb302/polyb302.h index 0e63d0eaba..681d85eb97 100644 --- a/plugins/polyb302/polyb302.h +++ b/plugins/polyb302/polyb302.h @@ -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 * diff --git a/plugins/singerbot/singerbot.cpp b/plugins/singerbot/singerbot.cpp index 99d7b66fb5..35d7ef9ca0 100644 --- a/plugins/singerbot/singerbot.cpp +++ b/plugins/singerbot/singerbot.cpp @@ -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 ); } diff --git a/src/core/engine.cpp b/src/core/engine.cpp index c422f66703..31d9c7c63b 100644 --- a/src/core/engine.cpp +++ b/src/core/engine.cpp @@ -3,7 +3,7 @@ /* * engine.cpp - implementation of LMMS' engine-system * - * Copyright (c) 2006 Tobias Doerffel + * Copyright (c) 2006-2007 Tobias Doerffel * * 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 pluginDescriptors; + plugin::getDescriptorsOfAvailPlugins( pluginDescriptors ); + for( vvector::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 ) diff --git a/src/core/file_browser.cpp b/src/core/file_browser.cpp index 33bc4745dd..3ea07380ee 100644 --- a/src/core/file_browser.cpp +++ b/src/core/file_browser.cpp @@ -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( 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" diff --git a/src/core/main_window.cpp b/src/core/main_window.cpp index 6538626644..2dc165e201 100644 --- a/src/core/main_window.cpp +++ b/src/core/main_window.cpp @@ -128,6 +128,14 @@ mainWindow::mainWindow( engine * _engine ) : splitter->setChildrenCollapsible( FALSE ); #endif + QString sample_filter; + vlist ext_keys = eng()->sampleExtensions().keys(); + for( vlist::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 ); diff --git a/src/core/sample_play_handle.cpp b/src/core/sample_play_handle.cpp index df88446be5..0ffbab53ec 100644 --- a/src/core/sample_play_handle.cpp +++ b/src/core/sample_play_handle.cpp @@ -3,7 +3,7 @@ /* * sample_play_handle.cpp - implementation of class samplePlayHandle * - * Copyright (c) 2005-2006 Tobias Doerffel + * Copyright (c) 2005-2007 Tobias Doerffel * * 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 ); diff --git a/src/core/track_container.cpp b/src/core/track_container.cpp index 7b3f9e8e2a..b528306ef5 100644 --- a/src/core/track_container.cpp +++ b/src/core/track_container.cpp @@ -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 + * Copyright (c) 2004-2007 Tobias Doerffel * * 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 ); } diff --git a/src/lib/sample_buffer.cpp b/src/lib/sample_buffer.cpp index 9d6d636448..86a0e94b52 100644 --- a/src/lib/sample_buffer.cpp +++ b/src/lib/sample_buffer.cpp @@ -3,7 +3,7 @@ /* * sample_buffer.cpp - container-class sampleBuffer * - * Copyright (c) 2005-2006 Tobias Doerffel + * Copyright (c) 2005-2007 Tobias Doerffel * * 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( 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( ( @@ -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( + ( m_loop_endFrame - play_frame ) / + freq_factor ); + } + else + { + if( play_frame >= m_endFrame ) + { + return( FALSE ); + } + frames_for_loop = static_cast( + ( 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( 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( 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( *_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( - 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( - 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( *_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 diff --git a/src/tracks/bb_track.cpp b/src/tracks/bb_track.cpp index 2bbfa6c9e9..29dc46e100 100644 --- a/src/tracks/bb_track.cpp +++ b/src/tracks/bb_track.cpp @@ -3,7 +3,7 @@ /* * bb_track.cpp - implementation of class bbTrack and bbTCO * - * Copyright (c) 2004-2006 Tobias Doerffel + * Copyright (c) 2004-2007 Tobias Doerffel * * 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() ) { diff --git a/src/tracks/pattern.cpp b/src/tracks/pattern.cpp index fe44021db8..a1715a28b6 100644 --- a/src/tracks/pattern.cpp +++ b/src/tracks/pattern.cpp @@ -3,8 +3,8 @@ /* * pattern.cpp - implementation of class pattern which holds notes * - * Copyright (c) 2004-2006 Tobias Doerffel - * Copyright (c) 2005 Danny McRae + * Copyright (c) 2004-2007 Tobias Doerffel + * Copyright (c) 2005-2007 Danny McRae * * 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 );