bugfixes, new plugin "Vibed" and more

git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@111 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
Tobias Doerffel
2006-03-27 12:19:04 +00:00
parent 87985c092c
commit 462c48d012
73 changed files with 3180 additions and 80 deletions

View File

@@ -1,5 +1,53 @@
2005-03-26 Danny McRae <khjklujn/at/yahoo/dot/com>
* plugins/vibed/:
added "Vibed"-plugin, a powerful combination of PluckedStringSynth and
BitInvader that's capable of producing a surprisingly wide range of
sounds
2006-03-26 Tobias Doerffel <tobydox/at/users/dot/sourceforge/dot/net>
* src/lib/journalling_object.cpp:
in journallingObject::saveState(): append new dom-element to parent
before calling saveSettings() as some implementations of it depend on
knowing something about it's parent (e.g. whether it's the clipboard
etc.) - fixes several bugs related to clipboard-usage and drag'n'drop
2006-03-25 Tobias Doerffel <tobydox/at/users/dot/sourceforge/dot/net>
* include/instrument_track.h:
* src/core/preset_preview_play_handle.cpp:
disable journalling for all objects involved in preset-preview
* src/tracks/instrument_track.cpp:
when saving preset, create new node below content-node of project, as
the behaviour of saveTrackSpecificSettings() was changed some days
before
* src/lib/mmp.cpp:
bugfixes concerning project type-naming
* src/core/arp_and_chords_tab_widget.cpp:
bugfixes concerning loading/saving settings
2006-03-24 Tobias Doerffel <tobydox/at/users/dot/sourceforge/dot/net>
* src/core/track.cpp:
in trackContentWidget::undoStep(): cast journalling object to
track-content-object and close it instead of deleting it - fixes crash
after undo of TCO-add
2006-03-23 Tobias Doerffel <tobydox/at/users/dot/sourceforge/dot/net>
* plugins/organic/organic.cpp:
* plugins/organic/randomise_pressed.png:
added pixmap for visual feedback when pressing randomise-button
* plugins/midi_import/midi_import.cpp:
removed attribute FASTCALL from midiImport::tryImport() for not
crashing LMMS, as tryImport() is not defined as FASTCALL in
importFilter-API
* src/core/export_project_dialog.cpp:
fixed bug causing LMMS to crash when trying to export a project

4
TODO
View File

@@ -1,3 +1,5 @@
- when recording MIDI-events, add switch to disable recording of velocity
- integrated sample-browser in context-menu of sample-track/-tco
- font-size-scaling-coefficient in setup-dialog
- make note able of journalling
- before calling undoStep/redoStep from journallingObject, save journalling-state-context and disabled journalling, restore afterwards
@@ -5,7 +7,6 @@
- undo/redo-support in note/track etc.
- save tco-settings in trackContentWidget::saveSettings() etc. instead of track::...
- restore stacking-order of windows when loading project
- fix MIDI-import-filter
- bristol-bindings
- resample sample-track-tcos when using hq-mode
- add support for panes-interface (like blender) (instead of MDI etc.)
@@ -25,7 +26,6 @@
- level-meters in output-graph and channel-track
- do not skip samples because of rounding-errors when resampling in src/lib/sample_buffer.cpp
- MIDI-program/MIDI-mapping/process program-/channel-change-events from MIDI-files
- add note-len- and note-alignment-selectbox to piano-roll
- DSSI-support
- somehow avoid hidden plugin-descriptor-widgets plugin-browser if height of window is too small -> add scrollbar
- use drawLineF() for drawing notes in pattern::paintEvent() in qt4-version

View File

@@ -2,8 +2,8 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.50)
AC_INIT(lmms, 0.1.4-cvs20060323, tobydox/at/users/dot/sourceforge/dot/net)
AM_INIT_AUTOMAKE(lmms, 0.1.4-cvs20060323)
AC_INIT(lmms, 0.1.4-cvs20060326, tobydox/at/users/dot/sourceforge/dot/net)
AM_INIT_AUTOMAKE(lmms, 0.1.4-cvs20060326)
AM_CONFIG_HEADER(config.h)
@@ -470,6 +470,7 @@ AC_CONFIG_FILES([Makefile
plugins/plucked_string_synth/Makefile
plugins/triple_oscillator/Makefile
plugins/vestige/Makefile
plugins/vibed/Makefile
lmms.spec])
AC_OUTPUT

View File

@@ -0,0 +1,30 @@
<?xml version="1.0"?>
<!DOCTYPE multimedia-project>
<multimediaproject creator="Linux MultiMedia Studio (LMMS)" creatorversion="0.1.4-cvs20060323" type="instrumenttracksettings" version="1.0" >
<head/>
<instrumenttracksettings>
<instrumenttrack width="250" x="12" y="227" surpos="134219776" fxch="0" height="436" baseoct="4" vol="100" name="AnalogTimes 2" basetone="9" tab="1" visible="1" >
<tripleoscillator userwavefile1="samples/empty.wav" wavetype1="2" coarse1="0" userwavefile2="samples/empty.wav" wavetype2="0" coarse2="-12" vol0="49" vol1="54" finel0="0" vol2="14" finel1="0" finel2="-14" modalgo1="2" stphdetun0="247" pan0="0" modalgo2="3" stphdetun1="109" pan1="0" stphdetun2="50" pan2="0" phoffset0="0" phoffset1="271" phoffset2="0" finer0="0" finer1="0" finer2="13" userwavefile0="samples/empty.wav" wavetype0="3" coarse0="0" >
<journal entries="0" metadata="1" id="391701" curentry="0" />
</tripleoscillator>
<eldata fres="0.66" ftype="0" fcut="0" fwet="1" >
<elvol lfosyncmode="0" lpdel="0" amt="1" rel="0.473" ctlenvamt="0" latt="0" sus="0.433" lspd="0.0917" att="0" pdel="0" lamt="0" dec="0.324" userwavefile="" x100="0" lshp="0" hold="0" >
<journal entries="0" metadata="1" id="579409" curentry="0" />
</elvol>
<elcut lfosyncmode="0" lpdel="0" amt="1" rel="0.43" ctlenvamt="0" latt="0" sus="0.64" lspd="0.767" att="0" pdel="0" lamt="0" dec="0.241" userwavefile="" x100="0" lshp="1" hold="0" >
<journal entries="0" metadata="1" id="907107" curentry="0" />
</elcut>
<elres lfosyncmode="0" lpdel="0" amt="0" rel="0.1" ctlenvamt="0" latt="0" sus="0.499" lspd="0.01" att="0" pdel="0" lamt="-0.01" dec="0.499" userwavefile="" x100="0" lshp="1" hold="0" >
<journal entries="0" metadata="1" id="403343" curentry="0" />
</elres>
<journal entries="0" metadata="1" id="518423" curentry="0" />
</eldata>
<arpandchords arpmode="0" chordrange="1" arprange="3" arpdisabled="1" chord="0" chorddisabled="0" arpgate="142" arp="0" arpsyncmode="0" arptime="102" arpdir="1" >
<journal entries="0" metadata="1" id="485335" curentry="0" />
</arpandchords>
<midi inputchannel="0" outputchannel="1" receive="1" send="0" inports="24:0 CS46XX:CS46XX" >
<journal entries="0" metadata="1" id="192691" curentry="0" />
</midi>
</instrumenttrack>
</instrumenttracksettings>
</multimediaproject>

View File

@@ -155,6 +155,9 @@ public:
virtual void FASTCALL loadTrackSpecificSettings( const QDomElement &
_this );
using track::setJournalling;
// load instrument whose name matches given one
instrument * FASTCALL loadInstrument( const QString &
_instrument_name );

View File

@@ -160,7 +160,7 @@ public:
int index( void ) const;
// note-play-handles belonging to given channel
static constNotePlayHandleVector nphsOfChannelTrack(
static constNotePlayHandleVector nphsOfInstrumentTrack(
const instrumentTrack * _ct );
// return whether given note-play-handle is equal to *this

View File

@@ -60,7 +60,7 @@ public:
virtual bool done( void ) const;
static void cleanUp( engine * _engine );
static constNotePlayHandleVector nphsOfChannelTrack(
static constNotePlayHandleVector nphsOfInstrumentTrack(
const instrumentTrack * _ct );
private:

View File

@@ -90,7 +90,13 @@ public:
// journalling information about the ID get's lost
void forgetAboutID( const jo_id_t _id );
void clear( void );
void clearJournal( void )
{
m_journalEntries.clear();
m_currentJournalEntry = m_journalEntries.end();
}
void clearInvalidJournallingObjects( void );
journallingObject * getJournallingObject( const jo_id_t _id )
{

View File

@@ -129,8 +129,8 @@ protected:
void setAutoResizeEnabled( bool _e = FALSE );
float pixelsPerTact( void );
virtual void undoStep( journalEntry & _edit_step );
virtual void redoStep( journalEntry & _edit_step );
virtual void undoStep( journalEntry & _je );
virtual void redoStep( journalEntry & _je );
protected slots:
@@ -210,8 +210,8 @@ protected:
return( "trackcontentwidget" );
}
virtual void undoStep( journalEntry & _edit_step );
virtual void redoStep( journalEntry & _edit_step );
virtual void undoStep( journalEntry & _je );
virtual void redoStep( journalEntry & _je );
private:
@@ -277,7 +277,7 @@ private:
// actual widget shown in trackContainer
class trackWidget : public QWidget
class trackWidget : public QWidget, public journallingObject
{
Q_OBJECT
public:
@@ -338,6 +338,15 @@ public slots:
protected:
virtual void undoStep( journalEntry & _je );
virtual void redoStep( journalEntry & _je );
virtual QString nodeName( void ) const
{
return( "trackwidget" );
}
virtual void dragEnterEvent( QDragEnterEvent * _dee );
virtual void dropEvent( QDropEvent * _de );
virtual void mousePressEvent( QMouseEvent * _me );

View File

@@ -129,6 +129,9 @@ public:
protected:
virtual void undoStep( journalEntry & _je );
virtual void redoStep( journalEntry & _je );
virtual void dragEnterEvent( QDragEnterEvent * _dee );
virtual void dropEvent( QDropEvent * _de );
virtual void mousePressEvent( QMouseEvent * _me );
@@ -152,6 +155,10 @@ protected slots:
private:
enum actions
{
ADD_TRACK, REMOVE_TRACK
} ;
class scrollArea : public QScrollArea
{

View File

@@ -2,5 +2,5 @@ if VST_SUPPORT
VESTIGE_SUBDIR=vestige
endif
SUBDIRS = audio_file_processor bit_invader midi_import organic plucked_string_synth triple_oscillator $(VESTIGE_SUBDIR)
SUBDIRS = audio_file_processor bit_invader midi_import organic plucked_string_synth triple_oscillator $(VESTIGE_SUBDIR) vibed

View File

@@ -85,7 +85,7 @@ midiImport::~midiImport()
bool FASTCALL midiImport::tryImport( trackContainer * _tc )
bool midiImport::tryImport( trackContainer * _tc )
{
if( openFile() == FALSE )
{

View File

@@ -184,7 +184,7 @@ organicInstrument::organicInstrument( instrumentTrack * _channel_track ) :
m_randBtn = new pixmapButton( this, eng() );
m_randBtn->move( 100, 200 );
m_randBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
"randomise" ) );
"randomise_pressed" ) );
m_randBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
"randomise" ) );
//m_randBtn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ).

Binary file not shown.

44
plugins/vibed/Makefile.am Normal file
View File

@@ -0,0 +1,44 @@
AUTOMAKE_OPTIONS = foreign 1.4
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/src/lib -I.
AM_CXXFLAGS := $(AM_CXXFLAGS) $(QT_CXXFLAGS) -DPLUGIN_NAME="vibedstrings"
%.moc: ./%.h
$(MOC) -o $@ $<
MOC_FILES = ./vibed.moc ./graph.moc ./impulse_editor.moc ./nine_button_selector.moc
BUILT_SOURCES = $(MOC_FILES) ./embedded_resources.h
EMBEDDED_RESOURCES = $(wildcard *png)
./embedded_resources.h: $(EMBEDDED_RESOURCES)
$(top_builddir)/buildtools/bin2res $(EMBEDDED_RESOURCES) > $@
EXTRA_DIST = $(EMBEDDED_RESOURCES)
CLEANFILES = $(MOC_FILES) ./embedded_resources.h
pkglib_LTLIBRARIES= libvibedstrings.la
libvibedstrings_la_SOURCES = vibed.cpp \
vibed.h \
graph.cpp \
graph.h \
vibrating_string.cpp \
vibrating_string.h \
string_container.cpp \
string_container.h \
impulse_editor.cpp \
impulse_editor.h \
nine_button_selector.cpp \
nine_button_selector.h
$(libvibedstrings_la_SOURCES): ./embedded_resources.h

BIN
plugins/vibed/artwork.png Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
plugins/vibed/button_up.png Normal file

Binary file not shown.

265
plugins/vibed/graph.cpp Normal file
View File

@@ -0,0 +1,265 @@
/*
* graph.cpp - a QT widget for displaying and manipulating waveforms
*
* Copyright (c) 2006 Andreas Brandmaier <andy/at/brandmaier/dot/de>
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <QPaintEvent>
#include <QFontMetrics>
#include <QPainter>
#else
#include <qfontmetrics.h>
#include <qpainter.h>
#include <qcursor.h>
#endif
#include "graph.h"
#include "string_pair_drag.h"
#include "sample_buffer.h"
#include <iostream>
#include <cstdlib>
using namespace std;
graph::graph( QWidget * _parent, engine * _engine ) :
QWidget( _parent ),
engineObject( _engine )
{
m_mouseDown = false;
setFixedSize( 132, 104 );
setAcceptDrops( TRUE );
#ifndef QT4
setBackgroundMode( NoBackground );
#endif
}
graph::~graph()
{
}
void graph::setForeground( const QPixmap &_pixmap )
{
m_foreground = _pixmap;
}
void graph::setSamplePointer( float * _pointer, int _length )
{
samplePointer = _pointer;
sampleLength = _length;
update();
}
void graph::loadSampleFromFile( const QString & _filename )
{
// zero sample_shape
for (int i = 0; i < sampleLength; i++)
{
samplePointer[i] = 0;
}
// load user shape
sampleBuffer buffer( eng(), _filename );
// copy buffer data
sampleLength = min( sampleLength, static_cast<int>(buffer.frames()) );
for ( int i = 0; i < sampleLength; i++ )
{
samplePointer[i] = (float)*buffer.data()[i];
}
}
void graph::mouseMoveEvent ( QMouseEvent * _me )
{
// get position
int x = _me->x();
int y = _me->y();
// avoid mouse leaps
int diff = x - m_lastCursorX;
if( diff >= 1 )
{
x = m_lastCursorX + 1;
}
else if( diff <= 1 )
{
x = m_lastCursorX - 1;
}
else
{
x = m_lastCursorX;
}
changeSampleAt( x, y );
// update mouse
m_lastCursorX = x;
}
void graph::mousePressEvent( QMouseEvent * _me )
{
if( _me->button() == Qt::LeftButton )
{
// toggle mouse state
m_mouseDown = true;
// get position
int x = _me->x();
int y = _me->y();
changeSampleAt( x,y );
// toggle mouse state
m_mouseDown = true;
#ifndef QT3
setCursor( Qt::BlankCursor );
#else
setCursor( QCursor::BlankCursor );
#endif
m_lastCursorX = x;
}
}
void graph::changeSampleAt(int _x, int _y)
{
// consider border of background image
_x -= 2;
_y -= 2;
// boundary check
if (_x < 0) { return; }
if (_x > sampleLength) { return; }
if (_y < 0) { return; }
if (_y >= 100) { return; }
_y = 100 - _y;
// change sample shape
samplePointer[_x] = (_y-50.0)/50.0;
emit sampleChanged();
}
void graph::mouseReleaseEvent( QMouseEvent * _me )
{
if( _me->button() == Qt::LeftButton )
{
// toggle mouse state
m_mouseDown = false;
#ifndef QT3
setCursor( Qt::ArrowCursor );
#else
setCursor( QCursor::ArrowCursor );
#endif
update();
}
}
void graph::paintEvent( QPaintEvent * )
{
#ifdef QT4
QPainter p( this );
#else
QPixmap draw_pm( rect().size() );
draw_pm.fill( this, rect().topLeft() );
QPainter p( &draw_pm, this );
#endif
p.setPen( QColor( 0xFF, 0xAA, 0x00 ) );
p.drawLine( 1+sampleLength, 2, 1+sampleLength, 102);
float xscale = 128.0 / sampleLength;
for (int i=0; i < sampleLength-1; i++)
{
p.drawLine(2+static_cast<int>(i*xscale),
2+static_cast<int>(-samplePointer[i]*50) + 50,
2+static_cast<int>((i+1)*xscale),
2+static_cast<int>(-samplePointer[i+1]*50 + 50)
);
}
// draw Pointer
if (m_mouseDown) {
QPoint cursor = mapFromGlobal( QCursor::pos() );
p.setPen( QColor( 0xAA, 0xFF, 0x00 ) );
p.drawLine( 2, cursor.y(), 130, cursor.y() );
p.drawLine( cursor.x(), 2, cursor.x(), 102 );
}
p.drawPixmap( 0, 0, m_foreground );
#ifndef QT4
// and blit all the drawn stuff on the screen...
bitBlt( this, rect().topLeft(), &draw_pm );
#endif
}
void graph::dropEvent( QDropEvent * _de )
{
QString type = stringPairDrag::decodeKey( _de );
QString value = stringPairDrag::decodeValue( _de );
if( type == "samplefile" )
{
loadSampleFromFile( value );
_de->accept();
}
}
void graph::dragEnterEvent( QDragEnterEvent * _dee )
{
if( stringPairDrag::processDragEnterEvent( _dee,
QString( "samplefile" ) ) == FALSE )
{
_dee->ignore();
}
}
#include "graph.moc"

87
plugins/vibed/graph.h Normal file
View File

@@ -0,0 +1,87 @@
/*
* graph.h - a QT widget for displaying and manipulating waveforms
*
* Copyright (c) 2006 Andreas Brandmaier <andy/at/brandmaier/dot/de>
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#ifndef _GRAPH_H
#define _GRAPH_H
#include "qt3support.h"
#ifdef QT4
#include <QWidget>
#include <QPixmap>
#include <QCursor>
#else
#include <qwidget.h>
#include <qpixmap.h>
#include <qcursor.h>
#endif
#include "engine.h"
class graph : public QWidget, public engineObject
{
Q_OBJECT
public:
graph( QWidget * _parent, engine * _engine );
virtual ~graph();
void setSamplePointer( float * pointer, int length );
void setForeground( const QPixmap & _pixmap );
void loadSampleFromFile( const QString & _filename );
signals:
void sampleSizeChanged( float f );
void sampleChanged( void );
protected:
virtual void paintEvent( QPaintEvent * _pe );
virtual void dropEvent( QDropEvent * _de );
virtual void dragEnterEvent( QDragEnterEvent * _dee );
virtual void mousePressEvent( QMouseEvent * _me );
virtual void mouseMoveEvent( QMouseEvent * _me );
virtual void mouseReleaseEvent( QMouseEvent * _me );
private:
void changeSampleAt(int _x, int _y);
QPixmap m_foreground;
float *samplePointer;
int sampleLength;
bool m_mouseDown;
int m_lastCursorX;
} ;
#endif

View File

@@ -0,0 +1,492 @@
/*
* impulse_editor.cpp - graphic waveform editor
*
* Copyright (c) 2006 Danny McRae <khjklujn/at/yahoo/com>
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <QPoint>
#include <Qt/QtXml>
#include <QMap>
#include <QLabel>
#include <QMenu>
#else
#include <qpoint.h>
#include <qdom.h>
#include <qmap.h>
#include <qwhatsthis.h>
#include <qlabel.h>
#include <qpopupmenu.h>
#include <qcursor.h>
#endif
#include "impulse_editor.h"
#include "vibed.h"
#include "tooltip.h"
#include "oscillator.h"
#include "song_editor.h"
impulseEditor::impulseEditor( QWidget * _parent, int _x, int _y,
engine * _engine, Uint32 _len ) :
QWidget( _parent, "impulseEditor" ),
engineObject( _engine ),
m_sampleLength( _len ),
m_normalizeFactor( 1.0f ),
m_forward( TRUE )
{
setFixedSize( 153, 124 );
m_base = QPixmap::grabWidget( _parent, _x, _y );
setPaletteBackgroundPixmap( m_base );
m_graph = new graph( this, eng() );
m_graph->setForeground( PLUGIN_NAME::getIconPixmap( "wavegraph4" ) );
m_graph->move( 0, 0 );
m_graph->setCursor( QCursor( Qt::CrossCursor ) );
toolTip::add( m_graph, tr ( "Draw your own waveform here "
"by dragging your mouse onto this graph" ) );
connect( m_graph, SIGNAL ( sampleChanged( void ) ),
this, SLOT ( sampleChanged( void ) ) );
m_sinWaveBtn = new pixmapButton( this, eng() );
m_sinWaveBtn->move( 136, 3 );
m_sinWaveBtn->setActiveGraphic( embed::getIconPixmap(
"sin_wave_active" ) );
m_sinWaveBtn->setInactiveGraphic( embed::getIconPixmap(
"sin_wave_inactive" ) );
m_sinWaveBtn->setChecked( TRUE );
toolTip::add( m_sinWaveBtn,
tr( "Click here if you want a sine-wave for "
"current oscillator." ) );
connect( m_sinWaveBtn, SIGNAL (clicked ( void ) ),
this, SLOT ( sinWaveClicked( void ) ) );
m_triangleWaveBtn = new pixmapButton( this, eng() );
m_triangleWaveBtn->move( 136, 20 );
m_triangleWaveBtn->setActiveGraphic(
embed::getIconPixmap( "triangle_wave_active" ) );
m_triangleWaveBtn->setInactiveGraphic(
embed::getIconPixmap( "triangle_wave_inactive" ) );
toolTip::add( m_triangleWaveBtn,
tr( "Click here if you want a triangle-wave "
"for current oscillator." ) );
connect( m_triangleWaveBtn, SIGNAL ( clicked ( void ) ),
this, SLOT ( triangleWaveClicked( void ) ) );
m_sawWaveBtn = new pixmapButton( this, eng() );
m_sawWaveBtn->move( 136, 37 );
m_sawWaveBtn->setActiveGraphic( embed::getIconPixmap(
"saw_wave_active" ) );
m_sawWaveBtn->setInactiveGraphic( embed::getIconPixmap(
"saw_wave_inactive" ) );
toolTip::add( m_sawWaveBtn,
tr( "Click here if you want a saw-wave for "
"current oscillator." ) );
connect( m_sawWaveBtn, SIGNAL (clicked ( void ) ),
this, SLOT ( sawWaveClicked( void ) ) );
m_sqrWaveBtn = new pixmapButton( this, eng() );
m_sqrWaveBtn->move( 136, 54 );
m_sqrWaveBtn->setActiveGraphic( embed::getIconPixmap(
"square_wave_active" ) );
m_sqrWaveBtn->setInactiveGraphic( embed::getIconPixmap(
"square_wave_inactive" ) );
toolTip::add( m_sqrWaveBtn,
tr( "Click here if you want a square-wave for "
"current oscillator." ) );
connect( m_sqrWaveBtn, SIGNAL ( clicked ( void ) ),
this, SLOT ( sqrWaveClicked( void ) ) );
m_whiteNoiseWaveBtn = new pixmapButton( this, eng() );
m_whiteNoiseWaveBtn->move( 136, 71 );
m_whiteNoiseWaveBtn->setActiveGraphic(
embed::getIconPixmap( "white_noise_wave_active" ) );
m_whiteNoiseWaveBtn->setInactiveGraphic(
embed::getIconPixmap( "white_noise_wave_inactive" ) );
toolTip::add( m_whiteNoiseWaveBtn,
tr( "Click here if you want a white-noise for "
"current oscillator." ) );
connect( m_whiteNoiseWaveBtn, SIGNAL ( clicked ( void ) ),
this, SLOT ( noiseWaveClicked( void ) ) );
m_usrWaveBtn = new pixmapButton( this, eng() );
m_usrWaveBtn->move( 136, 88 );
m_usrWaveBtn->setActiveGraphic( embed::getIconPixmap(
"usr_wave_active" ) );
m_usrWaveBtn->setInactiveGraphic( embed::getIconPixmap(
"usr_wave_inactive" ) );
toolTip::add( m_usrWaveBtn,
tr( "Click here if you want a user-defined "
"wave-shape for current oscillator." ) );
connect( m_usrWaveBtn, SIGNAL ( clicked ( void ) ),
this, SLOT ( usrWaveClicked( void ) ) );
m_smoothBtn = new pixmapButton( this, eng() );
m_smoothBtn->move( 3, 108 );
m_smoothBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
"smooth_active" ) );
m_smoothBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
"smooth_inactive" ) );
m_smoothBtn->setChecked( FALSE );
toolTip::add( m_smoothBtn,
tr( "Click here to smooth waveform." ) );
connect( m_smoothBtn, SIGNAL ( clicked ( void ) ),
this, SLOT ( smoothClicked( void ) ) );
m_normalizeBtn = new pixmapButton( this, eng() );
m_normalizeBtn->move( 20, 108 );
m_normalizeBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
"normalize_active" ) );
m_normalizeBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
"normalize_inactive" ) );
m_normalizeBtn->setChecked( FALSE );
toolTip::add( m_normalizeBtn,
tr( "Click here to normalize waveform." ) );
connect( m_normalizeBtn, SIGNAL ( clicked ( void ) ),
this, SLOT ( normalizeClicked( void ) ) );
m_state = new ledCheckBox( "", this, eng() );
m_state->move( 136, 109 );
m_state->setChecked( TRUE );
toolTip::add( m_state,
tr( "Click here to enable/disable waveform." ) );
m_sampleShape = new float[m_sampleLength];
m_graph->setSamplePointer( m_sampleShape, m_sampleLength );
m_lastBtn = m_sinWaveBtn;
emit( sinWaveClicked() );
move( _x, _y );
}
impulseEditor::~impulseEditor()
{
}
void impulseEditor::sinWaveClicked( void )
{
m_lastBtn->setChecked( FALSE);
m_lastBtn = m_sinWaveBtn;
m_lastBtn->setChecked( TRUE );
// generate a Sinus wave using static oscillator-method
for( Uint32 i = 0; i < m_sampleLength; i++ )
{
m_sampleShape[i] = oscillator::sinSample( i /
static_cast<float>( m_sampleLength ) );
}
sampleChanged();
}
void impulseEditor::triangleWaveClicked( void )
{
m_lastBtn->setChecked( FALSE);
m_lastBtn = m_triangleWaveBtn;
m_lastBtn->setChecked( TRUE );
// generate a Triangle wave using static oscillator-method
for( Uint32 i = 0; i < m_sampleLength; i++ )
{
m_sampleShape[i] = oscillator::triangleSample( i /
static_cast<float>( m_sampleLength ) );
}
sampleChanged();
}
void impulseEditor::sawWaveClicked( void )
{
m_lastBtn->setChecked( FALSE);
m_lastBtn = m_sawWaveBtn;
m_lastBtn->setChecked( TRUE );
// generate a Saw wave using static oscillator-method
for( Uint32 i = 0; i < m_sampleLength; i++ )
{
m_sampleShape[i] = oscillator::sawSample( i /
static_cast<float>( m_sampleLength ) );
}
sampleChanged();
}
void impulseEditor::sqrWaveClicked( void )
{
m_lastBtn->setChecked( FALSE);
m_lastBtn = m_sqrWaveBtn;
m_lastBtn->setChecked( TRUE );
// generate a Sqr wave using static oscillator-method
for( Uint32 i = 0; i < m_sampleLength; i++ )
{
m_sampleShape[i] = oscillator::squareSample( i /
static_cast<float>( m_sampleLength ) );
}
sampleChanged();
}
void impulseEditor::noiseWaveClicked( void )
{
m_lastBtn->setChecked( FALSE);
m_lastBtn = m_whiteNoiseWaveBtn;
m_lastBtn->setChecked( TRUE );
// generate a Noise wave using static oscillator-method
for( Uint32 i = 0; i < m_sampleLength; i++ )
{
m_sampleShape[i] = oscillator::noiseSample( i /
static_cast<float>( m_sampleLength ) );
}
sampleChanged();
}
void impulseEditor::usrWaveClicked( void )
{
m_lastBtn->setChecked( FALSE);
m_lastBtn = m_usrWaveBtn;
m_lastBtn->setChecked( TRUE );
// zero sample_shape
for( Uint32 i = 0; i < m_sampleLength; i++ )
{
m_sampleShape[i] = 0;
}
// load user shape
sampleBuffer buffer( eng() );
QString af = buffer.openAudioFile();
if( af != "" )
{
buffer.setAudioFile( af );
// copy buffer data
if( m_sampleLength < static_cast<Uint32>( buffer.frames() ) )
{
m_sampleLength = m_sampleLength;
}
else
{
m_sampleLength = static_cast<int>( buffer.frames() );
}
for( Uint32 i = 0; i < m_sampleLength; i++ )
{
m_sampleShape[i] = static_cast<float>(
buffer.data()[0][i] );
}
}
sampleChanged();
}
void impulseEditor::smoothClicked( void )
{
m_smoothBtn->setChecked( TRUE );
m_smoothBtn->update();
float* temp = new float[m_sampleLength];
memcpy( temp, m_sampleShape, sizeof( float ) * m_sampleLength );
// Smoothing
m_sampleShape[0] = temp[0] / 2.0f;
for( Uint32 i = 1; i < m_sampleLength - 1; i++ )
{
m_sampleShape[i] = ( temp[i - 1] +
temp[i] +
temp[i + 1] ) / 3.0f;
}
m_sampleShape[m_sampleLength - 1] = temp[m_sampleLength - 1] / 2.0f;
m_forward = FALSE;
// Clean up
delete[] temp;
// paint
update();
m_graph->update();
eng()->getSongEditor()->setModified();
m_smoothBtn->setChecked( FALSE );
m_smoothBtn->update();
}
void impulseEditor::normalizeClicked( void )
{
m_normalizeBtn->setChecked( TRUE );
m_normalizeBtn->update();
float max = 0.0001f;
for( Uint32 i = 0; i < m_sampleLength; i++ )
{
if( fabsf(m_sampleShape[i]) > max && m_sampleShape[i] != 0.0f )
{
max = fabs( m_sampleShape[i] );
}
}
m_normalizeFactor = max;
for( Uint32 i = 0; i < m_sampleLength; i++ )
{
m_sampleShape[i] /= m_normalizeFactor;
}
update();
m_graph->update();
eng()->getSongEditor()->setModified();
m_normalizeBtn->setChecked( FALSE );
m_normalizeBtn->update();
}
void impulseEditor::sampleChanged()
{
// analyze
float max = 0.0001f;
for( Uint32 i = 0; i < m_sampleLength; i++ )
{
if( fabsf(m_sampleShape[i]) > max && m_sampleShape[i] != 0.0f )
{
max = fabs( m_sampleShape[i] );
}
}
m_normalizeFactor = max;
// update
if( m_graph != NULL )
{
m_graph->update();
}
eng()->getSongEditor()->setModified();
}
void impulseEditor::setOn( bool _on )
{
if( _on )
{
m_state->setChecked( TRUE );
}
else
{
m_state->setChecked( FALSE );
}
}
void impulseEditor::contextMenuEvent( QContextMenuEvent * )
{
QMenu contextMenu( this );
#ifdef QT4
contextMenu.setTitle( accessibleName() );
#else
QLabel * caption = new QLabel( "<font color=white><b>" +
QString( "Impulse Editor" ) + "</b></font>", this );
caption->setPaletteBackgroundColor( QColor( 0, 0, 192 ) );
caption->setAlignment( Qt::AlignCenter );
contextMenu.addAction( caption );
#endif
contextMenu.addAction( embed::getIconPixmap( "help" ), tr( "&Help" ),
this, SLOT( displayHelp() ) );
contextMenu.exec( QCursor::pos() );
}
void impulseEditor::displayHelp( void )
{
#ifdef QT4
QWhatsThis::showText( mapToGlobal( rect().bottomRight() ),
whatsThis() );
#else
QWhatsThis::display( QWhatsThis::textFor( this ), mapToGlobal(
rect().bottomRight() ) );
#endif
}
void FASTCALL impulseEditor::setValues( float * _shape )
{
for( Uint32 i = 0; i < m_sampleLength; i++ )
{
m_sampleShape[i] = _shape[i];
}
}
#include "impulse_editor.moc"

View File

@@ -0,0 +1,99 @@
/*
* impulse_editor.cpp - graphic waveform editor
*
* Copyright (c) 2006 Danny McRae <khjklujn/at/yahoo/com>
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#ifndef _IMPULSE_EDITOR_H
#define _IMPULSE_EDITOR_H
#include "qt3support.h"
#ifdef QT4
#include <QWidget>
#include <QPixmap>
#include <QCursor>
#else
#include <qwidget.h>
#include <qpixmap.h>
#include <qcursor.h>
#endif
#include "config.h"
#include "types.h"
#include "graph.h"
#include "pixmap_button.h"
#include "engine.h"
#include "led_checkbox.h"
class impulseEditor: public QWidget, public engineObject
{
Q_OBJECT
public:
impulseEditor( QWidget *parent, int _x, int _y,
engine * _engine, Uint32 _len = 128 );
~impulseEditor();
inline float * getValues() { return( m_sampleShape ); };
inline bool isOn() { return( m_state->isChecked() ); };
void FASTCALL setValues( float * _shape );
public slots:
void sinWaveClicked( void );
void triangleWaveClicked( void );
void sawWaveClicked( void );
void sqrWaveClicked( void );
void noiseWaveClicked( void );
void usrWaveClicked( void );
void smoothClicked( void );
void normalizeClicked( void );
void sampleChanged();
void setOn( bool _on );
void contextMenuEvent( QContextMenuEvent * );
void displayHelp( void );
private:
graph * m_graph;
pixmapButton * m_sinWaveBtn;
pixmapButton * m_triangleWaveBtn;
pixmapButton * m_sqrWaveBtn;
pixmapButton * m_sawWaveBtn;
pixmapButton * m_whiteNoiseWaveBtn;
pixmapButton * m_usrWaveBtn;
pixmapButton * m_smoothBtn;
pixmapButton * m_normalizeBtn;
pixmapButton * m_lastBtn;
ledCheckBox * m_state;
float * m_sampleShape;
Uint32 m_sampleLength;
float m_normalizeFactor;
bool m_forward;
QPixmap m_base;
};
#endif

BIN
plugins/vibed/logo.png Normal file

Binary file not shown.

View File

@@ -0,0 +1,318 @@
/*
* nine_button_selector.cpp
*
* Copyright (c) 2006 Danny McRae <khjklujn/at/yahoo/com>
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#ifdef QT4
#include <QLabel>
#include <QMenu>
#else
#include <qwhatsthis.h>
#include <qlabel.h>
#include <qpopupmenu.h>
#include <qcursor.h>
#endif
#include "nine_button_selector.h"
#include "embed.h"
nineButtonSelector::nineButtonSelector( QPixmap _button0_on,
QPixmap _button0_off,
QPixmap _button1_on,
QPixmap _button1_off,
QPixmap _button2_on,
QPixmap _button2_off,
QPixmap _button3_on,
QPixmap _button3_off,
QPixmap _button4_on,
QPixmap _button4_off,
QPixmap _button5_on,
QPixmap _button5_off,
QPixmap _button6_on,
QPixmap _button6_off,
QPixmap _button7_on,
QPixmap _button7_off,
QPixmap _button8_on,
QPixmap _button8_off,
Uint8 _default,
Uint32 _x, Uint32 _y,
QWidget * _parent,
engine * _engine ):
QWidget( _parent, "nineButtonSelector" ),
engineObject( _engine ),
m_selected( _default )
{
setFixedSize( 50, 50 );
m_base = QPixmap::grabWidget( _parent, _x, _y );
move( _x, _y );
setPaletteBackgroundPixmap( m_base );
m_button = new pixmapButton( this, eng() );
m_button->move( 1, 1 );
m_button->setActiveGraphic( _button0_on );
m_button->setInactiveGraphic( _button0_off );
m_button->setChecked( FALSE );
connect( m_button, SIGNAL ( clicked ( void ) ),
this, SLOT ( button0Clicked( void ) ) );
m_buttons.append( m_button );
m_button = new pixmapButton( this, eng() );
m_button->move( 18, 1 );
m_button->setActiveGraphic( _button1_on );
m_button->setInactiveGraphic( _button1_off );
m_button->setChecked( FALSE );
connect( m_button, SIGNAL ( clicked ( void ) ),
this, SLOT ( button1Clicked( void ) ) );
m_buttons.append( m_button );
m_button = new pixmapButton( this, eng() );
m_button->move( 35, 1 );
m_button->setActiveGraphic( _button2_on );
m_button->setInactiveGraphic( _button2_off );
m_button->setChecked( FALSE );
connect( m_button, SIGNAL ( clicked ( void ) ),
this, SLOT ( button2Clicked( void ) ) );
m_buttons.append( m_button );
m_button = new pixmapButton( this, eng() );
m_button->move( 1, 18 );
m_button->setActiveGraphic( _button3_on );
m_button->setInactiveGraphic( _button3_off );
m_button->setChecked( FALSE );
connect( m_button, SIGNAL ( clicked ( void ) ),
this, SLOT ( button3Clicked( void ) ) );
m_buttons.append( m_button );
m_button = new pixmapButton( this, eng() );
m_button->move( 18, 18 );
m_button->setActiveGraphic( _button4_on );
m_button->setInactiveGraphic( _button4_off );
m_button->setChecked( FALSE );
connect( m_button, SIGNAL ( clicked ( void ) ),
this, SLOT ( button4Clicked( void ) ) );
m_buttons.append( m_button );
m_button = new pixmapButton( this, eng() );
m_button->move( 35, 18 );
m_button->setActiveGraphic( _button5_on );
m_button->setInactiveGraphic( _button5_off );
m_button->setChecked( FALSE );
connect( m_button, SIGNAL ( clicked ( void ) ),
this, SLOT ( button5Clicked( void ) ) );
m_buttons.append( m_button );
m_button = new pixmapButton( this, eng() );
m_button->move( 1, 35 );
m_button->setActiveGraphic( _button6_on );
m_button->setInactiveGraphic( _button6_off );
m_button->setChecked( FALSE );
connect( m_button, SIGNAL ( clicked ( void ) ),
this, SLOT ( button6Clicked( void ) ) );
m_buttons.append( m_button );
m_button = new pixmapButton( this, eng() );
m_button->move( 18, 35 );
m_button->setActiveGraphic( _button7_on );
m_button->setInactiveGraphic( _button7_off );
m_button->setChecked( FALSE );
connect( m_button, SIGNAL ( clicked ( void ) ),
this, SLOT ( button7Clicked( void ) ) );
m_buttons.append( m_button );
m_button = new pixmapButton( this, eng() );
m_button->move( 35, 35 );
m_button->setActiveGraphic( _button8_on );
m_button->setInactiveGraphic( _button8_off );
m_button->setChecked( FALSE );
connect( m_button, SIGNAL ( clicked ( void ) ),
this, SLOT ( button8Clicked( void ) ) );
m_buttons.append( m_button );
m_lastBtn = m_buttons.at( _default );
m_lastBtn->setChecked( TRUE );
}
nineButtonSelector::~ nineButtonSelector()
{
}
void nineButtonSelector::button0Clicked( void )
{
m_lastBtn->setChecked( FALSE);
m_lastBtn = m_buttons.at( 0 );
m_lastBtn->setChecked( TRUE );
m_selected = 0;
emit nineButtonSelection( m_selected );
}
void nineButtonSelector::button1Clicked( void )
{
m_lastBtn->setChecked( FALSE);
m_lastBtn = m_buttons.at( 1 );
m_lastBtn->setChecked( TRUE );
m_selected = 1;
emit nineButtonSelection( m_selected );
}
void nineButtonSelector::button2Clicked( void )
{
m_lastBtn->setChecked( FALSE);
m_lastBtn = m_buttons.at( 2 );
m_lastBtn->setChecked( TRUE );
m_selected = 2;
emit nineButtonSelection( m_selected );
}
void nineButtonSelector::button3Clicked( void )
{
m_lastBtn->setChecked( FALSE);
m_lastBtn = m_buttons.at( 3 );
m_lastBtn->setChecked( TRUE );
m_selected = 3;
emit nineButtonSelection( m_selected );
}
void nineButtonSelector::button4Clicked( void )
{
m_lastBtn->setChecked( FALSE);
m_lastBtn = m_buttons.at( 4 );
m_lastBtn->setChecked( TRUE );
m_selected = 4;
emit nineButtonSelection( m_selected );
}
void nineButtonSelector::button5Clicked( void )
{
m_lastBtn->setChecked( FALSE);
m_lastBtn = m_buttons.at( 5 );
m_lastBtn->setChecked( TRUE );
m_selected = 5;
emit nineButtonSelection( m_selected );
}
void nineButtonSelector::button6Clicked( void )
{
m_lastBtn->setChecked( FALSE);
m_lastBtn = m_buttons.at( 6 );
m_lastBtn->setChecked( TRUE );
m_selected = 6;
emit nineButtonSelection( m_selected );
}
void nineButtonSelector::button7Clicked( void )
{
m_lastBtn->setChecked( FALSE);
m_lastBtn = m_buttons.at( 7 );
m_lastBtn->setChecked( TRUE );
m_selected = 7;
emit nineButtonSelection( m_selected );
}
void nineButtonSelector::button8Clicked( void )
{
m_lastBtn->setChecked( FALSE);
m_lastBtn = m_buttons.at( 8 );
m_lastBtn->setChecked( TRUE );
m_selected = 8;
emit nineButtonSelection( m_selected );
}
void nineButtonSelector::contextMenuEvent( QContextMenuEvent * )
{
QMenu contextMenu( this );
#ifdef QT4
contextMenu.setTitle( accessibleName() );
#else
QLabel * caption = new QLabel( "<font color=white><b>" +
QString( "Selector" ) + "</b></font>", this );
caption->setPaletteBackgroundColor( QColor( 0, 0, 192 ) );
caption->setAlignment( Qt::AlignCenter );
contextMenu.addAction( caption );
#endif
contextMenu.addAction( embed::getIconPixmap( "help" ), tr( "&Help" ),
this, SLOT( displayHelp() ) );
contextMenu.exec( QCursor::pos() );
}
void nineButtonSelector::displayHelp( void )
{
#ifdef QT4
QWhatsThis::showText( mapToGlobal( rect().bottomRight() ),
whatsThis() );
#else
QWhatsThis::display( QWhatsThis::textFor( this ), mapToGlobal(
rect().bottomRight() ) );
#endif
}
#include "nine_button_selector.moc"

View File

@@ -0,0 +1,89 @@
/*
* nine_button_selector.h
*
* Copyright (c) 2006 Danny McRae <khjklujn/at/yahoo/com>
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#ifndef _NINE_BUTTON_SELECTOR_H
#define _NINE_BUTTON_SELECTOR_H
#include <qptrlist.h>
#include "qt3support.h"
#include "config.h"
#include "types.h"
#include "pixmap_button.h"
class nineButtonSelector: public QWidget, public engineObject
{
Q_OBJECT
public:
nineButtonSelector( QPixmap _button1_on,
QPixmap _button1_off,
QPixmap _button2_on,
QPixmap _button2_off,
QPixmap _button3_on,
QPixmap _button3_off,
QPixmap _button4_on,
QPixmap _button4_off,
QPixmap _button5_on,
QPixmap _button5_off,
QPixmap _button6_on,
QPixmap _button6_off,
QPixmap _button7_on,
QPixmap _button7_off,
QPixmap _button8_on,
QPixmap _button8_off,
QPixmap _button9_on,
QPixmap _button9_off,
Uint8 _default,
Uint32 _x, Uint32 _y,
QWidget * _parent,
engine * _engine );
~nineButtonSelector();
inline Uint8 getSelected() { return( m_selected ); };
public slots:
void button0Clicked( void );
void button1Clicked( void );
void button2Clicked( void );
void button3Clicked( void );
void button4Clicked( void );
void button5Clicked( void );
void button6Clicked( void );
void button7Clicked( void );
void button8Clicked( void );
void contextMenuEvent( QContextMenuEvent * );
void displayHelp( void );
signals:
void nineButtonSelection( Uint8 );
private:
QPtrList<pixmapButton> m_buttons;
pixmapButton * m_button;
pixmapButton * m_lastBtn;
QPixmap m_base;
Uint8 m_selected;
};
#endif

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,95 @@
/*
* string_container.cpp - contains a collection of strings
*
* Copyright (c) 2006 Danny McRae <khjklujn/at/yahoo/com>
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "string_container.h"
stringContainer::stringContainer( const float _pitch,
const sample_rate_t _sample_rate,
const Uint32 _buffer_length ) :
m_pitch( _pitch ),
m_sampleRate( _sample_rate ),
m_bufferLength( _buffer_length )
{
}
void stringContainer::addString(Uint8 _harm,
const float _pick,
const float _pickup,
float * _impluse,
const float _randomize,
const float _string_loss,
const float _detune,
const Uint8 _oversample,
const bool _state )
{
float harm;
switch( _harm )
{
case 0:
harm = 0.25f;
break;
case 1:
harm = 0.5f;
break;
case 2:
harm = 1.0f;
break;
case 3:
harm = 2.0f;
break;
case 4:
harm = 3.0f;
break;
case 5:
harm = 4.0f;
break;
case 6:
harm = 5.0f;
break;
case 7:
harm = 6.0f;
break;
case 8:
harm = 7.0f;
break;
default:
harm = 1.0f;
}
m_strings.append( new vibratingString( m_pitch * harm,
_pick,
_pickup,
_impluse,
m_bufferLength,
m_sampleRate,
_oversample,
_randomize,
_string_loss,
_detune,
_state ) );
}

View File

@@ -0,0 +1,83 @@
/* string_container.h - contains a collection of strings
*
* Copyright (c) 2006 Danny McRae <khjklujn/at/yahoo/com>
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#ifndef _TWO_STRINGS_H
#define _TWO_STRINGS_H
#ifdef QT4
#include <Qt3Support>
#else
#include "qptrlist.h"
#endif
#include "config.h"
#include "types.h"
#include "vibrating_string.h"
class stringContainer
{
public:
stringContainer( const float _pitch,
const sample_rate_t _sample_rate,
const Uint32 _buffer_length );
void addString( Uint8 _harm,
const float _pick,
const float _pickup,
float * _impluse,
const float _randomize,
const float _string_loss,
const float _detune,
const Uint8 _oversample,
const bool _state );
inline ~stringContainer()
{
m_strings.setAutoDelete( TRUE );
Uint32 strings = m_strings.count();
for( Uint32 i = 0; i < strings; i++ )
{
m_strings.removeFirst();
}
}
inline float getStringSample( Uint8 _string )
{
return( m_strings.at( _string )->nextSample() );
}
private:
QPtrList<vibratingString> m_strings;
const float m_pitch;
const sample_rate_t m_sampleRate;
const Uint32 m_bufferLength;
} ;
#endif

747
plugins/vibed/vibed.cpp Normal file
View File

@@ -0,0 +1,747 @@
/*
* vibed.cpp - combination of PluckedStringSynth and BitInvader
*
* Copyright (c) 2006 Danny McRae <khjklujn/at/yahoo/com>
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <Qt/QtXml>
#include <QMap>
#include <QLabel>
#include <QMenu>
#else
#include <qdom.h>
#include <qmap.h>
#include <qwhatsthis.h>
#include <qlabel.h>
#include <qpopupmenu.h>
#include <qcursor.h>
#endif
#include "vibed.h"
#include "note_play_handle.h"
#include "instrument_track.h"
#include "templates.h"
#include "buffer_allocator.h"
#include "knob.h"
#include "tooltip.h"
#include "oscillator.h"
#include "song_editor.h"
#include "string_container.h"
#include "base64.h"
#undef SINGLE_SOURCE_COMPILE
#include "embed.cpp"
extern "C"
{
plugin::descriptor vibedstrings_plugin_descriptor =
{
STRINGIFY_PLUGIN_NAME( PLUGIN_NAME ),
"Vibed",
QT_TRANSLATE_NOOP( "pluginBrowser",
"Vibrating string modeler" ),
"Danny McRae <khjklujn/at/yahoo/com>",
0x0100,
plugin::INSTRUMENT,
new QPixmap( PLUGIN_NAME::getIconPixmap( "logo" ) )
};
}
vibed::vibed( instrumentTrack * _channel_track ) :
instrument( _channel_track, &vibedstrings_plugin_descriptor ),
m_sampleLength( 128 )
{
#ifdef QT4
QPalette pal;
pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap(
"artwork" ) );
setPalette( pal );
#else
setErasePixmap( PLUGIN_NAME::getIconPixmap( "artwork" ) );
#endif
for( Uint8 harm = 0; harm < 9; harm++ )
{
m_editor = new impulseEditor( this, 76, 21, eng() );
m_editor->setOn( FALSE );
m_editor->hide();
m_editors.append( m_editor );
#ifdef QT4
m_editor->setWhatsThis(
#else
QWhatsThis::add( m_editor,
#endif
tr(
"The waveform editor provides control over the initial state or impulse "
"that is used to start the string vibrating. The buttons to the right of "
"the graph will initialize the waveform to the selected type. The '?' "
"button will load a waveform from a file--only the first 128 samples "
"will be loaded.\n\n"
"The waveform can also be drawn in the graph.\n\n"
"The 'S' button will smooth the waveform.\n\n"
"The 'N' button will normalize the waveform.") );
m_volumeKnob = new knob( knobBright_26, this,
tr( "Volume" ),
eng() );
m_volumeKnob->setRange( 0.0f, 2.0f, 0.01f );
m_volumeKnob->setInitValue( 1.0f );
m_volumeKnob->move( 103, 142 );
m_volumeKnob->setHintText( tr( "Volume:" ) + " ", "" );
m_volumeKnob->hide();
m_volumeKnobs.append( m_volumeKnob );
#ifdef QT4
m_volumeKnob->setWhatsThis(
#else
QWhatsThis::add( m_volumeKnob,
#endif
tr(
"The 'V' knob sets the volume of the selected string." ) );
m_stiffnessKnob = new knob( knobBright_26, this,
tr( "String stiffness" ),
eng() );
m_stiffnessKnob->setRange( 0.0f, 0.05f, 0.001f );
m_stiffnessKnob->setInitValue( 0.0f );
m_stiffnessKnob->move( 129, 142 );
m_stiffnessKnob->setHintText( tr( "String stiffness:" ) +
" ", "" );
m_stiffnessKnob->hide();
m_stiffnessKnobs.append( m_stiffnessKnob );
#ifdef QT4
m_stiffnessKnob->setWhatsThis(
#else
QWhatsThis::add( m_stiffnessKnob,
#endif
tr(
"The 'S' knob sets the stiffness of the selected string. The stiffness "
"of the string affects how long the string will ring out. The lower "
"the setting, the longer the string will ring." ) );
m_pickKnob = new knob( knobBright_26, this,
tr( "Pick position" ),
eng() );
m_pickKnob->setRange( 0.0f, 0.5f, 0.005f );
m_pickKnob->setInitValue( 0.0f );
m_pickKnob->move( 153, 142 );
m_pickKnob->setHintText( tr( "Pick position:" ) + " ", "" );
m_pickKnob->hide();
m_pickKnobs.append( m_pickKnob );
#ifdef QT4
m_pickKnob->setWhatsThis(
#else
QWhatsThis::add( m_pickKnob,
#endif
tr(
"The 'P' knob sets the position where the selected string will be 'picked'. "
"The lower the setting the closer the pick is to the bridge." ) );
m_pickupKnob = new knob( knobBright_26, this,
tr( "Pickup position" ),
eng() );
m_pickupKnob->setRange( 0.0f, 0.5f, 0.005f );
m_pickupKnob->setInitValue( 0.05f );
m_pickupKnob->move( 177, 142 );
m_pickupKnob->setHintText( tr( "Pickup position:" ) +
" ", "" );
m_pickupKnob->hide();
m_pickupKnobs.append( m_pickupKnob );
#ifdef QT4
m_pickupKnob->setWhatsThis(
#else
QWhatsThis::add( m_pickupKnob,
#endif
tr(
"The 'PU' knob sets the position where the vibrations will be monitored "
"for the selected string. The lower the setting, the closer the "
"pickup is to the bridge." ) );
m_panKnob = new knob( knobBright_26, this,
tr( "Pan" ),
eng() );
m_panKnob->setRange( -1.0f, 1.0f, 0.01f );
m_panKnob->setInitValue( 0.0f );
m_panKnob->move( 105, 187 );
m_panKnob->setHintText( tr( "Pan:" ) + " ", "" );
m_panKnob->hide();
m_panKnobs.append( m_panKnob );
#ifdef QT4
m_panKnob->setWhatsThis(
#else
QWhatsThis::add( m_panKnob,
#endif
tr(
"The Pan knob determines the location of the selected string in the stereo "
"field." ) );
m_detuneKnob = new knob( knobBright_26, this,
tr( "Detune" ),
eng() );
m_detuneKnob->setRange( -0.1f, 0.1f, 0.001f );
m_detuneKnob->setInitValue( 0.0f );
m_detuneKnob->move( 150, 187 );
m_detuneKnob->setHintText( tr( "Detune:" ) + " ", "" );
m_detuneKnob->hide();
m_detuneKnobs.append( m_detuneKnob );
#ifdef QT4
m_detuneKnob->setWhatsThis(
#else
QWhatsThis::add( m_detuneKnob,
#endif
tr(
"The Detune knob modifies the pitch of the selected string. Settings less "
"than zero will cause the string to sound flat. Settings greater than zero "
"will cause the string to sound sharp." ) );
m_randomKnob = new knob( knobBright_26, this,
tr( "Fuzziness" ),
eng() );
m_randomKnob->setRange( 0.0f, 0.75f, 0.01f );
m_randomKnob->setInitValue( 0.0f );
m_randomKnob->move( 194, 187 );
m_randomKnob->setHintText( tr( "Fuzziness:" ) +
" ", "" );
m_randomKnob->hide();
m_randomKnobs.append( m_randomKnob );
#ifdef QT4
m_randomKnob->setWhatsThis(
#else
QWhatsThis::add( m_randomKnob,
#endif
tr(
"The Slap knob adds a bit of fuzz to the selected string which is most "
"apparent during the attack, though it can also be used to make the string "
"sound more 'metallic'.") );
m_lengthKnob = new knob( knobBright_26, this,
tr( "Length" ),
eng() );
m_lengthKnob->setRange( 1, 16, 1 );
m_lengthKnob->setInitValue( 1 );
m_lengthKnob->move( 23, 193 );
m_lengthKnob->setHintText( tr( "Length:" ) +
" ", "" );
m_lengthKnob->hide();
m_lengthKnobs.append( m_lengthKnob );
#ifdef QT4
m_lengthKnob->setWhatsThis(
#else
QWhatsThis::add( m_lengthKnob,
#endif
tr(
"The Length knob sets the length of the selected string. Longer strings "
"will both ring longer and sound brighter, however, they will also eat up "
"more CPU cycles." ) );
m_impulse = new ledCheckBox( "", this, eng() );
m_impulse->move( 23, 94 );
m_impulse->setChecked( FALSE );
toolTip::add( m_impulse,
tr( "Impulse or initial state" ) );
m_impulse->hide();
m_impulses.append( m_impulse );
#ifdef QT4
m_impulse->setWhatsThis(
#else
QWhatsThis::add( m_impulse,
#endif
tr(
"The 'Imp' selector determines whether the waveform in the graph is to be "
"treated as an impulse imparted to the string by the pick or the initial "
"state of the string." ) );
m_harmonic = new nineButtonSelector(
PLUGIN_NAME::getIconPixmap( "button_-2_on" ),
PLUGIN_NAME::getIconPixmap( "button_-2_off" ),
PLUGIN_NAME::getIconPixmap( "button_-1_on" ),
PLUGIN_NAME::getIconPixmap( "button_-1_off" ),
PLUGIN_NAME::getIconPixmap( "button_f_on" ),
PLUGIN_NAME::getIconPixmap( "button_f_off" ),
PLUGIN_NAME::getIconPixmap( "button_2_on" ),
PLUGIN_NAME::getIconPixmap( "button_2_off" ),
PLUGIN_NAME::getIconPixmap( "button_3_on" ),
PLUGIN_NAME::getIconPixmap( "button_3_off" ),
PLUGIN_NAME::getIconPixmap( "button_4_on" ),
PLUGIN_NAME::getIconPixmap( "button_4_off" ),
PLUGIN_NAME::getIconPixmap( "button_5_on" ),
PLUGIN_NAME::getIconPixmap( "button_5_off" ),
PLUGIN_NAME::getIconPixmap( "button_6_on" ),
PLUGIN_NAME::getIconPixmap( "button_6_off" ),
PLUGIN_NAME::getIconPixmap( "button_7_on" ),
PLUGIN_NAME::getIconPixmap( "button_7_off" ),
2,
21, 127,
this,
eng() );
m_harmonic->hide();
m_harmonics.append( m_harmonic );
#ifdef QT4
m_harmonic->setWhatsThis(
#else
QWhatsThis::add( m_harmonic,
#endif
tr(
"The Octave selector is used to choose which harmonic of the note the "
"string will ring at. For example, '-2' means the string will ring two "
"octaves below the fundamental, 'F' means the string will ring at the "
"fundamental, and '6' means the string will ring six octaves above the "
"fundamental." ) );
}
m_stringSelector = new nineButtonSelector(
PLUGIN_NAME::getIconPixmap( "button_1_on" ),
PLUGIN_NAME::getIconPixmap( "button_1_off" ),
PLUGIN_NAME::getIconPixmap( "button_2_on" ),
PLUGIN_NAME::getIconPixmap( "button_2_off" ),
PLUGIN_NAME::getIconPixmap( "button_3_on" ),
PLUGIN_NAME::getIconPixmap( "button_3_off" ),
PLUGIN_NAME::getIconPixmap( "button_4_on" ),
PLUGIN_NAME::getIconPixmap( "button_4_off" ),
PLUGIN_NAME::getIconPixmap( "button_5_on" ),
PLUGIN_NAME::getIconPixmap( "button_5_off" ),
PLUGIN_NAME::getIconPixmap( "button_6_on" ),
PLUGIN_NAME::getIconPixmap( "button_6_off" ),
PLUGIN_NAME::getIconPixmap( "button_7_on" ),
PLUGIN_NAME::getIconPixmap( "button_7_off" ),
PLUGIN_NAME::getIconPixmap( "button_8_on" ),
PLUGIN_NAME::getIconPixmap( "button_8_off" ),
PLUGIN_NAME::getIconPixmap( "button_9_on" ),
PLUGIN_NAME::getIconPixmap( "button_9_off" ),
0,
21, 39,
this,
eng() );
connect( m_stringSelector, SIGNAL( nineButtonSelection( Uint8 ) ),
this, SLOT( showString( Uint8 ) ) );
#ifdef QT4
m_stringSelector->setWhatsThis(
#else
QWhatsThis::add( m_stringSelector,
#endif
tr(
"The String selector is used to choose which string the controls are "
"editting. A Vibed instrument can contain up to nine independently "
"vibrating strings. The LED in the lower right corner of the "
"waveform editor indicates whether the selected string is active." ) );
m_pickKnob = m_pickKnobs.at( 0 );
m_pickupKnob = m_pickupKnobs.at( 0 );
m_stiffnessKnob = m_stiffnessKnobs.at( 0 );
m_volumeKnob = m_volumeKnobs.at( 0 );
m_panKnob = m_panKnobs.at( 0 );
m_detuneKnob = m_detuneKnobs.at( 0 );
m_randomKnob = m_randomKnobs.at( 0 );
m_lengthKnob = m_lengthKnobs.at( 0 );
m_editor = m_editors.at( 0 );
m_impulse = m_impulses.at( 0 );
m_harmonic = m_harmonics.at( 0 );
m_editor->setOn( TRUE );
showString( 0 );
#ifdef QT4
this->setWhatsThis(
#else
QWhatsThis::add( this,
#endif
tr(
"Vibed models up to nine independently vibrating strings. The 'String' "
"selector allows you to choose which string is being edited. The 'Imp' " "selector chooses whether the graph represents an impulse or the initial "
"state of the string. The 'Octave' selector chooses which harmonic the "
"string should vibrate at.\n\n"
"The graph allows you to control the initial state or impulse used to set the "
"string in motion.\n\n"
"The 'V' knob controls the volume. The 'S' knob controls the string's "
"stiffness. The 'P' knob controls the pick position. The 'PU' knob "
"controls the pickup position.\n\n"
"'Pan' and 'Detune' hopefully don't need explanation. The 'Slap' knob "
"adds a bit of fuzz to the sound of the string.\n\n"
"The 'Length' knob controls the length of the string.\n\n"
"The LED in the lower right corner of the waveform editor determines "
"whether the string is active in the current instrument." ) );
}
vibed::~vibed()
{
delete m_sampleBuffer;
m_pickKnobs.setAutoDelete( TRUE );
m_pickupKnobs.setAutoDelete( TRUE );
m_stiffnessKnobs.setAutoDelete( TRUE );
m_volumeKnobs.setAutoDelete( TRUE );
m_panKnobs.setAutoDelete( TRUE );
m_detuneKnobs.setAutoDelete( TRUE );
m_randomKnobs.setAutoDelete( TRUE );
m_lengthKnobs.setAutoDelete( TRUE );
m_editors.setAutoDelete( TRUE );
m_impulses.setAutoDelete( TRUE );
for( Uint8 harm = 0; harm < 9; harm++ )
{
m_pickKnobs.removeFirst();
m_pickupKnobs.removeFirst();
m_stiffnessKnobs.removeFirst();
m_volumeKnobs.removeFirst();
m_panKnobs.removeFirst();
m_detuneKnobs.removeFirst();
m_randomKnobs.removeFirst();
m_lengthKnobs.removeFirst();
m_editors.removeFirst();
m_impulses.removeFirst();
m_harmonics.removeFirst();
}
}
void vibed::saveSettings( QDomDocument & _doc,
QDomElement & _this )
{
QString name;
// Save plugin version
_this.setAttribute( "version", "0.1" );
for( Uint8 i = 0; i < 9; i++ )
{
name = "active" + QString::number( i );
_this.setAttribute( name, QString::number(
m_editors.at( i )->isOn() ) );
if( m_editors.at( i )->isOn() )
{
name = "volume" + QString::number( i );
_this.setAttribute( name, QString::number(
m_volumeKnobs.at( i )->value() ) );
name = "stiffness" + QString::number( i );
_this.setAttribute( name, QString::number(
m_stiffnessKnobs.at( i )->value() ) );
name = "pick" + QString::number( i );
_this.setAttribute( name, QString::number(
m_pickKnobs.at( i )->value() ) );
name = "pickup" + QString::number( i );
_this.setAttribute( name, QString::number(
m_pickupKnobs.at( i )->value() ) );
name = "length" + QString::number( i );
_this.setAttribute( name, QString::number(
m_lengthKnobs.at( i )->value() ) );
name = "pan" + QString::number( i );
_this.setAttribute( name, QString::number(
m_panKnobs.at( i )->value() ) );
name = "detune" + QString::number( i );
_this.setAttribute( name, QString::number(
m_detuneKnobs.at( i )->value() ) );
name = "slap" + QString::number( i );
_this.setAttribute( name, QString::number(
m_randomKnobs.at( i )->value() ) );
name = "impulse" + QString::number( i );
_this.setAttribute( name, QString::number(
m_impulses.at( i )->isChecked() ) );
QString sampleString;
base64::encode(
(const char *)m_editors.at( i )->getValues(),
128 * sizeof(float), sampleString );
name = "graph" + QString::number( i );
_this.setAttribute( name, sampleString );
}
}
}
void vibed::loadSettings( const QDomElement & _this )
{
QString name;
for( Uint8 i = 0; i < 9; i++ )
{
name = "active" + QString::number( i );
m_editors.at( i )->setOn( _this.attribute( name ).toInt() );
if( m_editors.at( i )->isOn() )
{
name = "volume" + QString::number( i );
m_volumeKnobs.at( i )->setValue(
_this.attribute( name ).toFloat() );
name = "stiffness" + QString::number( i );
m_stiffnessKnobs.at( i )->setValue(
_this.attribute( name ).toFloat() );
name = "pick" + QString::number( i );
m_pickKnobs.at( i )->setValue(
_this.attribute( name ).toFloat() );
name = "pickup" + QString::number( i );
m_pickupKnobs.at( i )->setValue(
_this.attribute( name ).toFloat() );
name = "length" + QString::number( i );
m_lengthKnobs.at( i )->setValue(
_this.attribute( name ).toFloat() );
name = "pan" + QString::number( i );
m_panKnobs.at( i )->setValue(
_this.attribute( name ).toFloat() );
name = "detune" + QString::number( i );
m_detuneKnobs.at( i )->setValue(
_this.attribute( name ).toFloat() );
name = "slap" + QString::number( i );
m_randomKnobs.at( i )->setValue(
_this.attribute( name ).toFloat() );
name = "impulse" + QString::number( i );
m_impulses.at( i )->setChecked(
_this.attribute( name ).toInt() );
name = "graph" + QString::number( i );
float shape[128];
int size = 0;
QString sampleString = _this.attribute( name );
char * dst = 0;
base64::decode( sampleString, &dst, &size );
memcpy( shape, dst, size );
m_editors.at( i )->setValues( shape );
}
}
update();
}
QString vibed::nodeName( void ) const
{
return( vibedstrings_plugin_descriptor.name );
}
void vibed::playNote( notePlayHandle * _n )
{
if ( _n->totalFramesPlayed() == 0 )
{
float freq = getInstrumentTrack()->frequency( _n );
_n->m_pluginData = new stringContainer(
freq,
eng()->getMixer()->sampleRate(),
m_sampleLength );
for( Uint8 i = 0; i < 9; i++ )
{
if( m_editors.at( i )->isOn() )
{
static_cast<stringContainer*>(
_n->m_pluginData )->addString(
m_harmonics.at( i )->getSelected(),
m_pickKnobs.at( i )->value(),
m_pickupKnobs.at( i )->value(),
m_editors.at( i )->getValues(),
m_randomKnobs.at( i )->value(),
m_stiffnessKnobs.at( i )->value(),
m_detuneKnobs.at( i )->value(),
static_cast<int>(
m_lengthKnobs.at( i )->value() ),
m_impulses.at( i )->isChecked() );
}
}
}
const Uint32 frames = eng()->getMixer()->framesPerAudioBuffer();
stringContainer * ps = static_cast<stringContainer *>(
_n->m_pluginData );
sampleFrame * buf = bufferAllocator::alloc<sampleFrame>( frames );
float vol;
float pan;
float sample;
Uint8 s;
for( Uint32 i = 0; i < frames; i++ )
{
buf[i][0] = 0.0f;
buf[i][1] = 0.0f;
s = 0;
for( Uint8 string = 0; string < 9; string ++ )
{
if( m_editors.at( string )->isOn() )
{
vol = m_volumeKnobs.at(
string )->value();
pan = (
m_panKnobs.at( string )->value() + 1 ) / 2.0;
sample = ps->getStringSample( s );
buf[i][0] += pan * vol * sample;
buf[i][1] += ( 1.0 - pan ) * vol * sample;
s++;
}
}
}
getInstrumentTrack()->processAudioBuffer( buf, frames, _n );
bufferAllocator::free( buf );
}
void vibed::deleteNotePluginData( notePlayHandle * _n )
{
delete static_cast<stringContainer *>( _n->m_pluginData );
}
void vibed::showString( Uint8 _string )
{
m_pickKnob->hide();
m_pickupKnob->hide();
m_stiffnessKnob->hide();
m_volumeKnob->hide();
m_panKnob->hide();
m_detuneKnob->hide();
m_randomKnob->hide();
m_lengthKnob->hide();
m_editor->hide();
m_impulse->hide();
m_harmonic->hide();
m_editors.at( _string )->show();
m_volumeKnobs.at( _string )->show();
m_stiffnessKnobs.at( _string )->show();
m_pickKnobs.at( _string )->show();
m_pickupKnobs.at( _string )->show();
m_panKnobs.at( _string )->show();
m_detuneKnobs.at( _string )->show();
m_randomKnobs.at( _string )->show();
m_lengthKnobs.at( _string )->show();
m_impulses.at( _string )->show();
m_impulses.at( _string )->update();
m_harmonics.at( _string )->show();
m_pickKnob = m_pickKnobs.at( _string );
m_pickupKnob = m_pickupKnobs.at( _string );
m_stiffnessKnob = m_stiffnessKnobs.at( _string );
m_volumeKnob = m_volumeKnobs.at( _string );
m_panKnob = m_panKnobs.at( _string );
m_detuneKnob = m_detuneKnobs.at( _string );
m_randomKnob = m_randomKnobs.at( _string );
m_lengthKnob = m_lengthKnobs.at( _string );
m_editor = m_editors.at( _string );
m_impulse = m_impulses.at( _string );
m_harmonic = m_harmonics.at( _string );
}
void vibed::contextMenuEvent( QContextMenuEvent * )
{
QMenu contextMenu( this );
#ifdef QT4
contextMenu.setTitle( accessibleName() );
#else
QLabel * caption = new QLabel( "<font color=white><b>" +
QString( "Vibed" ) + "</b></font>", this );
caption->setPaletteBackgroundColor( QColor( 0, 0, 192 ) );
caption->setAlignment( Qt::AlignCenter );
contextMenu.addAction( caption );
#endif
contextMenu.addAction( embed::getIconPixmap( "help" ), tr( "&Help" ),
this, SLOT( displayHelp() ) );
contextMenu.exec( QCursor::pos() );
}
void vibed::displayHelp( void )
{
#ifdef QT4
QWhatsThis::showText( mapToGlobal( rect().bottomRight() ),
whatsThis() );
#else
QWhatsThis::display( QWhatsThis::textFor( this ), mapToGlobal(
rect().bottomRight() ) );
#endif
}
extern "C"
{
// neccessary for getting instance out of shared lib
plugin * lmms_plugin_main( void * _data )
{
return( new vibed( static_cast<instrumentTrack *>( _data ) ) );
}
}
#include "vibed.moc"

100
plugins/vibed/vibed.h Normal file
View File

@@ -0,0 +1,100 @@
/* vibed_strings.h -
*
* Copyright (c) 2006 Danny McRae <khjklujn/at/yahoo/com>
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#ifndef _VIBED_STRINGS_H
#define _VIBED_STRINGS_H
#include <qptrlist.h>
#include "instrument.h"
#include "sample_buffer.h"
#include "graph.h"
#include "pixmap_button.h"
#include "buffer_allocator.h"
#include "led_checkbox.h"
#include "impulse_editor.h"
#include "lcd_spinbox.h"
#include "nine_button_selector.h"
class knob;
class notePlayHandle;
class vibed : public instrument
{
Q_OBJECT
public:
vibed( instrumentTrack * _channel_track );
virtual ~vibed();
virtual void FASTCALL playNote( notePlayHandle * _n );
virtual void FASTCALL deleteNotePluginData( notePlayHandle * _n );
virtual void FASTCALL saveSettings( QDomDocument & _doc,
QDomElement & _parent );
virtual void FASTCALL loadSettings( const QDomElement & _this );
virtual QString nodeName( void ) const;
public slots:
void showString( Uint8 _string );
void contextMenuEvent( QContextMenuEvent * );
void displayHelp( void );
private:
QPtrList<knob> m_pickKnobs;
QPtrList<knob> m_pickupKnobs;
QPtrList<knob> m_stiffnessKnobs;
QPtrList<knob> m_volumeKnobs;
QPtrList<knob> m_panKnobs;
QPtrList<knob> m_detuneKnobs;
QPtrList<knob> m_randomKnobs;
QPtrList<knob> m_lengthKnobs;
QPtrList<impulseEditor> m_editors;
QPtrList<ledCheckBox> m_impulses;
QPtrList<nineButtonSelector> m_harmonics;
knob * m_pickKnob;
knob * m_pickupKnob;
knob * m_stiffnessKnob;
knob * m_volumeKnob;
knob * m_panKnob;
knob * m_detuneKnob;
knob * m_randomKnob;
knob * m_lengthKnob;
impulseEditor * m_editor;
nineButtonSelector * m_stringSelector;
nineButtonSelector * m_harmonic;
ledCheckBox * m_impulse;
sampleBuffer * m_sampleBuffer;
int m_sampleLength;
} ;
#endif

View File

@@ -0,0 +1,158 @@
/*
* vibrating_sring.h - model of a vibrating string lifted from pluckedSynth
*
* Copyright (c) 2006 Danny McRae <khjklujn/at/yahoo/com>
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include <math.h>
#include "vibrating_string.h"
#include "templates.h"
#include "interpolation.h"
vibratingString::vibratingString( float _pitch,
float _pick,
float _pickup,
float * _impulse,
Uint32 _len,
sample_rate_t _sample_rate,
Uint8 _oversample,
float _randomize,
float _string_loss,
float _detune,
bool _state ):
m_oversample( _oversample ),
m_randomize( _randomize ),
m_stringLoss( 1.0f - _string_loss ),
m_state( 0.1f )
{
int string_length;
string_length = static_cast<int>( m_oversample *_sample_rate /
_pitch ) + 1;
string_length += static_cast<int>( string_length * -_detune );
int pick = static_cast<int>( ceil( string_length * _pick ) );
if( not _state )
{
m_impulse = bufferAllocator::alloc<float>( string_length );
resample( _impulse, _len, string_length );
}
else
{
m_impulse = bufferAllocator::alloc<float>( _len );
for( Uint32 i = 0; i < _len; i++ )
{
m_impulse[i] = _impulse[i];
}
}
m_toBridge = vibratingString::initDelayLine( string_length, pick );
m_fromBridge = vibratingString::initDelayLine( string_length, pick );
vibratingString::setDelayLine( m_toBridge, pick,
m_impulse, _len, 0.5f,
_state );
vibratingString::setDelayLine( m_fromBridge, pick,
m_impulse, _len, 0.5f,
_state);
m_choice = static_cast<int>( m_oversample *
static_cast<float>( rand() ) / RAND_MAX );
m_pickupLoc = static_cast<int>( _pickup * string_length );
}
vibratingString::delayLine * FASTCALL vibratingString::initDelayLine(
int _len,
int _pick )
{
delayLine * dl = new vibratingString::delayLine[_len];
dl->length = _len;
if( _len > 0 )
{
dl->data = new sample_t[_len];
float r;
float offset = 0.0f;
for( int i = 0; i < dl->length; i++ )
{
r = static_cast<float>( rand() ) /
RAND_MAX;
offset = ( m_randomize / 2.0f -
m_randomize ) * r;
dl->data[i] = offset;
}
}
else
{
dl->data = NULL;
}
dl->pointer = dl->data;
dl->end = dl->data + _len - 1;
return( dl );
}
void FASTCALL vibratingString::freeDelayLine( delayLine * _dl )
{
if( _dl && _dl->data )
{
delete[] _dl->data;
}
_dl->data = NULL;
delete[] _dl;
}
void FASTCALL vibratingString::resample( float *_src,
f_cnt_t _src_frames,
f_cnt_t _dst_frames )
{
for( f_cnt_t frame = 0; frame < _dst_frames; ++frame )
{
const float src_frame_float = frame *
(float) _src_frames /
_dst_frames;
const float frac_pos = src_frame_float -
static_cast<f_cnt_t>( src_frame_float );
const f_cnt_t src_frame = tLimit<f_cnt_t>(
static_cast<f_cnt_t>( src_frame_float ),
1, _src_frames - 3 );
m_impulse[frame] = cubicInterpolate(
_src[src_frame - 1],
_src[src_frame + 0],
_src[src_frame + 1],
_src[src_frame + 2],
frac_pos );
}
}

View File

@@ -0,0 +1,272 @@
/*
* vibrating_string.h - model of a vibrating string lifted from pluckedSynth
*
* Copyright (c) 2006 Danny McRae <khjklujn/at/yahoo/com>
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#ifndef _VIBRATING_STRING_H
#define _VIBRATING_STRING_H
#include <stdio.h>
#include <stdlib.h>
#include "config.h"
#include "types.h"
#include "buffer_allocator.h"
class vibratingString
{
public:
vibratingString( float _pitch,
float _pick,
float _pickup,
float * impluse,
Uint32 _len,
sample_rate_t _sample_rate,
Uint8 _oversample,
float _randomize,
float _string_loss,
float _detune,
bool _state );
inline ~vibratingString( void )
{
bufferAllocator::free( m_impulse );
vibratingString::freeDelayLine( m_fromBridge );
vibratingString::freeDelayLine( m_toBridge );
}
inline sample_t nextSample( void )
{
sample_t outsamp[m_oversample];
sample_t ym0;
sample_t ypM;
for( Uint8 i = 0; i < m_oversample; i++)
{
// Output at pickup position
outsamp[i] = fromBridgeAccess( m_fromBridge,
m_pickupLoc );
outsamp[i] += toBridgeAccess( m_toBridge,
m_pickupLoc );
// Sample traveling into "bridge"
ym0 = toBridgeAccess( m_toBridge, 1 );
// Sample to "nut"
ypM = fromBridgeAccess( m_fromBridge,
m_fromBridge->length - 2 );
// String state update
// Decrement pointer and then update
fromBridgeUpdate( m_fromBridge,
-bridgeReflection( ym0 ) );
// Update and then increment pointer
toBridgeUpdate( m_toBridge, -ypM );
}
return( outsamp[m_choice] );
}
private:
struct delayLine
{
sample_t * data;
int length;
sample_t * pointer;
sample_t * end;
} ;
delayLine * m_fromBridge;
delayLine * m_toBridge;
int m_pickupLoc;
Uint8 m_oversample;
float m_randomize;
float m_stringLoss;
float * m_impulse;
int m_choice;
float m_state;
delayLine * FASTCALL initDelayLine( int _len, int _pick );
static void FASTCALL freeDelayLine( delayLine * _dl );
void FASTCALL resample( float *_src,
sample_rate_t _src_frames,
sample_rate_t _dst_frames );
/* setDelayLine initializes the string with an impulse at the pick
* position unless the impulse is longer than the string, in which
* case the impulse gets truncated. */
inline void setDelayLine( delayLine * _dl,
int _pick,
const float * _values,
int _len,
float _scale,
bool _state )
{
float r;
float offset;
if( not _state )
{
for( int i = 0; i < _pick; i++ )
{
r = static_cast<float>( rand() ) /
RAND_MAX;
offset = ( m_randomize / 2.0f -
m_randomize ) * r;
_dl->data[i] = _scale *
_values[_dl->length - i] +
offset;
}
for( int i = _pick; i < _dl->length; i++ )
{
r = static_cast<float>( rand() ) /
RAND_MAX;
offset = ( m_randomize / 2.0f -
m_randomize ) * r;
_dl->data[i] = _scale *
_values[i - _pick] + offset ;
}
}
else
{
if( _len + _pick > _dl->length )
{
for( int i = _pick; i < _dl->length; i++ )
{
r = static_cast<float>( rand() ) /
RAND_MAX;
offset = ( m_randomize / 2.0f -
m_randomize ) * r;
_dl->data[i] = _scale *
_values[i-_pick] +
offset;
}
}
else
{
for( int i = 0; i < _len; i++ )
{
r = static_cast<float>( rand() ) /
RAND_MAX;
offset = ( m_randomize / 2.0f -
m_randomize ) * r;
_dl->data[i+_pick] = _scale *
_values[i] +
offset;
}
}
}
}
/* toBridgeUpdate(dl, insamp);
* Places "nut-reflected" sample from upper delay-line into
* current lower delay-line pointer position (which represents
* x = 0 position). The pointer is then incremented (i.e. the
* wave travels one sample to the left), turning the previous
* position into an "effective" x = L position for the next
* iteration. */
inline void toBridgeUpdate( delayLine * _dl, sample_t _insamp )
{
register sample_t * ptr = _dl->pointer;
*ptr = _insamp * m_stringLoss;
++ptr;
if( ptr > _dl->end )
{
ptr = _dl->data;
}
_dl->pointer = ptr;
}
/* fromBridgeUpdate(dl, insamp);
* Decrements current upper delay-line pointer position (i.e.
* the wave travels one sample to the right), moving it to the
* "effective" x = 0 position for the next iteration. The
* "bridge-reflected" sample from lower delay-line is then placed
* into this position. */
inline void fromBridgeUpdate( delayLine * _dl,
sample_t _insamp )
{
register sample_t * ptr = _dl->pointer;
--ptr;
if( ptr < _dl->data )
{
ptr = _dl->end;
}
*ptr = _insamp * m_stringLoss;
_dl->pointer = ptr;
}
/* dlAccess(dl, position);
* Returns sample "position" samples into delay-line's past.
* Position "0" points to the most recently inserted sample. */
static inline sample_t dlAccess( delayLine * _dl, int _position )
{
sample_t * outpos = _dl->pointer + _position;
while( outpos < _dl->data )
{
outpos += _dl->length;
}
while( outpos > _dl->end )
{
outpos -= _dl->length;
}
return( *outpos );
}
/*
* Right-going delay line:
* -->---->---->---
* x=0
* (pointer)
* Left-going delay line:
* --<----<----<---
* x=0
* (pointer)
*/
/* fromBridgeAccess(dl, position);
* Returns spatial sample at position "position", where position zero
* is equal to the current upper delay-line pointer position (x = 0).
* In a right-going delay-line, position increases to the right, and
* delay increases to the right => left = past and right = future. */
static inline sample_t fromBridgeAccess( delayLine * _dl,
int _position )
{
return( dlAccess( _dl, _position ) );
}
/* toBridgeAccess(dl, position);
* Returns spatial sample at position "position", where position zero
* is equal to the current lower delay-line pointer position (x = 0).
* In a left-going delay-line, position increases to the right, and
* delay DEcreases to the right => left = future and right = past. */
static inline sample_t toBridgeAccess( delayLine * _dl, int _position )
{
return( dlAccess( _dl, _position ) );
}
inline sample_t bridgeReflection( sample_t _insamp )
{
return( m_state = ( m_state + _insamp ) * 0.5 );
}
} ;
#endif

Binary file not shown.

View File

@@ -472,9 +472,10 @@ void arpAndChordsTabWidget::processNote( notePlayHandle * _n )
// now follows code for arpeggio
if( _n->baseNote() == FALSE || m_arpDirectionBtnGrp->value() == OFF ||
!m_arpGroupBox->isActive() ||
( _n->released() && _n->releaseFramesDone() >=
if( _n->baseNote() == FALSE ||
( m_arpDirectionBtnGrp->value() + 1) == OFF ||
!m_arpGroupBox->isActive() ||
( _n->released() && _n->releaseFramesDone() >=
_n->actualReleaseFramesToDo() ) )
{
return;
@@ -483,13 +484,13 @@ void arpAndChordsTabWidget::processNote( notePlayHandle * _n )
const int selected_arp = m_arpComboBox->value();
constNotePlayHandleVector cnphv = notePlayHandle::nphsOfChannelTrack(
_n->getInstrumentTrack() );
constNotePlayHandleVector cnphv = notePlayHandle::nphsOfInstrumentTrack(
_n->getInstrumentTrack() );
if( m_arpModeComboBox->value() != FREE && cnphv.size() == 0 )
{
// maybe we're playing only a preset-preview-note?
cnphv = presetPreviewPlayHandle::nphsOfChannelTrack(
_n->getInstrumentTrack() );
cnphv = presetPreviewPlayHandle::nphsOfInstrumentTrack(
_n->getInstrumentTrack() );
if( cnphv.size() == 0 )
{
// still nothing found here, so lets return
@@ -654,7 +655,7 @@ void arpAndChordsTabWidget::saveSettings( QDomDocument & _doc,
_this.setAttribute( "arprange", m_arpRangeKnob->value() );
_this.setAttribute( "arptime", m_arpTimeKnob->value() );
_this.setAttribute( "arpgate", m_arpGateKnob->value() );
_this.setAttribute( "arpdir", m_arpDirectionBtnGrp->value() );
_this.setAttribute( "arpdir", m_arpDirectionBtnGrp->value() + 1 );
_this.setAttribute( "arpsyncmode",
( int ) m_arpTimeKnob->getSyncMode() );
@@ -675,14 +676,14 @@ void arpAndChordsTabWidget::loadSettings( const QDomElement & _this )
m_arpTimeKnob->setValue( _this.attribute( "arptime" ).toFloat() );
m_arpGateKnob->setValue( _this.attribute( "arpgate" ).toFloat() );
m_arpDirectionBtnGrp->setInitValue(
_this.attribute( "arpdir" ).toInt() );
_this.attribute( "arpdir" ).toInt() - 1 );
m_arpTimeKnob->setSyncMode(
( tempoSyncKnob::tempoSyncMode ) _this.attribute(
"arpsyncmode" ).toInt() );
m_arpModeComboBox->setValue( _this.attribute( "arpmode" ).toInt() );
m_arpGroupBox->setState( m_arpDirectionBtnGrp->value() != OFF &&
m_arpGroupBox->setState( _this.attribute( "arpdir" ).toInt() != OFF &&
!_this.attribute( "arpdisabled" ).toInt() );
}

View File

@@ -27,6 +27,7 @@
#include "import_filter.h"
#include "track_container.h"
#include "project_journal.h"
#ifdef QT4
@@ -75,6 +76,10 @@ void importFilter::import( const QString & _file_to_import,
#endif
);
// do not record changes while importing files
const bool j = _tc->eng()->getProjectJournal()->isJournalling();
_tc->eng()->getProjectJournal()->setJournalling( FALSE );
for( vvector<plugin::descriptor>::iterator it = d.begin();
it != d.end(); ++it )
{
@@ -93,6 +98,8 @@ void importFilter::import( const QString & _file_to_import,
}
}
_tc->eng()->getProjectJournal()->setJournalling( j );
delete[] s;
if( successful == FALSE )

View File

@@ -348,7 +348,7 @@ int notePlayHandle::index( void ) const
constNotePlayHandleVector notePlayHandle::nphsOfChannelTrack(
constNotePlayHandleVector notePlayHandle::nphsOfInstrumentTrack(
const instrumentTrack * _it )
{
const playHandleVector & phv = _it->eng()->getMixer()->playHandles();

View File

@@ -56,12 +56,15 @@ class previewTrackContainer : public trackContainer
public:
previewTrackContainer( engine * _engine ) :
trackContainer( _engine ),
m_previewChannelTrack( dynamic_cast<instrumentTrack *>(
track::create( track::CHANNEL_TRACK,
this ) )),
m_previewInstrumentTrack( NULL ),
m_previewNote( NULL ),
m_dataMutex()
{
setJournalling( FALSE );
m_previewInstrumentTrack = dynamic_cast<instrumentTrack *>(
track::create( track::CHANNEL_TRACK,
this ) );
m_previewInstrumentTrack->setJournalling( FALSE );
hide();
}
@@ -81,9 +84,9 @@ public:
return( "previewtc" );
}
instrumentTrack * previewChannelTrack( void )
instrumentTrack * previewInstrumentTrack( void )
{
return( m_previewChannelTrack );
return( m_previewInstrumentTrack );
}
notePlayHandle * previewNote( void )
@@ -108,7 +111,7 @@ public:
private:
instrumentTrack * m_previewChannelTrack;
instrumentTrack * m_previewInstrumentTrack;
notePlayHandle * m_previewNote;
QMutex m_dataMutex;
@@ -141,21 +144,21 @@ presetPreviewPlayHandle::presetPreviewPlayHandle(
multimediaProject mmp( _preset_file );
previewTC()->previewChannelTrack()->loadTrackSpecificSettings(
printf("load track sp\n");
previewTC()->previewInstrumentTrack()->loadTrackSpecificSettings(
mmp.content().firstChild().toElement() );
printf("here\n");
// make sure, our preset-preview-track does not appear in any MIDI-
// devices list, so just disable receiving/sending MIDI-events at all
previewTC()->previewChannelTrack()->m_midiPort->setMode(
previewTC()->previewInstrumentTrack()->m_midiPort->setMode(
midiPort::DUMMY );
// create temporary note
note n();
// create note-play-handle for it
m_previewNote = new notePlayHandle( previewTC()->previewChannelTrack(),
0, ~0,
m_previewNote = new notePlayHandle(
previewTC()->previewInstrumentTrack(), 0, ~0,
note( NULL, 0, 0, static_cast<tones>( A ),
static_cast<octaves>( DEFAULT_OCTAVE-1 ), 100 ) );
static_cast<octaves>( DEFAULT_OCTAVE - 1 ), 100 ) );
previewTC()->setPreviewNote( m_previewNote );
@@ -210,7 +213,7 @@ void presetPreviewPlayHandle::cleanUp( engine * _engine )
constNotePlayHandleVector presetPreviewPlayHandle::nphsOfChannelTrack(
constNotePlayHandleVector presetPreviewPlayHandle::nphsOfInstrumentTrack(
const instrumentTrack * _it )
{
constNotePlayHandleVector cnphv;

View File

@@ -1368,7 +1368,8 @@ void songEditor::clearProject( void )
eng()->getProjectNotes()->clear();
eng()->getProjectJournal()->clear();
eng()->getProjectJournal()->clearInvalidJournallingObjects();
eng()->getProjectJournal()->clearJournal();
eng()->getProjectJournal()->setJournalling( TRUE );
}

View File

@@ -595,7 +595,7 @@ trackContentWidget::~trackContentWidget()
trackContentObject * FASTCALL trackContentWidget::getTCO( csize _tco_num )
trackContentObject * trackContentWidget::getTCO( csize _tco_num )
{
if( _tco_num < m_trackContentObjects.size() )
{
@@ -618,8 +618,7 @@ csize trackContentWidget::numOfTCOs( void )
trackContentObject * FASTCALL trackContentWidget::addTCO(
trackContentObject * _tco )
trackContentObject * trackContentWidget::addTCO( trackContentObject * _tco )
{
QMap<QString, QVariant> map;
map["id"] = _tco->id();
@@ -639,7 +638,7 @@ trackContentObject * FASTCALL trackContentWidget::addTCO(
void FASTCALL trackContentWidget::removeTCO( csize _tco_num, bool _also_delete )
void trackContentWidget::removeTCO( csize _tco_num, bool _also_delete )
{
removeTCO( getTCO( _tco_num ), _also_delete );
}
@@ -661,10 +660,12 @@ void trackContentWidget::removeTCO( trackContentObject * _tco,
map["id"] = _tco->id();
map["state"] = mmp.toString();
addJournalEntry( journalEntry( REMOVE_TCO, map ) );
if( _also_delete )
{
delete _tco;
}
m_trackContentObjects.erase( it );
getTrack()->eng()->getSongEditor()->setModified();
}
@@ -873,15 +874,16 @@ void trackContentWidget::undoStep( journalEntry & _je )
case ADD_TCO:
{
QMap<QString, QVariant> map = _je.data().toMap();
journallingObject * jo =
eng()->getProjectJournal()->getJournallingObject( map["id"].toInt() );
assert( jo != NULL );
trackContentObject * tco =
dynamic_cast<trackContentObject *>(
eng()->getProjectJournal()->getJournallingObject( map["id"].toInt() ) );
assert( tco != NULL );
multimediaProject mmp(
multimediaProject::JOURNAL_DATA );
jo->saveState( mmp, mmp.content() );
tco->saveState( mmp, mmp.content() );
map["state"] = mmp.toString();
_je.data() = map;
delete jo;
tco->close();
break;
}
@@ -1141,6 +1143,7 @@ void trackOperationsWidget::muteBtnRightClicked( void )
trackWidget::trackWidget( track * _track, QWidget * _parent ) :
QWidget( _parent ),
journallingObject( _track->eng() ),
m_track( _track ),
m_trackOperationsWidget( this ),
m_trackSettingsWidget( this ),
@@ -1232,6 +1235,46 @@ void trackWidget::changePosition( const midiTime & _new_pos )
void trackWidget::undoStep( journalEntry & _je )
{
saveJournallingState( FALSE );
switch( _je.actionID() )
{
case MOVE_TRACK:
{
trackContainer * tc = m_track->getTrackContainer();
if( _je.data().toInt() > 0 )
{
tc->moveTrackUp( m_track );
}
else
{
tc->moveTrackDown( m_track );
}
break;
}
case RESIZE_TRACK:
setFixedHeight( tMax<int>( height() +
_je.data().toInt(),
MINIMAL_TRACK_HEIGHT ) );
m_track->getTrackContainer()->realignTracks();
break;
}
restoreJournallingState();
}
void trackWidget::redoStep( journalEntry & _je )
{
journalEntry je( _je.actionID(), -_je.data().toInt() );
undoStep( je );
}
void trackWidget::dragEnterEvent( QDragEnterEvent * _dee )
{
stringPairDrag::processDragEnterEvent( _dee, "track_" +
@@ -1320,6 +1363,7 @@ void trackWidget::mouseMoveEvent( QMouseEvent * _me )
{
tc->moveTrackDown( m_track );
}
addJournalEntry( journalEntry( MOVE_TRACK, _me->y() ) );
}
}
else if( m_action == RESIZE_TRACK )
@@ -1429,7 +1473,7 @@ track::~track()
track * FASTCALL track::create( trackTypes _tt, trackContainer * _tc )
track * track::create( trackTypes _tt, trackContainer * _tc )
{
// while adding track, pause mixer for not getting into any trouble
// because of track being not created completely so far
@@ -1460,8 +1504,7 @@ track * FASTCALL track::create( trackTypes _tt, trackContainer * _tc )
track * FASTCALL track::create( const QDomElement & _this,
trackContainer * _tc )
track * track::create( const QDomElement & _this, trackContainer * _tc )
{
track * t = create( static_cast<trackTypes>( _this.attribute(
"type" ).toInt() ), _tc );
@@ -1472,7 +1515,7 @@ track * FASTCALL track::create( const QDomElement & _this,
track * FASTCALL track::clone( track * _track )
track * track::clone( track * _track )
{
QDomDocument doc;
QDomElement parent = doc.createElement( "clone" );
@@ -1492,7 +1535,7 @@ tact track::length( void ) const
void FASTCALL track::saveSettings( QDomDocument & _doc, QDomElement & _this )
void track::saveSettings( QDomDocument & _doc, QDomElement & _this )
{
csize num_of_tcos = getTrackContentWidget()->numOfTCOs();
@@ -1518,7 +1561,7 @@ void FASTCALL track::saveSettings( QDomDocument & _doc, QDomElement & _this )
void FASTCALL track::loadSettings( const QDomElement & _this )
void track::loadSettings( const QDomElement & _this )
{
if( _this.attribute( "type" ).toInt() != type() )
{
@@ -1550,7 +1593,11 @@ void FASTCALL track::loadSettings( const QDomElement & _this )
trackContentObject * tco = createTCO(
midiTime( 0 ) );
tco->restoreState( node.toElement() );
getTrackContentWidget()->saveJournallingState(
FALSE );
addTCO( tco );
getTrackContentWidget()->
restoreJournallingState();
}
}
node = node.nextSibling();
@@ -1566,7 +1613,7 @@ void FASTCALL track::loadSettings( const QDomElement & _this )
trackContentObject * FASTCALL track::addTCO( trackContentObject * _tco )
trackContentObject * track::addTCO( trackContentObject * _tco )
{
return( getTrackContentWidget()->addTCO( _tco ) );
}
@@ -1574,7 +1621,7 @@ trackContentObject * FASTCALL track::addTCO( trackContentObject * _tco )
void FASTCALL track::removeTCO( csize _tco_num )
void track::removeTCO( csize _tco_num )
{
getTrackContentWidget()->removeTCO( _tco_num );
}
@@ -1590,7 +1637,7 @@ csize track::numOfTCOs( void )
trackContentObject * FASTCALL track::getTCO( csize _tco_num )
trackContentObject * track::getTCO( csize _tco_num )
{
return( getTrackContentWidget()->getTCO( _tco_num ) );
@@ -1599,7 +1646,7 @@ trackContentObject * FASTCALL track::getTCO( csize _tco_num )
csize FASTCALL track::getTCONum( trackContentObject * _tco )
csize track::getTCONum( trackContentObject * _tco )
{
for( csize i = 0; i < getTrackContentWidget()->numOfTCOs(); ++i )
{
@@ -1608,16 +1655,14 @@ csize FASTCALL track::getTCONum( trackContentObject * _tco )
return( i );
}
}
#ifdef LMMS_DEBUG
qFatal( "track::getTCONum(...) -> _tco not found!\n" );
#endif
qWarning( "track::getTCONum(...) -> _tco not found!\n" );
return( 0 );
}
void FASTCALL track::getTCOsInRange( vlist<trackContentObject *> & _tco_v,
void track::getTCOsInRange( vlist<trackContentObject *> & _tco_v,
const midiTime & _start,
const midiTime & _end )
{
@@ -1655,7 +1700,7 @@ void FASTCALL track::getTCOsInRange( vlist<trackContentObject *> & _tco_v,
void FASTCALL track::swapPositionOfTCOs( csize _tco_num1, csize _tco_num2 )
void track::swapPositionOfTCOs( csize _tco_num1, csize _tco_num2 )
{
getTrackContentWidget()->swapPositionOfTCOs( _tco_num1, _tco_num2 );
}

View File

@@ -61,6 +61,7 @@
#include "import_filter.h"
#include "instrument.h"
#include "rubberband.h"
#include "project_journal.h"
@@ -202,6 +203,10 @@ void trackContainer::cloneTrack( track * _track )
void trackContainer::addTrack( track * _track )
{
QMap<QString, QVariant> map;
map["id"] = _track->id();
addJournalEntry( journalEntry( ADD_TRACK, map ) );
m_trackWidgets.push_back( _track->getTrackWidget() );
#ifndef QT4
m_scrollArea->addChild( _track->getTrackWidget() );
@@ -221,6 +226,13 @@ void trackContainer::removeTrack( track * _track )
m_trackWidgets.end(), _track->getTrackWidget() );
if( it != m_trackWidgets.end() )
{
QMap<QString, QVariant> map;
multimediaProject mmp( multimediaProject::JOURNAL_DATA );
_track->saveState( mmp, mmp.content() );
map["id"] = _track->id();
map["state"] = mmp.toString();
addJournalEntry( journalEntry( REMOVE_TRACK, map ) );
eng()->getMixer()->pause();
#ifndef QT4
m_scrollArea->removeChild( _track->getTrackWidget() );
@@ -417,6 +429,60 @@ void trackContainer::setPixelsPerTact( Uint16 _ppt )
void trackContainer::undoStep( journalEntry & _je )
{
saveJournallingState( FALSE );
switch( _je.actionID() )
{
case ADD_TRACK:
{
QMap<QString, QVariant> map = _je.data().toMap();
track * tr =
dynamic_cast<track *>(
eng()->getProjectJournal()->getJournallingObject( map["id"].toInt() ) );
assert( tr != NULL );
multimediaProject mmp(
multimediaProject::JOURNAL_DATA );
tr->saveState( mmp, mmp.content() );
map["state"] = mmp.toString();
_je.data() = map;
removeTrack( tr );
break;
}
case REMOVE_TRACK:
{
multimediaProject mmp(
_je.data().toMap()["state"].toString(), FALSE );
track::create( mmp.content().firstChild().toElement(),
this );
break;
}
}
restoreJournallingState();
}
void trackContainer::redoStep( journalEntry & _je )
{
switch( _je.actionID() )
{
case ADD_TRACK:
case REMOVE_TRACK:
_je.actionID() = ( _je.actionID() == ADD_TRACK ) ?
REMOVE_TRACK : ADD_TRACK;
undoStep( _je );
_je.actionID() = ( _je.actionID() == ADD_TRACK ) ?
REMOVE_TRACK : ADD_TRACK;
break;
}
}
void trackContainer::dragEnterEvent( QDragEnterEvent * _dee )
{
stringPairDrag::processDragEnterEvent( _dee,

View File

@@ -69,6 +69,7 @@ journallingObject::~journallingObject()
void journallingObject::undo( void )
{
printf("undo: %d\n", id() );
if( m_journalEntries.empty() == TRUE )
{
return;
@@ -85,6 +86,7 @@ void journallingObject::undo( void )
void journallingObject::redo( void )
{
printf("undo: %d\n", id() );
if( m_journalEntries.empty() == TRUE )
{
return;
@@ -103,9 +105,9 @@ QDomElement journallingObject::saveState( QDomDocument & _doc,
QDomElement & _parent )
{
QDomElement _this = _doc.createElement( nodeName() );
_parent.appendChild( _this );
saveSettings( _doc, _this );
saveJournal( _doc, _this );
_parent.appendChild( _this );
return( _this );
}
@@ -115,7 +117,11 @@ QDomElement journallingObject::saveState( QDomDocument & _doc,
void journallingObject::restoreState( const QDomElement & _this )
{
saveJournallingState( FALSE );
// load actual settings
loadSettings( _this );
// search for journal-node
QDomNode node = _this.firstChild();
while( !node.isNull() )
{
@@ -125,13 +131,14 @@ void journallingObject::restoreState( const QDomElement & _this )
}
node = node.nextSibling();
}
restoreJournallingState();
}
void journallingObject::addJournalEntry( const journalEntry & _edit_step )
void journallingObject::addJournalEntry( const journalEntry & _je )
{
if( !( eng() == NULL ||
eng()->getProjectJournal()->isJournalling() == FALSE ||
@@ -139,7 +146,7 @@ void journallingObject::addJournalEntry( const journalEntry & _edit_step )
{
m_journalEntries.erase( m_currentJournalEntry,
m_journalEntries.end() );
m_journalEntries.push_back( _edit_step );
m_journalEntries.push_back( _je );
m_currentJournalEntry = m_journalEntries.end();
eng()->getProjectJournal()->journalEntryAdded( id() );
}

View File

@@ -152,10 +152,8 @@ multimediaProject::multimediaProject( const QString & _in_file_name,
}
}
QDomElement root = documentElement();
m_type = type( root.attribute( "type" ) );
QDomNode node = root.firstChild();
while( !node.isNull() )
{
@@ -308,7 +306,10 @@ QString multimediaProject::typeName( projectTypes _project_type )
{
if( _project_type >= UNKNOWN && _project_type < PROJ_TYPE_COUNT )
{
return( s_types[_project_type].m_name );
return( s_types[_project_type].m_name
#warning compat-code, remove in 0.3.0
.section( ',', 0, 0 )
);
}
return( s_types[UNKNOWN].m_name );
}

View File

@@ -80,6 +80,7 @@ void projectJournal::redo( void )
journallingObject * jo;
printf("%d\n", m_joIDs[*(m_currentJournalEntry+1)] );
if( m_currentJournalEntry < m_journalEntries.end() &&
( jo = m_joIDs[*m_currentJournalEntry++] ) != NULL )
{
@@ -97,7 +98,7 @@ void projectJournal::journalEntryAdded( const jo_id_t _id )
m_journalEntries.push_back( _id );
m_currentJournalEntry = m_journalEntries.end();
eng()->getSongEditor()->setModified();
printf("history size:%d\n", m_journalEntries.size());
printf("history size: %d\n", m_journalEntries.size() );
}
@@ -122,7 +123,7 @@ jo_id_t projectJournal::allocID( journallingObject * _obj )
void projectJournal::reallocID( const jo_id_t _id, journallingObject * _obj )
{
//printf("realloc %d %d\n", _id, _obj);
//printf("realloc %d %d\n", _id, _obj );
if( m_joIDs.contains( _id ) )
{
m_joIDs[_id] = _obj;
@@ -134,6 +135,7 @@ void projectJournal::reallocID( const jo_id_t _id, journallingObject * _obj )
void projectJournal::forgetAboutID( const jo_id_t _id )
{
printf("forget about %d\n", _id );
journalEntryVector::iterator it;
while( ( it = qFind( m_journalEntries.begin(), m_journalEntries.end(),
_id ) ) != m_journalEntries.end() )
@@ -150,12 +152,22 @@ void projectJournal::forgetAboutID( const jo_id_t _id )
void projectJournal::clear( void )
void projectJournal::clearInvalidJournallingObjects( void )
{
while( m_joIDs.size() )
vlist<journallingObject *>::const_iterator it;
for( joIDMap::iterator it = m_joIDs.begin(); it != m_joIDs.end(); )
{
forgetAboutID( m_joIDs.keys().front() );
if( it.data() == NULL )
{
forgetAboutID( it.key() );
it = m_joIDs.begin();
}
else
{
++it;
}
}
//clearJournal();
}

View File

@@ -357,7 +357,8 @@ bool FASTCALL bbTrack::play( const midiTime & _start,
{
if( _tco_num >= 0 )
{
return( eng()->getBBEditor()->play( _start, _start_frame, _frames,
return( eng()->getBBEditor()->play( _start, _start_frame,
_frames,
_frame_base,
s_infoMap[this] ) );
}
@@ -424,7 +425,8 @@ void bbTrack::saveTrackSpecificSettings( QDomDocument & _doc,
/* _this.setAttribute( "current", s_infoMap[this] ==
eng()->getBBEditor()->currentBB() );*/
if( s_infoMap[this] == 0 &&
_this.parentNode().nodeName() != "clone" )
_this.parentNode().nodeName() != "clone" &&
_this.parentNode().nodeName() != "journaldata" )
{
eng()->getBBEditor()->saveState( _doc, _this );
}

View File

@@ -415,7 +415,9 @@ void instrumentTrack::saveSettingsBtnClicked( void )
{
multimediaProject mmp(
multimediaProject::INSTRUMENT_TRACK_SETTINGS );
saveTrackSpecificSettings( mmp, mmp.content() );
QDomElement _this = mmp.createElement( nodeName() );
saveTrackSpecificSettings( mmp, _this );
mmp.content().appendChild( _this );
#ifdef QT4
mmp.writeFile( sfd.selectedFiles()[0] );
#else

View File

@@ -419,7 +419,7 @@ void pattern::saveSettings( QDomDocument & _doc, QDomElement & _this )
// pattern, we must not store actual position, instead we store -1
// which tells loadSettings() not to mess around with position
if( _this.parentNode().nodeName() == "clipboard" ||
_this.parentNode().nodeName() == "dnddata" )
_this.parentNode().nodeName() == "dnddata" )
{
_this.setAttribute( "pos", -1 );
}