completely new MIDI-subsystem and other bugfixes, see ChangeLog for details

git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@20 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
Tobias Doerffel
2005-10-24 09:13:39 +00:00
parent d959938370
commit 40d8b3c4f6
53 changed files with 2739 additions and 387 deletions

View File

@@ -44,6 +44,11 @@
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "arp_and_chords_tab_widget.h"
#include "embed.h"
#include "note_play_handle.h"
@@ -54,10 +59,7 @@
#include "tooltip.h"
#include "gui_templates.h"
#include "tempo_sync_knob.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "channel_track.h"
@@ -194,12 +196,10 @@ const int ARP_GROUPBOX_HEIGHT = 200 - ARP_GROUPBOX_Y;
arpAndChordsTabWidget::arpAndChordsTabWidget( channelTrack * _channel_track,
QWidget * _parent ) :
QWidget( _parent ),
arpAndChordsTabWidget::arpAndChordsTabWidget( channelTrack * _channel_track ) :
QWidget( _channel_track->tabWidgetParent() ),
settings(),
m_arpDirection( UP ),
m_channelTrack( _channel_track )
m_arpDirection( UP )
{
m_chordsGroupBox = new groupBox( tr( "CHORDS" ), this );
m_chordsGroupBox->setGeometry( CHORDS_GROUPBOX_X, CHORDS_GROUPBOX_Y,
@@ -604,41 +604,41 @@ void arpAndChordsTabWidget::processNote( notePlayHandle * _n )
void arpAndChordsTabWidget::saveSettings( QDomDocument & _doc,
QDomElement & _parent )
{
QDomElement elw_de = _doc.createElement( nodeName() );
elw_de.setAttribute( "chorddisabled", QString::number(
QDomElement act_de = _doc.createElement( nodeName() );
act_de.setAttribute( "chorddisabled", QString::number(
!m_chordsGroupBox->isActive() ) );
#ifdef QT4
elw_de.setAttribute( "chord", QString::number(
act_de.setAttribute( "chord", QString::number(
m_chordsComboBox->currentIndex() ) );
#else
elw_de.setAttribute( "chord", QString::number(
act_de.setAttribute( "chord", QString::number(
m_chordsComboBox->currentItem() ) );
#endif
elw_de.setAttribute( "chordrange", QString::number(
act_de.setAttribute( "chordrange", QString::number(
m_chordRangeKnob->value() ) );
elw_de.setAttribute( "arpdisabled", QString::number(
act_de.setAttribute( "arpdisabled", QString::number(
!m_arpGroupBox->isActive() ) );
#ifdef QT4
elw_de.setAttribute( "arp", QString::number(
act_de.setAttribute( "arp", QString::number(
m_arpComboBox->currentIndex() ) );
#else
elw_de.setAttribute( "arp", QString::number(
act_de.setAttribute( "arp", QString::number(
m_arpComboBox->currentItem() ) );
#endif
elw_de.setAttribute( "arprange", QString::number(
act_de.setAttribute( "arprange", QString::number(
m_arpRangeKnob->value() ) );
elw_de.setAttribute( "arptime", QString::number(
act_de.setAttribute( "arptime", QString::number(
m_arpTimeKnob->value() ) );
elw_de.setAttribute( "arpgate", QString::number(
act_de.setAttribute( "arpgate", QString::number(
m_arpGateKnob->value() ) );
elw_de.setAttribute( "arpdir", QString::number(
act_de.setAttribute( "arpdir", QString::number(
m_arpDirection ) );
elw_de.setAttribute( "arpsyncmode", QString::number(
( int ) m_arpTimeKnob->getSyncMode() ) );
act_de.setAttribute( "arpsyncmode", QString::number(
( int ) m_arpTimeKnob->getSyncMode() ) );
_parent.appendChild( elw_de );
_parent.appendChild( act_de );
}

View File

@@ -52,6 +52,8 @@
#include "tab_widget.h"
#include "embed.h"
#include "gui_templates.h"
#include "channel_track.h"
const int TARGETS_TABWIDGET_X = 4;
@@ -82,11 +84,9 @@ static const QString targetNames[envelopeTabWidget::TARGET_COUNT][2] =
envelopeTabWidget::envelopeTabWidget( channelTrack * _channel_track,
QWidget * _parent ) :
QWidget( _parent ),
settings(),
m_channelTrack( _channel_track )
envelopeTabWidget::envelopeTabWidget( channelTrack * _channel_track ) :
QWidget( _channel_track->tabWidgetParent() ),
settings()
{
m_targetsTabWidget = new tabWidget( tr( "TARGET" ), this );

756
src/core/file_browser.cpp Normal file
View File

@@ -0,0 +1,756 @@
/*
* file_browser.cpp - implementation of the project-, preset- and sample-file-browser
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <QPushButton>
#include <QKeyEvent>
#include <QMenu>
#else
#include <qpushbutton.h>
#include <qpopupmenu.h>
#endif
#include "file_browser.h"
#include "song_editor.h"
#include "bb_editor.h"
#include "embed.h"
#include "channel_track.h"
#include "mmp.h"
#include "preset_preview_play_handle.h"
#include "sample_play_handle.h"
#include "debug.h"
#include "gui_templates.h"
#include "instrument.h"
fileBrowser::fileBrowser( const QString & _path, const QString & _filter,
const QString & _title, const QPixmap & _pm,
QWidget * _parent ) :
sideBarWidget( _title, _pm, _parent ),
m_contextMenuItem( NULL ),
m_path( _path ),
m_filter( _filter ),
m_previewPlayHandle( NULL )
{
setWindowTitle( tr( "Browser" ) );
m_l = new Q3ListView( contentParent() );
addContentWidget( m_l );
#ifdef QT4
connect( m_l, SIGNAL( mouseButtonPressed( int, Q3ListViewItem *,
const QPoint &, int ) ),
this, SLOT( itemPressed( int, Q3ListViewItem *,
const QPoint &, int ) ) );
connect( m_l, SIGNAL( mouseButtonClicked( int, Q3ListViewItem *,
const QPoint &, int ) ),
this, SLOT( itemReleased( int, Q3ListViewItem *,
const QPoint &, int ) ) );
connect( m_l, SIGNAL( doubleClicked( Q3ListViewItem *,
const QPoint &, int ) ),
this, SLOT( itemDoubleClicked( Q3ListViewItem *,
const QPoint &, int ) ) );
connect( m_l, SIGNAL( contextMenuRequested( Q3ListViewItem *,
const QPoint &, int ) ),
this, SLOT( contextMenuRequest( Q3ListViewItem *,
const QPoint &, int ) ) );
#else
connect( m_l, SIGNAL( mouseButtonPressed( int, QListViewItem *,
const QPoint &, int ) ),
this, SLOT( itemPressed( int, QListViewItem *,
const QPoint &, int ) ) );
connect( m_l, SIGNAL( mouseButtonClicked( int, QListViewItem *,
const QPoint &, int ) ),
this, SLOT( itemReleased( int, QListViewItem *,
const QPoint &, int ) ) );
/* connect( m_l, SIGNAL( pressed( QListViewItem * ) ),
this, SLOT( itemClicked( QListViewItem * ) ) );*/
connect( m_l, SIGNAL( doubleClicked( QListViewItem *,
const QPoint &, int ) ),
this, SLOT( itemDoubleClicked( QListViewItem *,
const QPoint &, int ) ) );
connect( m_l, SIGNAL( contextMenuRequested( QListViewItem *,
const QPoint &, int ) ),
this, SLOT( contextMenuRequest( QListViewItem *,
const QPoint &, int ) ) );
#endif
connect( m_l, SIGNAL( selectionChanged() ), this,
SLOT( selectionChanged() ) );
m_l->addColumn( tr( "Files" ) );
m_l->setTreeStepSize( 12 );
m_l->setDefaultRenameAction( Q3ListView::Accept );
m_l->setSorting( -1 );
//setColumnWidthMode (0, Manual);
//setColumnWidth (0, 196);
m_l->setShowToolTips( TRUE );
//m_l->setGeometry (0, 0, 200, 600);
m_l->setFont( pointSize<8>( m_l->font() ) );
QPushButton * reload_btn = new QPushButton( embed::getIconPixmap(
"reload" ), tr( "Reload (F5)" ), contentParent() );
addContentWidget( reload_btn );
connect( reload_btn, SIGNAL( clicked() ), this, SLOT( reloadTree() ) );
reloadTree();
show();
}
fileBrowser::~fileBrowser()
{
}
void fileBrowser::reloadTree( void )
{
m_l->clear();
QDir cdir( m_path );
QStringList files = cdir.entryList( QDir::NoFilter, QDir::Name );
// TODO: after dropping qt3-support we can use QStringList's iterator
// which makes it possible to travel through the list in reverse
// direction
for( csize i = 0; i < files.size(); ++i )
{
QString cur_file = files[files.size() - i - 1];
if( cur_file[0] != '.' &&
!QFileInfo( m_path + "/" + cur_file ).isDir()
#ifdef QT4
// TBD
#else
&& QDir::match( m_filter, cur_file.lower() )
#endif
)
{
(void) new fileItem( m_l, cur_file, m_path );
}
}
for( csize i = 0; i < files.size(); ++i )
{
QString cur_file = files[files.size() - i - 1];
if( cur_file[0] != '.' &&
QFileInfo( m_path + "/" + cur_file ).isDir() )
{
(void) new directory( m_l, cur_file, m_path, m_filter );
}
}
}
void fileBrowser::keyPressEvent( QKeyEvent * _ke )
{
if( _ke->key() == Qt::Key_F5 )
{
reloadTree();
}
else
{
_ke->ignore();
}
}
#ifdef QT4
void fileBrowser::itemPressed( int _btn, Q3ListViewItem * i, const QPoint &, int )
#else
void fileBrowser::itemPressed( int _btn, QListViewItem * i, const QPoint &, int )
#endif
{
fileItem * f = dynamic_cast<fileItem *>( i );
if( f != NULL && _btn == Qt::LeftButton )
{
if( m_previewPlayHandle != NULL )
{
mixer::inst()->removePlayHandle( m_previewPlayHandle );
m_previewPlayHandle = NULL;
}
if( f->type() == fileItem::SAMPLE_FILE )
{
samplePlayHandle * s = new samplePlayHandle(
f->fullName() );
s->setDoneMayReturnTrue( FALSE );
m_previewPlayHandle = s;
}
else if( f->type() == fileItem::PRESET_FILE )
{
m_previewPlayHandle = new presetPreviewPlayHandle(
f->fullName() );
}
if( m_previewPlayHandle != NULL )
{
mixer::inst()->addPlayHandle( m_previewPlayHandle );
}
}
}
#ifdef QT4
void fileBrowser::itemReleased( int, Q3ListViewItem * i, const QPoint &, int )
#else
void fileBrowser::itemReleased( int, QListViewItem * i, const QPoint &, int )
#endif
{
selectionChanged();
}
void fileBrowser::selectionChanged( void )
{
if( m_previewPlayHandle != NULL )
{
// if there're samples shorter than 3 seconds, we don't
// stop them if the user releases mouse-button...
samplePlayHandle * s = dynamic_cast<samplePlayHandle *>(
m_previewPlayHandle );
if( s != NULL )
{
if( s->totalFrames() - s->framesDone() <=
static_cast<Uint32>(
mixer::inst()->sampleRate() * 3 ) )
{
s->setDoneMayReturnTrue( TRUE );
m_previewPlayHandle = NULL;
return;
}
}
mixer::inst()->removePlayHandle( m_previewPlayHandle );
m_previewPlayHandle = NULL;
}
}
#ifdef QT4
void fileBrowser::itemDoubleClicked( Q3ListViewItem * i, const QPoint &, int )
#else
void fileBrowser::itemDoubleClicked( QListViewItem * i, const QPoint &, int )
#endif
{
fileItem * f = dynamic_cast<fileItem *>( i );
if( f != NULL )
{
if( f->type() == fileItem::SAMPLE_FILE )
{
// samples are per default opened in bb-editor because
// they're likely drum-samples etc.
channelTrack * ct = dynamic_cast<channelTrack *>(
track::create(
track::CHANNEL_TRACK,
bbEditor::inst() ) );
#ifdef LMMS_DEBUG
assert( ct != NULL );
#endif
instrument * afp = ct->loadInstrument(
"audiofileprocessor" );
if( afp != NULL )
{
afp->setParameter( "audiofile", f->fullName() );
}
ct->toggledChannelButton( TRUE );
}
else if( f->type() == fileItem::PRESET_FILE )
{
// presets are per default opened in bb-editor
multimediaProject mmp( f->fullName() );
track * t = track::create( track::CHANNEL_TRACK,
bbEditor::inst() );
channelTrack * ct = dynamic_cast<channelTrack *>( t );
if( ct != NULL )
{
ct->loadTrackSpecificSettings( mmp.content().
firstChild().
toElement() );
ct->toggledChannelButton( TRUE );
}
}
else if( f->type() == fileItem::SONG_FILE )
{
if( songEditor::inst()->mayChangeProject() == TRUE )
{
songEditor::inst()->loadProject(
f->fullName() );
}
}
}
}
#ifdef QT4
void fileBrowser::contextMenuRequest( Q3ListViewItem * i, const QPoint &, int )
#else
void fileBrowser::contextMenuRequest( QListViewItem * i, const QPoint &, int )
#endif
{
fileItem * f = dynamic_cast<fileItem *>( i );
if( f != NULL && ( f->type() == fileItem::SAMPLE_FILE ||
f->type() == fileItem::PRESET_FILE ) )
{
m_contextMenuItem = f;
QMenu * contextMenu = new QMenu( this );
contextMenu->addAction( tr( "Send to active channel" ), this,
SLOT( sendToActiveChannel() ) );
contextMenu->addAction( tr( "Open in new channel/Song-Editor" ),
this,
SLOT( openInNewChannelSE() ) );
contextMenu->addAction( tr( "Open in new channel/B+B Editor" ),
this,
SLOT( openInNewChannelBBE() ) );
//contextMenu->addSeparator ();
//contextMenu->addAction (tr("Rename"), this, SLOT(renameItem()));
contextMenu->exec( QCursor::pos() );
m_contextMenuItem = NULL;
delete contextMenu;
}
}
void fileBrowser::sendToActiveChannel( void )
{
// get all windows opened in the workspace
QWidgetList pl = lmmsMainWin::inst()->workspace()->windowList(
#if QT_VERSION >= 0x030200
QWorkspace::StackingOrder
#endif
);
#ifdef QT4
QListIterator<QWidget *> w( pl );
w.toBack();
// now we travel through the window-list until we find a channel-track
while( w.hasPrevious() )
{
channelTrack * ct = dynamic_cast<channelTrack *>(
w.previous() );
#else
QWidget * w = pl.last();
// now we travel through the window-list until we find a channel-track
while( w != NULL )
{
channelTrack * ct = dynamic_cast<channelTrack *>( w );
#endif
if( ct != NULL && ct->isHidden() == FALSE )
{
// ok, it's a channel-track, so we can apply the
// sample or the preset
if( m_contextMenuItem->type() == fileItem::SAMPLE_FILE )
{
instrument * afp = ct->loadInstrument(
"audiofileprocessor" );
if( afp != NULL )
{
afp->setParameter( "audiofile",
m_contextMenuItem->fullName() );
}
}
else if( m_contextMenuItem->type() ==
fileItem::PRESET_FILE )
{
multimediaProject mmp(
m_contextMenuItem->fullName() );
ct->loadTrackSpecificSettings(
mmp.content().
firstChild().
toElement() );
}
ct->toggledChannelButton( TRUE );
break;
}
#ifndef QT4
w = pl.prev();
#endif
}
}
void fileBrowser::openInNewChannel( trackContainer * _tc )
{
if( m_contextMenuItem->type() == fileItem::SAMPLE_FILE )
{
channelTrack * ct = dynamic_cast<channelTrack *>(
track::create( track::CHANNEL_TRACK, _tc ) );
#ifdef LMMS_DEBUG
assert( ct != NULL );
#endif
instrument * afp = ct->loadInstrument( "audiofileprocessor" );
if( afp != NULL )
{
afp->setParameter( "audiofile",
m_contextMenuItem->fullName() );
}
ct->toggledChannelButton( TRUE );
}
else if( m_contextMenuItem->type() == fileItem::PRESET_FILE )
{
multimediaProject mmp( m_contextMenuItem->fullName() );
track * t = track::create( track::CHANNEL_TRACK, _tc );
channelTrack * ct = dynamic_cast<channelTrack *>( t );
if( ct != NULL )
{
ct->loadTrackSpecificSettings( mmp.content().
firstChild().
toElement() );
ct->toggledChannelButton( TRUE );
}
}
}
void fileBrowser::openInNewChannelSE( void )
{
openInNewChannel( songEditor::inst() );
}
void fileBrowser::openInNewChannelBBE( void )
{
openInNewChannel( bbEditor::inst() );
}
void fileBrowser::renameItem( void )
{
m_contextMenuItem->startRename( 0 );
}
QPixmap * directory::s_folderPixmap = NULL;
QPixmap * directory::s_folderOpenedPixmap = NULL;
QPixmap * directory::s_folderLockedPixmap = NULL;
directory::directory( directory * _parent, const QString & _name,
const QString & _path, const QString & _filter ) :
Q3ListViewItem( _parent, _name ),
m_p( _parent ),
m_pix( NULL ),
m_path( _path ),
m_filter( _filter )
{
initPixmapStuff();
}
directory::directory( Q3ListView * _parent, const QString & _name,
const QString & _path, const QString & _filter ) :
Q3ListViewItem( _parent, _name ),
m_p( NULL ),
m_pix( NULL ),
m_path( _path ),
m_filter( _filter )
{
initPixmapStuff();
}
void directory::initPixmapStuff( void )
{
if( s_folderPixmap == NULL )
{
s_folderPixmap = new QPixmap(
embed::getIconPixmap( "folder" ) );
}
if( s_folderOpenedPixmap == NULL )
{
s_folderOpenedPixmap = new QPixmap(
embed::getIconPixmap( "folder_opened" ) );
}
if( s_folderLockedPixmap == NULL )
{
s_folderLockedPixmap = new QPixmap(
embed::getIconPixmap( "folder_locked" ) );
}
if( !QDir( fullName() ).isReadable() )
{
setPixmap( s_folderLockedPixmap );
}
else
{
setPixmap( s_folderPixmap );
}
}
void directory::setPixmap( QPixmap * _px )
{
m_pix = _px;
setup();
widthChanged( 0 );
invalidateHeight();
repaint();
}
void directory::setOpen( bool _o )
{
if( _o )
{
setPixmap( s_folderOpenedPixmap );
}
else
{
setPixmap( s_folderPixmap );
}
if( _o && !childCount() )
{
QString s( fullName() );
QDir thisDir( s );
if( !thisDir.isReadable() )
{
//readable = FALSE;
setExpandable( FALSE );
return;
}
listView()->setUpdatesEnabled( FALSE );
QStringList files = thisDir.entryList( QDir::NoFilter,
QDir::Name );
for( csize i = 0; i < files.size(); ++i )
{
QString cur_file = files[files.size()-i-1];
#ifdef QT4
if( cur_file[0] != '.' && !QFileInfo(
thisDir.absolutePath() + "/" +
cur_file ).isDir() &&
thisDir.match( m_filter, cur_file.lower() )
/*QDir::match( FILE_FILTER, cur_file )*/ )
#else
if( cur_file[0] != '.' && !QFileInfo(
thisDir.absPath() + "/" +
cur_file ).isDir() &&
thisDir.match( m_filter, cur_file.lower() )
/*QDir::match( FILE_FILTER, cur_file )*/ )
#endif
{
(void) new fileItem( this, cur_file, s );
}
}
for( csize i = 0; i < files.size(); ++i )
{
QString cur_file = files[files.size()-i-1];
#ifdef QT4
if( cur_file[0] != '.' && QFileInfo(
thisDir.absolutePath() + "/" +
cur_file ).isDir() )
#else
if( cur_file[0] != '.' && QFileInfo(
thisDir.absPath() + "/" +
cur_file ).isDir() )
#endif
{
(void) new directory( this, cur_file, s,
m_filter );
}
}
listView()->setUpdatesEnabled( TRUE );
}
Q3ListViewItem::setOpen( _o );
}
void directory::setup( void )
{
setExpandable( TRUE );
Q3ListViewItem::setup();
}
QPixmap * fileItem::s_songFilePixmap = NULL;
QPixmap * fileItem::s_presetFilePixmap = NULL;
QPixmap * fileItem::s_sampleFilePixmap = NULL;
QPixmap * fileItem::s_unknownFilePixmap = NULL;
fileItem::fileItem( Q3ListView * _parent, const QString & _name,
const QString & _path ) :
Q3ListViewItem( _parent, _name ),
m_path( _path )
{
determineFileType();
initPixmapStuff();
setDragEnabled( TRUE );
}
fileItem::fileItem( Q3ListViewItem * _parent, const QString & _name,
const QString & _path ) :
Q3ListViewItem( _parent, _name ),
m_path( _path )
{
determineFileType();
initPixmapStuff();
setDragEnabled( TRUE );
}
void fileItem::initPixmapStuff( void )
{
if( s_songFilePixmap == NULL )
{
s_songFilePixmap = new QPixmap( embed::getIconPixmap(
"project_file", 16, 16 ) );
}
if( s_presetFilePixmap == NULL )
{
s_presetFilePixmap = new QPixmap( embed::getIconPixmap(
"preset_file", 16, 16 ) );
}
if( s_sampleFilePixmap == NULL )
{
s_sampleFilePixmap = new QPixmap( embed::getIconPixmap(
"sound_file", 16, 16 ) );
}
if( s_unknownFilePixmap == NULL )
{
s_unknownFilePixmap = new QPixmap( embed::getIconPixmap(
"unknown_file" ) );
}
switch( m_type )
{
case SONG_FILE: m_pix = s_songFilePixmap; break;
case PRESET_FILE: m_pix = s_presetFilePixmap; break;
case SAMPLE_FILE: m_pix = s_sampleFilePixmap; break;
case UNKNOWN: m_pix = s_unknownFilePixmap; break;
}
}
void fileItem::determineFileType( void )
{
#ifdef QT4
QString ext = QFileInfo( fullName() ).suffix().toLower();
#else
QString ext = QFileInfo( fullName() ).extension( FALSE ).toLower();
#endif
if( ext == "mmp" )
{
m_type = SONG_FILE;
}
else if( ext == "xml" )
{
multimediaProject::projectTypes t =
multimediaProject::typeOfFile( fullName() );
if( t == multimediaProject::SONG_PROJECT )
{
m_type = SONG_FILE;
}
else if( t == multimediaProject::CHANNEL_SETTINGS )
{
m_type = PRESET_FILE;
}
else
{
m_type = UNKNOWN;
}
}
else if( ext == "csf" )
{
m_type = PRESET_FILE;
}
else if( ext == "wav" || ext == "ogg" || ext == "mp3" ||
ext == "aiff" || ext == "aif" || ext == "voc" ||
ext == "au" || ext == "raw" )
{
m_type = SAMPLE_FILE;
}
else
{
m_type = UNKNOWN;
}
}
#include "file_browser.moc"

View File

@@ -28,7 +28,7 @@
instrument::instrument( channelTrack * _channel_track, const QString & _name ) :
QWidget( _channel_track->pluginParent() ),
QWidget( _channel_track->tabWidgetParent() ),
plugin( _name, INSTRUMENT ),
m_channelTrack( _channel_track ),
m_valid( TRUE )

View File

@@ -0,0 +1,196 @@
/*
* midi_tab_widget.cpp - tab-widget in channel-track-window for setting up
* MIDI-related stuff
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <Qt/QtXml>
#else
#include <qdom.h>
#endif
#include "midi_tab_widget.h"
#include "channel_track.h"
#include "midi_port.h"
#include "tab_widget.h"
#include "led_checkbox.h"
#include "lcd_spinbox.h"
#include "tooltip.h"
#include "song_editor.h"
midiTabWidget::midiTabWidget( channelTrack * _channel_track,
midiPort * _port ) :
QWidget( _channel_track->tabWidgetParent() ),
settings(),
m_channelTrack( _channel_track ),
m_midiPort( _port )
{
m_setupTabWidget = new tabWidget( tr( "MIDI-SETUP FOR THIS CHANNEL" ),
this );
m_setupTabWidget->setGeometry( 4, 5, 238, 130 );
m_inputChannelSpinBox = new lcdSpinBox( 0, MIDI_CHANNEL_COUNT, 3,
m_setupTabWidget );
m_inputChannelSpinBox->addTextForValue( 0, "---" );
m_inputChannelSpinBox->setValue( m_midiPort->inputChannel() + 1 );
m_inputChannelSpinBox->setLabel( tr( "CHANNEL" ) );
m_inputChannelSpinBox->move( 190, 30 );
connect( m_inputChannelSpinBox, SIGNAL( valueChanged( int ) ),
this, SLOT( inputChannelChanged( int ) ) );
m_outputChannelSpinBox = new lcdSpinBox( 0, MIDI_CHANNEL_COUNT, 3,
m_setupTabWidget );
m_outputChannelSpinBox->addTextForValue( 0, "---" );
m_outputChannelSpinBox->setValue( m_midiPort->outputChannel() + 1 );
m_outputChannelSpinBox->setLabel( tr( "CHANNEL" ) );
m_outputChannelSpinBox->move( 190, 60 );
connect( m_outputChannelSpinBox, SIGNAL( valueChanged( int ) ),
this, SLOT( outputChannelChanged( int ) ) );
m_receiveCheckBox = new ledCheckBox( tr( "RECEIVE MIDI-EVENTS" ),
m_setupTabWidget );
m_receiveCheckBox->move( 10, 34 );
connect( m_receiveCheckBox, SIGNAL( toggled( bool ) ),
this, SLOT( midiPortModeToggled( bool ) ) );
connect( m_receiveCheckBox, SIGNAL( toggled( bool ) ),
m_inputChannelSpinBox, SLOT( setEnabled( bool ) ) );
m_sendCheckBox = new ledCheckBox( tr( "SEND MIDI-EVENTS" ),
m_setupTabWidget );
m_sendCheckBox->move( 10, 64 );
connect( m_sendCheckBox, SIGNAL( toggled( bool ) ),
this, SLOT( midiPortModeToggled( bool ) ) );
connect( m_sendCheckBox, SIGNAL( toggled( bool ) ),
m_outputChannelSpinBox, SLOT( setEnabled( bool ) ) );
m_routeCheckBox = new ledCheckBox( tr( "SEND RECEIVED MIDI-EVENTS" ),
m_setupTabWidget );
m_routeCheckBox->setChecked(
m_channelTrack->midiEventRoutingEnabled() );
m_routeCheckBox->move( 10, 100 );
connect( m_sendCheckBox, SIGNAL( toggled( bool ) ),
m_channelTrack, SLOT( toggleMidiEventRouting( bool ) ) );
midiPort::modes m = m_midiPort->mode();
m_receiveCheckBox->setChecked( m == midiPort::INPUT ||
m == midiPort::DUPLEX );
m_sendCheckBox->setChecked( m == midiPort::OUTPUT ||
m == midiPort::DUPLEX );
}
midiTabWidget::~midiTabWidget()
{
}
void midiTabWidget::saveSettings( QDomDocument & _doc, QDomElement & _parent )
{
QDomElement mw_de = _doc.createElement( nodeName() );
mw_de.setAttribute( "inputchannel", QString::number(
m_inputChannelSpinBox->value() ) );
mw_de.setAttribute( "outputchannel", QString::number(
m_outputChannelSpinBox->value() ) );
mw_de.setAttribute( "receive", QString::number(
m_receiveCheckBox->isChecked() ) );
mw_de.setAttribute( "send", QString::number(
m_sendCheckBox->isChecked() ) );
mw_de.setAttribute( "route", QString::number(
m_routeCheckBox->isChecked() ) );
_parent.appendChild( mw_de );
}
void midiTabWidget::loadSettings( const QDomElement & _this )
{
m_inputChannelSpinBox->setValue( _this.attribute( "inputchannel"
).toInt() );
m_outputChannelSpinBox->setValue( _this.attribute( "outputchannel"
).toInt() );
m_receiveCheckBox->setChecked( _this.attribute( "receive" ).toInt() );
m_sendCheckBox->setChecked( _this.attribute( "send" ).toInt() );
m_routeCheckBox->setChecked( _this.attribute( "route" ).toInt() );
}
void midiTabWidget::inputChannelChanged( int _new_chnl )
{
m_midiPort->setInputChannel( _new_chnl - 1 );
songEditor::inst()->setModified();
}
void midiTabWidget::outputChannelChanged( int _new_chnl )
{
m_midiPort->setOutputChannel( _new_chnl - 1 );
songEditor::inst()->setModified();
}
void midiTabWidget::midiPortModeToggled( bool )
{
// this small lookup-table makes everything easier
static const midiPort::modes modeTable[2][2] =
{
{ midiPort::DUMMY, midiPort::OUTPUT },
{ midiPort::INPUT, midiPort::DUPLEX }
} ;
m_midiPort->setMode( modeTable[m_receiveCheckBox->isChecked()]
[m_sendCheckBox->isChecked()] );
songEditor::inst()->setModified();
}
#include "midi_tab_widget.moc"

View File

@@ -32,7 +32,7 @@
#include "config_mgr.h"
#include "audio_device.h"
#include "midi_device.h"
#include "midi_client.h"
// platform-specific audio-interface-classes
#include "audio_alsa.h"
@@ -100,7 +100,7 @@ mixer::mixer() :
m_audioDev = tryAudioDevices();
m_midiDev = tryMIDIDevices();
m_midiClient = tryMIDIClients();
for( int i = 0; i < MAX_SAMPLE_PACKETS; ++i )
@@ -303,7 +303,7 @@ void mixer::run( void )
// all remaining notes etc. would be played until their end
void mixer::clear( void )
{
m_midiDev->noteOffAll();
// TODO: m_midiClient->noteOffAll();
for( playHandleVector::iterator it = m_playHandles.begin();
it != m_playHandles.end(); ++it )
{
@@ -639,17 +639,18 @@ audioDevice * mixer::tryAudioDevices( void )
midiDevice * mixer::tryMIDIDevices( void )
midiClient * mixer::tryMIDIClients( void )
{
QString dev_name = configManager::inst()->value( "mixer", "mididev" );
QString client_name = configManager::inst()->value( "mixer",
"midiclient" );
#ifdef ALSA_SUPPORT
if( dev_name == midiALSARaw::name() || dev_name == "" )
if( client_name == midiALSARaw::name() || client_name == "" )
{
midiALSARaw * malsa = new midiALSARaw();
if( malsa->isRunning() )
{
m_midiDevName = midiALSARaw::name();
m_midiClientName = midiALSARaw::name();
return( malsa );
}
delete malsa;
@@ -657,22 +658,22 @@ midiDevice * mixer::tryMIDIDevices( void )
#endif
#ifdef OSS_SUPPORT
if( dev_name == midiOSS::name() || dev_name == "" )
if( client_name == midiOSS::name() || client_name == "" )
{
midiOSS * moss = new midiOSS();
if( moss->isRunning() )
{
m_midiDevName = midiOSS::name();
m_midiClientName = midiOSS::name();
return( moss );
}
delete moss;
}
#endif
printf( "Couldn't open a MIDI-device, neither with ALSA nor with "
"OSS. Will use dummy-MIDI-device.\n" );
printf( "Couldn't create MIDI-client, neither with ALSA nor with "
"OSS. Will use dummy-MIDI-client.\n" );
m_midiDevName = midiDummy::name();
m_midiClientName = midiDummy::name();
return( new midiDummy() );
}

View File

@@ -46,17 +46,25 @@
#endif
#ifndef __USE_XOPEN
#define __USE_XOPEN
#endif
#include <math.h>
#include "piano_roll.h"
#include "song_editor.h"
#include "pattern.h"
#include "embed.h"
#include "crystal_button.h"
#include "pixmap_button.h"
#include "note_play_handle.h"
#include "templates.h"
#include "gui_templates.h"
#include "timeline.h"
#include "channel_track.h"
#include "tooltip.h"
#include "midi.h"
extern tones whiteKeys[]; // defined in piano_widget.cpp
@@ -518,10 +526,10 @@ void pianoRoll::setCurrentPattern( pattern * _new_pattern )
// remove all connections to other channel-tracks
disconnect( this, SLOT( recordNote( const note & ) ) );
// and now connect to noetFromMidiDeviceDone of channel so that
// we receive note-off-events from midi-keyboard for recording it
// and now connect to noteDone()-signal of channel so that
// we receive note-off-events from it's midi-port for recording it
connect( m_pattern->getChannelTrack(),
SIGNAL( noteFromMidiDeviceDone( const note & ) ),
SIGNAL( noteDone( const note & ) ),
this, SLOT( recordNote( const note & ) ) );
setWindowTitle( tr( "Piano-Roll - %1" ).arg( m_pattern->name() ) );
@@ -1260,7 +1268,8 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me )
songEditor::inst()->playing() == FALSE )
{
m_pattern->getChannelTrack()->processInEvent(
midiEvent( NOTE_ON, 0, key_num, vol ) );
midiEvent( NOTE_ON, 0, key_num, vol ),
midiTime() );
}
}
}
@@ -1276,12 +1285,13 @@ void pianoRoll::mouseReleaseEvent( QMouseEvent * _me )
{
m_pattern->getChannelTrack()->processInEvent(
midiEvent( NOTE_OFF, 0,
m_currentNote->key() ) );
m_currentNote->key() ), midiTime() );
}
else
{
m_pattern->getChannelTrack()->processInEvent(
midiEvent( NOTE_OFF, 0, getKey( _me->y() ) ) );
midiEvent( NOTE_OFF, 0, getKey( _me->y() ) ),
midiTime() );
}
}
@@ -1325,7 +1335,8 @@ void pianoRoll::mouseMoveEvent( QMouseEvent * _me )
edit_note == FALSE )
{
m_pattern->getChannelTrack()->processInEvent(
midiEvent( NOTE_OFF, 0, released_key ) );
midiEvent( NOTE_OFF, 0, released_key ),
midiTime() );
if(
#ifdef QT4
_me->buttons() &
@@ -1340,7 +1351,8 @@ void pianoRoll::mouseMoveEvent( QMouseEvent * _me )
{
m_pattern->getChannelTrack()->processInEvent(
midiEvent( NOTE_ON, 0, key_num,
DEFAULT_VOLUME ) );
DEFAULT_VOLUME ),
midiTime() );
}
}
if( _me->x() <= WHITE_KEY_WIDTH )
@@ -1361,12 +1373,10 @@ void pianoRoll::mouseMoveEvent( QMouseEvent * _me )
MIN_VOLUME,
MAX_VOLUME );
m_currentNote->setVolume( vol );
if( m_pattern->getChannelTrack()->keyPressed(
m_currentNote->key() ) == TRUE )
{
m_pattern->getChannelTrack()->noteForKey( m_currentNote->key()
)->setVolume( vol );
}
m_pattern->getChannelTrack()->processInEvent(
midiEvent( KEY_PRESSURE, 0, key_num,
vol ),
midiTime() );
}
}
else if( m_currentNote != NULL &&

View File

@@ -40,7 +40,8 @@
#include "piano_widget.h"
#include "channel_track.h"
#include "note_play_handle.h"
#include "midi.h"
#include "templates.h"
#include "embed.h"
@@ -106,6 +107,11 @@ pianoWidget::pianoWidget (channelTrack * _parent ) :
"black_key_pressed" ) );
}
for( int i = 0; i < NOTES_PER_OCTAVE * OCTAVES; ++i )
{
m_pressedKeys[i] = FALSE;
}
#ifdef QT4
m_pianoScroll = new QScrollBar( Qt::Horizontal, this );
m_pianoScroll->setRange( 0, WHITE_KEYS_PER_OCTAVE * ( OCTAVES - 3 ) -
@@ -231,7 +237,9 @@ void pianoWidget::mousePressEvent( QMouseEvent * _me )
}
// set note on
m_channelTrack->processInEvent(
midiEvent( NOTE_ON, 0, key_num, vol ) );
midiEvent( NOTE_ON, 0, key_num, vol ),
midiTime() );
m_pressedKeys[key_num] = TRUE;
}
else
{
@@ -255,7 +263,8 @@ void pianoWidget::mouseReleaseEvent( QMouseEvent * _me )
int released_key = getKeyFromMouse( _me->pos() );
m_channelTrack->processInEvent(
midiEvent ( NOTE_OFF, 0, released_key ) );
midiEvent( NOTE_OFF, 0, released_key, 0 ), midiTime() );
m_pressedKeys[released_key] = FALSE;
// and let the user see that he released a key... :)
update();
@@ -294,7 +303,9 @@ void pianoWidget::mouseMoveEvent( QMouseEvent * _me )
if( key_num != released_key )
{
m_channelTrack->processInEvent(
midiEvent( NOTE_OFF, 0, released_key ) );
midiEvent( NOTE_OFF, 0, released_key, 0 ),
midiTime() );
m_pressedKeys[released_key] = FALSE;
#ifdef QT4
if( _me->buttons() & Qt::LeftButton )
#else
@@ -304,7 +315,9 @@ void pianoWidget::mouseMoveEvent( QMouseEvent * _me )
if( _me->pos().y() > PIANO_BASE )
{
m_channelTrack->processInEvent(
midiEvent( NOTE_ON, 0, key_num, vol ) );
midiEvent( NOTE_ON, 0, key_num, vol ),
midiTime() );
m_pressedKeys[key_num] = TRUE;
}
else
{
@@ -317,9 +330,11 @@ void pianoWidget::mouseMoveEvent( QMouseEvent * _me )
// and let the user see that he pressed a key... :)
update();
}
else if( m_channelTrack->keyPressed( key_num ) == TRUE )
else if( m_pressedKeys[key_num] == TRUE )
{
m_channelTrack->noteForKey( key_num )->setVolume( vol );
m_channelTrack->processInEvent(
midiEvent( KEY_PRESSURE, 0, key_num, vol ),
midiTime() );
}
}
@@ -376,7 +391,9 @@ void pianoWidget::keyPressEvent( QKeyEvent * _ke )
if( _ke->isAutoRepeat() == FALSE && key_num > -1 )
{
m_channelTrack->processInEvent(
midiEvent( NOTE_ON, 0, key_num, DEFAULT_VOLUME ) );
midiEvent( NOTE_ON, 0, key_num, DEFAULT_VOLUME ),
midiTime() );
m_pressedKeys[key_num] = TRUE;
update();
}
else
@@ -395,7 +412,9 @@ void pianoWidget::keyReleaseEvent( QKeyEvent * _ke )
if( _ke->isAutoRepeat() == FALSE && key_num > -1 )
{
m_channelTrack->processInEvent(
midiEvent( NOTE_OFF, 0, key_num ) );
midiEvent( NOTE_OFF, 0, key_num, 0 ),
midiTime() );
m_pressedKeys[key_num] = FALSE;
update();
}
else
@@ -407,25 +426,19 @@ void pianoWidget::keyReleaseEvent( QKeyEvent * _ke )
void pianoWidget::focusInEvent( QFocusEvent * )
{
mixer::inst()->getMIDIDevice()->setChannelTrack( m_channelTrack );
}
void pianoWidget::focusOutEvent( QFocusEvent * )
{
// if we loose focus, we HAVE to note off all "running" notes because
// if we loose focus, we HAVE to note off all running notes because
// we don't receive key-release-events anymore and so the notes would
// hang otherwise
for( int i = 0; i < NOTES_PER_OCTAVE * OCTAVES; ++i )
{
if( m_channelTrack->keyPressed( i ) )
if( m_pressedKeys[i] == TRUE )
{
m_channelTrack->processInEvent(
midiEvent( NOTE_OFF, 0, i ) );
midiEvent( NOTE_OFF, 0, i, 0 ),
midiTime() );
m_pressedKeys[i] = FALSE;
}
}
update();
@@ -531,7 +544,7 @@ void pianoWidget::paintEvent( QPaintEvent * )
// draw pressed or not pressed key, depending on state of
// current key
if( m_channelTrack->keyPressed( cur_key ) == TRUE )
if( m_pressedKeys[cur_key] == TRUE )
{
p.drawPixmap( x, PIANO_BASE, *s_whiteKeyPressedPm );
}
@@ -562,7 +575,7 @@ void pianoWidget::paintEvent( QPaintEvent * )
if( s_key > 0 &&
KEY_ORDER[(tones)( --s_key ) % NOTES_PER_OCTAVE] == BLACK_KEY )
{
if( m_channelTrack->keyPressed( s_key ) == TRUE )
if( m_pressedKeys[s_key] == TRUE )
{
p.drawPixmap( 0 - WHITE_KEY_WIDTH / 2, PIANO_BASE,
*s_blackKeyPressedPm );
@@ -581,7 +594,7 @@ void pianoWidget::paintEvent( QPaintEvent * )
{
// draw pressed or not pressed key, depending on
// state of current key
if( m_channelTrack->keyPressed( cur_key ) == TRUE )
if( m_pressedKeys[cur_key] == TRUE )
{
p.drawPixmap( x + WHITE_KEY_WIDTH / 2,
PIANO_BASE,

View File

@@ -156,7 +156,7 @@ void pluginDescWidget::paintEvent( QPaintEvent * )
f.setBold( FALSE );
p.setFont( pointSize<7>( f ) );
QStringList words = QStringList::split( ' ',
plugin::tr( m_pluginDescriptor.description ) );
pluginBrowser::tr( m_pluginDescriptor.description ) );
for( QStringList::iterator it = words.begin(); it != words.end(); ++it )
{
if( ( *it ).contains( '-' ) )

View File

@@ -328,11 +328,11 @@ setupDialog::setupDialog( configTabs _tab_to_open ) :
#ifdef QT4
m_midiInterfaces->setCurrentIndex( m_midiInterfaces->findText(
mixer::inst()->midiDevName() ) );
mixer::inst()->midiClientName() ) );
#else
m_midiInterfaces->setCurrentText( mixer::inst()->midiDevName() );
m_midiInterfaces->setCurrentText( mixer::inst()->midiClientName() );
#endif
m_midiIfaceSetupWidgets[mixer::inst()->midiDevName()]->show();
m_midiIfaceSetupWidgets[mixer::inst()->midiClientName()]->show();
connect( m_midiInterfaces, SIGNAL( activated( const QString & ) ),
this, SLOT( midiInterfaceChanged( const QString & ) ) );

View File

@@ -75,7 +75,7 @@
#include "bb_track.h"
#include "channel_track.h"
#include "mmp.h"
#include "midi_device.h"
#include "midi_client.h"
#include "timeline.h"
#include "pattern.h"
#include "piano_roll.h"

View File

@@ -416,7 +416,8 @@ void trackContainer::updateScrollArea( void )
trackContainer::scrollArea::scrollArea( trackContainer * _parent ) :
QScrollArea( _parent )
QScrollArea( _parent ),
m_trackContainer( _parent )
{
setFrameStyle( QFrame::NoFrame );
setHorizontalScrollBarPolicy(
@@ -444,7 +445,7 @@ void trackContainer::scrollArea::wheelEvent( QWheelEvent * _we )
// bb-editor etc.) because they might want to use it for zooming
// or scrolling left/right if a modifier-key is pressed, otherwise
// they do not accept it and we pass it up to QScrollArea
dynamic_cast<trackContainer *>( parentWidget() )->wheelEvent( _we );
m_trackContainer->wheelEvent( _we );
if( !_we->isAccepted() )
{
QScrollArea::wheelEvent( _we );

View File

@@ -1,5 +1,5 @@
/*
* midi_alsa_raw.cpp - midi-device-driver for RawMIDI via ALSA
* midi_alsa_raw.cpp - midi-client for RawMIDI via ALSA
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.sourceforge.net>
@@ -46,8 +46,8 @@
#ifdef ALSA_SUPPORT
midiALSARaw::midiALSARaw( channelTrack * _ct ) :
midiDevice( _ct ),
midiALSARaw::midiALSARaw( void ) :
midiRawClient(),
QThread(),
m_inputp( &m_input ),
m_outputp( &m_output ),
@@ -184,14 +184,12 @@ void midiALSARaw::run( void )
break;
}
if( err == 0 )
{
continue;
}
for( int i = 0; i < err; ++i )
{
const midiEvent * midi_event = parseData( buf[i] );
if( midi_event != NULL )
{
processInEvent( *midi_event );
}
parseData( buf[i] );
}
}
@@ -201,7 +199,7 @@ void midiALSARaw::run( void )
midiALSARaw::setupWidget::setupWidget( QWidget * _parent ) :
midiDevice::setupWidget( midiALSARaw::name(), _parent )
midiRawClient::setupWidget( midiALSARaw::name(), _parent )
{
m_device = new QLineEdit( midiALSARaw::probeDevice(), this );
m_device->setGeometry( 10, 20, 160, 20 );

339
src/midi/midi_client.cpp Normal file
View File

@@ -0,0 +1,339 @@
/*
* midi_client.cpp - base-class for MIDI-clients like ALSA-sequencer-client
*
* Linux MultiMedia Studio
* Copyright (_c) 2004-2005 Tobias Doerffel <tobydox@users.sourceforge.net>
* This file partly contains code from Fluidsynth, Peter Hanappe
*
* 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"
#ifndef QT4
#include <qmap.h>
#endif
#include "midi_client.h"
/*#include "midi_mapper.h"*/
#include "templates.h"
#include "midi_port.h"
#include "midi_alsa_raw.h"
#include "midi_oss.h"
#include "midi_dummy.h"
midiClient::midiClient( void )
{
}
midiClient::~midiClient()
{
//TODO: noteOffAll();
}
void midiClient::removePort( midiPort * _port )
{
vvector<midiPort *>::iterator it = qFind( m_midiPorts.begin(),
m_midiPorts.end(),
_port );
if( it != m_midiPorts.end() )
{
m_midiPorts.erase( it );
}
}
midiRawClient::midiRawClient() :
midiClient()
{
}
midiRawClient::~midiRawClient()
{
}
midiPort * FASTCALL midiRawClient::createPort( midiEventProcessor * _mep,
const QString & _desired_name )
{
midiPort * mp = new midiPort( this, _mep, _desired_name );
addPort( mp );
return( mp );
}
// raw-MIDI-clients to not have real ports, therefore the name doesn't matter
// and we can dummy-implement validation-method
void midiRawClient::validatePortName( midiPort * )
{
}
void midiRawClient::parseData( const Uint8 _c )
{
/*********************************************************************/
/* 'Process' system real-time messages */
/*********************************************************************/
/* There are not too many real-time messages that are of interest here.
* They can occur anywhere, even in the middle of a noteon message!
* Real-time range: 0xF8 .. 0xFF
* Note: Real-time does not affect (running) status.
*/
if( _c >= 0xF8 )
{
if( _c == MIDI_SYSTEM_RESET )
{
m_midiParseData.m_midiEvent.m_type = MIDI_SYSTEM_RESET;
m_midiParseData.m_status = 0;
processParsedEvent();
}
return;
}
/*********************************************************************/
/* 'Process' system common messages (again, just skip them) */
/*********************************************************************/
/* There are no system common messages that are of interest here.
* System common range: 0xF0 .. 0xF7
*/
if( _c > 0xF0 )
{
/* MIDI spec say: To ignore a non-real-time message, just discard all
* data up to the next status byte. And our parser will ignore data
* that is received without a valid status.
* Note: system common cancels running status. */
m_midiParseData.m_status = 0;
return;
}
/*********************************************************************/
/* Process voice category messages: */
/*********************************************************************/
/* Now that we have handled realtime and system common messages, only
* voice messages are left.
* Only a status byte has bit # 7 set.
* So no matter the status of the parser (in case we have lost sync),
* as soon as a byte >= 0x80 comes in, we are dealing with a status byte
* and start a new event.
*/
if( _c & 0x80 )
{
m_midiParseData.m_channel = _c & 0x0F;
m_midiParseData.m_status = _c & 0xF0;
/* The event consumes x bytes of data...
(subtract 1 for the status byte) */
m_midiParseData.m_bytesTotal = eventLength(
m_midiParseData.m_status ) - 1;
/* of which we have read 0 at this time. */
m_midiParseData.m_bytes = 0;
return;
}
/*********************************************************************/
/* Process data */
/*********************************************************************/
/* If we made it this far, then the received char belongs to the data
* of the last event. */
if( m_midiParseData.m_status == 0 )
{
/* We are not interested in the event currently received.
Discard the data. */
return;
}
/* Store the first couple of bytes */
if( m_midiParseData.m_bytes < RAW_MIDI_PARSE_BUF_SIZE )
{
m_midiParseData.m_buffer[m_midiParseData.m_bytes] = _c;
}
++m_midiParseData.m_bytes;
/* Do we still need more data to get this event complete? */
if( m_midiParseData.m_bytes < m_midiParseData.m_bytesTotal )
{
return;
}
/*********************************************************************/
/* Send the event */
/*********************************************************************/
/* The event is ready-to-go. About 'running status':
*
* The MIDI protocol has a built-in compression mechanism. If several
* similar events are sent in-a-row, for example note-ons, then the
* event type is only sent once. For this case, the last event type
* (status) is remembered.
* We simply keep the status as it is, just reset the parameter counter.
* If another status byte comes in, it will overwrite the status.
*/
m_midiParseData.m_midiEvent.m_type = static_cast<midiEventTypes>(
m_midiParseData.m_status );
m_midiParseData.m_midiEvent.m_channel = m_midiParseData.m_channel;
m_midiParseData.m_bytes = 0; /* Related to running status! */
switch( m_midiParseData.m_midiEvent.m_type )
{
case NOTE_OFF:
case NOTE_ON:
case KEY_PRESSURE:
case CONTROL_CHANGE:
case PROGRAM_CHANGE:
case CHANNEL_PRESSURE:
m_midiParseData.m_midiEvent.m_data.m_param[0] =
m_midiParseData.m_buffer[0] - NOTES_PER_OCTAVE;
m_midiParseData.m_midiEvent.m_data.m_param[1] =
m_midiParseData.m_buffer[1];
break;
case PITCH_BEND:
// Pitch-bend is transmitted with 14-bit precision.
// Note: '|' does here the same as '+' (no common bits),
// but might be faster
m_midiParseData.m_midiEvent.m_data.m_param[0] =
( ( m_midiParseData.m_buffer[1] * 128 ) |
m_midiParseData.m_buffer[0] );
break;
default:
// Unlikely
return;
}
processParsedEvent();
}
void midiRawClient::processParsedEvent()
{
for( csize i = 0; i < m_midiPorts.size(); ++i )
{
m_midiPorts[i]->processInEvent( m_midiParseData.m_midiEvent,
midiTime() );
}
}
void midiRawClient::processOutEvent( const midiEvent & _me,
const midiTime & ,
const midiPort * _port )
{
// TODO: also evaluate _time and queue event if neccessary
switch( _me.m_type )
{
case NOTE_ON:
case NOTE_OFF:
if( _port->outputChannel() >= 0 )
{
sendByte( _me.m_type | _port->outputChannel() );
sendByte( _me.m_data.m_param[0] +
NOTES_PER_OCTAVE );
sendByte( tLimit( (int) _me.m_data.m_param[1],
0, 127 ) );
}
else
{
for( Sint8 i = 0; i < MIDI_CHANNEL_COUNT; ++i )
{
sendByte( _me.m_type | i );
sendByte( _me.m_data.m_param[0] +
NOTES_PER_OCTAVE );
sendByte( tLimit( (int)
_me.m_data.m_param[1],
0, 127 ) );
}
}
break;
default:
break;
}
}
// Taken from Nagano Daisuke's USB-MIDI driver
const Uint8 REMAINS_F0F6[] =
{
0, /* 0xF0 */
2, /* 0XF1 */
3, /* 0XF2 */
2, /* 0XF3 */
2, /* 0XF4 (Undefined by MIDI Spec, and subject to change) */
2, /* 0XF5 (Undefined by MIDI Spec, and subject to change) */
1 /* 0XF6 */
} ;
const Uint8 REMAINS_80E0[] =
{
3, /* 0x8X Note Off */
3, /* 0x9X Note On */
3, /* 0xAX Poly-key pressure */
3, /* 0xBX Control Change */
2, /* 0xCX Program Change */
2, /* 0xDX Channel pressure */
3 /* 0xEX PitchBend Change */
} ;
// Returns the length of the MIDI message starting with _event.
// Taken from Nagano Daisuke's USB-MIDI driver
Uint8 midiRawClient::eventLength( const Uint8 _event )
{
if ( _event < 0xF0 )
{
return( REMAINS_80E0[( ( _event - 0x80 ) >>4 ) & 0x0F] );
}
else if ( _event < 0xF7 )
{
return( REMAINS_F0F6[_event - 0xF0] );
}
return( 1 );
}

View File

@@ -1,5 +1,5 @@
/*
* midi_oss.cpp - simple midi-device-driver for OSS
* midi_oss.cpp - OSS-raw-midi-client
*
* Linux MultiMedia Studio
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.sourceforge.net>
@@ -52,8 +52,8 @@
midiOSS::midiOSS( channelTrack * _ct ) :
midiDevice( _ct ),
midiOSS::midiOSS( void ) :
midiRawClient(),
QThread(),
m_midiDev( probeDevice() ),
m_quit( FALSE )
@@ -108,7 +108,7 @@ QString midiOSS::probeDevice( void )
void midiOSS::sendByte( Uint8 _c )
void midiOSS::sendByte( const Uint8 _c )
{
#ifdef QT4
m_midiDev.putChar( _c );
@@ -130,14 +130,10 @@ void midiOSS::run( void )
{
continue;
}
const midiEvent * midi_event = parseData( c );
parseData( c );
#else
const midiEvent * midi_event = parseData( m_midiDev.getch() );
parseData( m_midiDev.getch() );
#endif
if( midi_event != NULL )
{
processInEvent( *midi_event );
}
}
}
@@ -146,7 +142,7 @@ void midiOSS::run( void )
midiOSS::setupWidget::setupWidget( QWidget * _parent ) :
midiDevice::setupWidget( midiOSS::name(), _parent )
midiRawClient::setupWidget( midiOSS::name(), _parent )
{
m_device = new QLineEdit( midiOSS::probeDevice(), this );
m_device->setGeometry( 10, 20, 160, 20 );

85
src/midi/midi_port.cpp Normal file
View File

@@ -0,0 +1,85 @@
/*
* midi_port.cpp - abstraction of MIDI-ports which are part of LMMS's MIDI-
* sequencing system
*
* Linux MultiMedia Studio
* Copyright (_c) 2004-2005 Tobias Doerffel <tobydox@users.sourceforge.net>
* This file partly contains code from Fluidsynth, Peter Hanappe
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "midi_port.h"
#include "midi_client.h"
midiPort::midiPort( midiClient * _mc, midiEventProcessor * _mep,
const QString & _name, modes _mode ) :
m_midiClient( _mc ),
m_midiEventProcessor( _mep ),
m_name( _name ),
m_mode( _mode ),
m_inputChannel( -1 ),
m_outputChannel( -1 )
{
}
midiPort::~midiPort()
{
}
void midiPort::trySetName( const QString & _name )
{
setName( _name );
m_midiClient->validatePortName( this );
}
void midiPort::processInEvent( const midiEvent & _me, const midiTime & _time )
{
// mask event
if( ( mode() == INPUT || mode() == DUPLEX ) &&
( inputChannel() == _me.m_channel || inputChannel() == -1 ) )
{
m_midiEventProcessor->processInEvent( _me, _time );
}
}
void midiPort::processOutEvent( const midiEvent & _me, const midiTime & _time )
{
// mask event
if( ( mode() == OUTPUT || mode() == DUPLEX ) &&
( outputChannel() == _me.m_channel || outputChannel() == -1 ) )
{
m_midiClient->processOutEvent( _me, _time, this );
}
}

View File

@@ -39,6 +39,7 @@
#include <QStatusBar>
#include <QFontMetrics>
#include <QApplication>
#include <QInputDialog>
#else
@@ -50,6 +51,7 @@
#include <qstatusbar.h>
#include <qfontmetrics.h>
#include <qapplication.h>
#include <qinputdialog.h>
#define addSeparator insertSeparator
@@ -62,7 +64,7 @@
#include "knob.h"
#include "song_editor.h"
#include "midi_device.h"
/*#include "midi_client.h"*/
#include "embed.h"
#include "spc_bg_hndl_widget.h"
#include "config_mgr.h"
@@ -91,12 +93,9 @@ knob::knob( int _knob_num, QWidget * _parent, const QString & _name ) :
, _name.ascii()
#endif
),
m_scrollMode( ScrNone ),
m_mouseOffset( 0.0f ),
m_tracking( TRUE ),
m_buttonPressed( FALSE ),
m_angle( 0.0f ),
m_oldAngle( 0.0f ),
m_nTurns( 0.0f ),
m_knobNum( _knob_num ),
m_hintTextBeforeValue( "" ),
m_hintTextAfterValue( "" ),
@@ -116,23 +115,14 @@ knob::knob( int _knob_num, QWidget * _parent, const QString & _name ) :
#ifdef QT4
setAccessibleName( _name );
#endif
setRange( 0.0, 100.0, 1.0 );
#ifdef QT4
m_knobPixmap = new QPixmap( embed::getIconPixmap( QString( "knob0" +
QString::number( m_knobNum + 1 ) ).toAscii().constData() ) );
#else
setBackgroundMode( Qt::NoBackground );
m_knobPixmap = new QPixmap( embed::getIconPixmap( "knob0" +
QString::number( m_knobNum + 1 ) ) );
#endif
#ifdef QT4
// setAttribute( Qt::WA_NoBackground );
#else
setBackgroundMode( Qt::NoBackground );
#endif
m_knobWidth = m_knobPixmap->width();
setRange( 0.0f, 100.0f, 1.0f );
setFixedSize( m_knobPixmap->width(), m_knobPixmap->height() );
setTotalAngle( 270.0f );
@@ -146,12 +136,12 @@ knob::knob( int _knob_num, QWidget * _parent, const QString & _name ) :
// Destructor
knob::~knob()
{
// make sure pointer to this knob isn't used anymore in active
/* // make sure pointer to this knob isn't used anymore in active
// midi-device-class
if( mixer::inst()->getMIDIDevice()->pitchBendKnob() == this )
if( mixer::inst()->getMIDIClient()->pitchBendKnob() == this )
{
mixer::inst()->getMIDIDevice()->setPitchBendKnob( NULL );
}
mixer::inst()->getMIDIClient()->setPitchBendKnob( NULL );
}*/
}
@@ -251,10 +241,7 @@ void knob::valueChange( void )
{
recalcAngle();
update();
if( m_tracking )
{
emit valueChanged( value() );
}
emit valueChanged( value() );
}
@@ -273,8 +260,7 @@ float knob::getValue( const QPoint & _p )
const float arc = atan2( -dx, dy ) * 180.0 / M_PI;
float new_value = 0.5 * ( m_minValue + m_maxValue ) +
( arc + m_nTurns * 360.0 ) *
( m_maxValue - m_minValue ) /
arc * ( m_maxValue - m_minValue ) /
m_totalAngle;
const float oneTurn = tAbs<float>( m_maxValue - m_minValue ) *
@@ -294,17 +280,7 @@ float knob::getValue( const QPoint & _p )
}
return( new_value );
}
return( ( _p.y() - m_origMousePos.y() ) * m_step );
}
void knob::getScrollMode( const QPoint &, int & _scroll_mode, int & _direction )
{
_scroll_mode = ScrMouse;
_direction = 0;
return( ( _p.y() - m_origMousePos.y() ) * m_pageSize );
}
@@ -343,7 +319,6 @@ void knob::layoutKnob( bool _update_geometry )
void knob::paintEvent( QPaintEvent * _me )
{
// Use double-buffering
QRect ur = _me->rect();
#ifndef QT4
if( ur.isValid() )
@@ -378,22 +353,18 @@ void knob::paintEvent( QPaintEvent * _me )
void knob::recalcAngle( void )
{
m_oldAngle = m_angle;
//
// calculate the angle corresponding to the value
//
if( m_maxValue == m_minValue )
{
m_angle = 0;
m_nTurns = 0;
}
else
{
m_angle = ( value() - 0.5 * ( m_minValue + m_maxValue ) ) /
( m_maxValue - m_minValue ) * m_totalAngle;
m_nTurns = floor( ( m_angle + 180.0 ) / 360.0 );
m_angle = m_angle - m_nTurns * 360.0;
m_angle = static_cast<int>( m_angle ) % 360;
}
}
@@ -403,26 +374,18 @@ void knob::recalcAngle( void )
//! Mouse press event handler
void knob::mousePressEvent( QMouseEvent * _me )
{
const QPoint & p = _me->pos();
m_origMousePos = p;
getScrollMode( p, m_scrollMode, m_direction );
switch( m_scrollMode )
{
case ScrMouse:
m_mouseOffset = getValue( p ) - value();
emit sliderPressed();
break;
default:
m_mouseOffset = 0;
m_direction = 0;
break;
}
if( _me->button() == Qt::LeftButton )
{
const QPoint & p = _me->pos();
m_origMousePos = p;
if( configManager::inst()->value( "knobs",
"classicalusability").toInt() )
{
m_mouseOffset = getValue( p ) - value();
}
emit sliderPressed();
if( !configManager::inst()->value( "knobs", "classicalusability"
).toInt() )
{
@@ -435,6 +398,11 @@ void knob::mousePressEvent( QMouseEvent * _me )
s_textFloat->move( mapTo( topLevelWidget(), QPoint( 0, 0 ) ) +
QPoint( m_knobPixmap->width() + 2, 0 ) );
s_textFloat->show();
m_buttonPressed = TRUE;
}
else if( _me->button() == Qt::MidButton )
{
reset();
}
}
@@ -444,26 +412,21 @@ void knob::mousePressEvent( QMouseEvent * _me )
//! Mouse Move Event handler
void knob::mouseMoveEvent( QMouseEvent * _me )
{
if( m_scrollMode == ScrMouse )
if( m_buttonPressed == TRUE )
{
setPosition( _me->pos() );
if( value() != m_prevValue )
{
emit sliderMoved( value() );
if( !configManager::inst()->value( "knobs",
emit sliderMoved( value() );
if( !configManager::inst()->value( "knobs",
"classicalusability").toInt() )
{
QCursor::setPos( mapToGlobal(
m_origMousePos ) );
}
{
QCursor::setPos( mapToGlobal( m_origMousePos ) );
}
songEditor::inst()->setModified();
}
songEditor::inst()->setModified();
s_textFloat->setText( m_hintTextBeforeValue +
QString::number( value() ) +
m_hintTextAfterValue );
}
@@ -472,30 +435,14 @@ void knob::mouseMoveEvent( QMouseEvent * _me )
//! Mouse Release Event handler
void knob::mouseReleaseEvent( QMouseEvent * /* _me*/ )
{
if( m_scrollMode != ScrNone )
if( m_buttonPressed )
{
m_scrollMode = ScrNone;
m_buttonPressed = TRUE;
buttonReleased();
}
switch( m_scrollMode )
{
case ScrMouse:
//setPosition( _me->pos() );
m_direction = 0;
m_mouseOffset = 0;
emit sliderReleased();
break;
case ScrDirect:
//setPosition( _me->pos() );
m_direction = 0;
m_mouseOffset = 0;
break;
default:
break;
}
m_mouseOffset = 0;
emit sliderReleased();
if( !configManager::inst()->value( "knobs", "classicalusability"
).toInt() )
@@ -509,15 +456,23 @@ void knob::mouseReleaseEvent( QMouseEvent * /* _me*/ )
//! Qt wheel event
void knob::wheelEvent( QWheelEvent * _me )
void knob::mouseDoubleClickEvent( QMouseEvent * )
{
_me->accept();
const int inc = _me->delta() / WHEEL_DELTA;
incPages( inc );
enterValue();
}
//! Qt wheel event
void knob::wheelEvent( QWheelEvent * _we )
{
_we->accept();
const int inc = _we->delta() / WHEEL_DELTA;
incValue( inc );
songEditor::inst()->setModified();
s_textFloat->reparent( this );
s_textFloat->setText( m_hintTextBeforeValue +
QString::number( value() ) +
@@ -538,7 +493,7 @@ void knob::wheelEvent( QWheelEvent * _me )
//! Emits a valueChanged() signal if necessary
void knob::buttonReleased( void )
{
if( ( !m_tracking ) || ( value() != m_prevValue ) )
if( value() != m_prevValue )
{
emit valueChanged( value() );
}
@@ -552,26 +507,17 @@ void knob::setPosition( const QPoint & _p )
if( configManager::inst()->value( "knobs", "classicalusability"
).toInt() )
{
setNewValue( getValue( _p ) - m_mouseOffset, 1 );
setValue( getValue( _p ) - m_mouseOffset );
}
else
{
setNewValue( m_value - getValue( _p ), 1 );
setValue( m_value - getValue( _p ) );
}
}
void knob::setTracking( bool _enable )
{
m_tracking = _enable;
}
void knob::setValue( float _val, bool _is_init_value )
{
if( _is_init_value )
@@ -579,7 +525,7 @@ void knob::setValue( float _val, bool _is_init_value )
m_initValue = _val;
}
setNewValue( _val, 0 );
setNewValue( _val, TRUE );
}
@@ -587,7 +533,7 @@ void knob::setValue( float _val, bool _is_init_value )
void knob::fitValue( float _val )
{
setNewValue( _val, 1 );
setValue( _val );
}
@@ -595,7 +541,7 @@ void knob::fitValue( float _val )
void knob::incValue( int _steps )
{
setNewValue( m_value + float( _steps ) * m_step, 1 );
setValue( m_value + float( _steps ) * m_step );
}
@@ -622,13 +568,14 @@ void knob::setRange( float _vmin, float _vmax, float _vstep, int _page_size )
//
/* m_pageSize = tLimit( pageSize, 0, int( tAbs<float>( ( m_maxValue -
m_minValue ) / m_step ) ) ); */
m_pageSize = tMax<float>( ( m_maxValue - m_minValue ) / 40.0f, _vstep );
m_pageSize = tMax<float>( ( m_maxValue - m_minValue ) / 100.0f,
m_step );
//
// If the value lies out of the range, it
// will be changed. Note that it will not be adjusted to
// the new step width.
setNewValue( m_value, 0 );
setNewValue( m_value, FALSE );
// call notifier after the step width has been
// adjusted.
@@ -641,7 +588,7 @@ void knob::setRange( float _vmin, float _vmax, float _vstep, int _page_size )
void knob::setNewValue( float _x, int _align )
void knob::setNewValue( float _x, bool _align )
{
m_prevValue = m_value;
@@ -768,6 +715,14 @@ void knob::contextMenuEvent( QContextMenuEvent * )
void knob::reset( void )
{
setValue( m_initValue );
songEditor::inst()->setModified();
s_textFloat->reparent( this );
s_textFloat->setText( m_hintTextBeforeValue +
QString::number( value() ) +
m_hintTextAfterValue );
s_textFloat->move( mapTo( topLevelWidget(), QPoint( 0, 0 ) ) +
QPoint( m_knobPixmap->width() + 2, 0 ) );
s_textFloat->setVisibilityTimeOut( 1000 );
}
@@ -784,6 +739,32 @@ void knob::copyValue( void )
void knob::pasteValue( void )
{
setValue( s_copiedValue );
songEditor::inst()->setModified();
s_textFloat->reparent( this );
s_textFloat->setText( m_hintTextBeforeValue +
QString::number( value() ) +
m_hintTextAfterValue );
s_textFloat->move( mapTo( topLevelWidget(), QPoint( 0, 0 ) ) +
QPoint( m_knobPixmap->width() + 2, 0 ) );
s_textFloat->setVisibilityTimeOut( 1000 );
}
void knob::enterValue( void )
{
bool ok;
float new_val = QInputDialog::getDouble( accessibleName(),
tr( "Please enter a new value between "
"%1 and %2:" ).arg(
minValue() ).arg( maxValue() ),
value(), minValue(), maxValue(),
4, &ok, this );
if( ok )
{
setValue( new_val );
}
}
@@ -791,7 +772,7 @@ void knob::pasteValue( void )
void knob::connectToMidiDevice( void )
{
mixer::inst()->getMIDIDevice()->setPitchBendKnob( this );
//mixer::inst()->getMIDIDevice()->setPitchBendKnob( this );
}

View File

@@ -58,15 +58,8 @@ lcdSpinBox::lcdSpinBox( int _min, int _max, int _num_digits,
m_number->setFrameShape( QFrame::Panel );
m_number->setFrameShadow( QFrame::Sunken );
m_number->setSegmentStyle( QLCDNumber::Flat );
#ifdef QT4
QPalette pal = m_number->palette();
pal.setColor( QPalette::Background, QColor( 32, 32, 32 ) );
pal.setColor( QPalette::Foreground, QColor( 255, 180, 0 ) );
m_number->setPalette( pal );
#else
m_number->setPaletteBackgroundColor( QColor( 32, 32, 32 ) );
m_number->setPaletteForegroundColor( QColor( 255, 180, 0 ) );
#endif
setEnabled( TRUE );
// value is automatically limited to given range
setValue( 0 );
@@ -95,12 +88,15 @@ void lcdSpinBox::setValue( int _value )
{
_value = ( ( tLimit( _value, m_minValue, m_maxValue ) - m_minValue ) /
m_step ) * m_step + m_minValue;
QString s = QString::number( _value );
while( (int) s.length() < m_number->numDigits() )
QString s = m_textForValue[_value];
if( s == "" )
{
s = "0" + s;
s = QString::number( _value );
while( (int) s.length() < m_number->numDigits() )
{
s = "0" + s;
}
}
m_number->display( s );
}
@@ -127,6 +123,28 @@ void lcdSpinBox::setLabel( const QString & _txt )
void lcdSpinBox::setEnabled( bool _on )
{
QColor fg( 255, 180, 0 );
if( _on == FALSE )
{
fg = QColor( 160, 160, 160 );
}
#ifdef QT4
QPalette pal = m_number->palette();
pal.setColor( QPalette::Background, QColor( 32, 32, 32 ) );
pal.setColor( QPalette::Foreground, fg );
m_number->setPalette( pal );
#else
m_number->setPaletteBackgroundColor( QColor( 32, 32, 32 ) );
m_number->setPaletteForegroundColor( fg );
#endif
QWidget::setEnabled( _on );
}
void lcdSpinBox::mousePressEvent( QMouseEvent * _me )
{
if( _me->button() == Qt::LeftButton && _me->y() < m_number->height() )
@@ -138,6 +156,7 @@ void lcdSpinBox::mousePressEvent( QMouseEvent * _me )
void lcdSpinBox::mouseMoveEvent( QMouseEvent * _me )
{
if( _me->modifiers() == Qt::LeftButton )

View File

@@ -117,6 +117,10 @@ void ledCheckBox::setChecked( bool _on )
{
toggle();
}
else
{
emit( toggled( m_checked ) );
}
}

View File

@@ -49,22 +49,15 @@
#endif
#ifndef __USE_XOPEN
#define __USE_XOPEN
#endif
#include "tempo_sync_knob.h"
#include "song_editor.h"
#include "midi_device.h"
#include "embed.h"
#include "tooltip.h"
#include "config_mgr.h"
#include "text_float.h"
const int WHEEL_DELTA = 120;
tempoSyncKnob::tempoSyncKnob( int _knob_num, QWidget * _parent, const QString & _name,
@@ -171,59 +164,19 @@ void tempoSyncKnob::contextMenuEvent( QContextMenuEvent * )
void tempoSyncKnob::mouseMoveEvent( QMouseEvent * _me )
{
if( m_scrollMode == ScrMouse )
{
m_tempoSyncMode = NO_SYNC;
calculateTempoSyncTime( songEditor::inst()->getBPM() );
setPosition( _me->pos() );
if( value() != m_prevValue )
{
emit sliderMoved( value() );
}
if( !configManager::inst()->value( "knobs", "classicalusability"
).toInt() )
{
QCursor::setPos( mapToGlobal( m_origMousePos ) );
}
}
songEditor::inst()->setModified();
s_textFloat->setText( m_hintTextBeforeValue +
QString::number( value() ) +
m_hintTextAfterValue );
m_tempoSyncMode = NO_SYNC;
calculateTempoSyncTime( songEditor::inst()->getBPM() );
knob::mouseMoveEvent( _me );
}
void tempoSyncKnob::wheelEvent( QWheelEvent * _me )
void tempoSyncKnob::wheelEvent( QWheelEvent * _we )
{
_me->accept();
const int inc = _me->delta() / WHEEL_DELTA;
incPages( inc );
knob::wheelEvent( _we );
m_tempoSyncMode = NO_SYNC;
calculateTempoSyncTime( songEditor::inst()->getBPM() );
songEditor::inst()->setModified();
s_textFloat->reparent( this );
s_textFloat->setText( m_hintTextBeforeValue +
QString::number( value() ) +
m_hintTextAfterValue );
s_textFloat->move( mapTo( topLevelWidget(), QPoint( 0, 0 ) ) +
QPoint( m_knobPixmap->width() + 2, 0 ) );
s_textFloat->setVisibilityTimeOut( 1000 );
toolTip::add( this, m_hintTextBeforeValue+QString::number( value() ) +
m_hintTextAfterValue );
if( value() != m_prevValue )
{
emit sliderMoved( value() );
}
}
@@ -283,7 +236,7 @@ void tempoSyncKnob::calculateTempoSyncTime( int _bpm )
conversionFactor = 8.0;
break;
default:
printf( "arpAndChordsTabWidget::calculateTempoSyncTime: invalid tempoSyncMode" );
printf( "tempoSyncKnob::calculateTempoSyncTime: invalid tempoSyncMode" );
break;
}
setValue( 60000.0 / ( _bpm * conversionFactor * m_scale ),