Sequencer: More simplification of pattern drawing.
This commit is contained in:
parent
cec17e7990
commit
a872d99e9b
|
@ -20,7 +20,7 @@
|
||||||
#include <FL/Fl.H>
|
#include <FL/Fl.H>
|
||||||
#include <FL/Fl_Double_Window.H>
|
#include <FL/Fl_Double_Window.H>
|
||||||
#include <FL/Fl_Single_Window.H>
|
#include <FL/Fl_Single_Window.H>
|
||||||
#include <FL/Fl_Scalepack.H>
|
#include <FL/Fl_Pack.H>
|
||||||
#include <FL/Fl_Choice.H>
|
#include <FL/Fl_Choice.H>
|
||||||
#include <FL/fl_draw.H>
|
#include <FL/fl_draw.H>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
@ -131,7 +131,7 @@ main ( int argc, char **argv )
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Fl_Scalepack *o = new Fl_Scalepack( 0, 24, 800, 600 - 24 );
|
Fl_Pack *o = new Fl_Pack( 0, 24, 800, 600 - 24 );
|
||||||
o->type( 0 );
|
o->type( 0 );
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
|
||||||
|
/*******************************************************************************/
|
||||||
|
/* Copyright (C) 2007-2008 Jonathan Moore Liles */
|
||||||
|
/* */
|
||||||
|
/* 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 the file COPYING. If not,write to the Free Software */
|
||||||
|
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||||
|
/*******************************************************************************/
|
||||||
|
|
||||||
|
#include "event.H"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
namespace MIDI
|
||||||
|
{
|
||||||
|
void
|
||||||
|
event::_init ( void )
|
||||||
|
{
|
||||||
|
_link = _next = _prev = NULL;
|
||||||
|
_selected = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
event::event ( void )
|
||||||
|
{
|
||||||
|
_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
event::~event ( void )
|
||||||
|
{
|
||||||
|
_link = _next = _prev = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy constructor */
|
||||||
|
event::event ( const event &e ) : midievent( e )
|
||||||
|
{
|
||||||
|
_link = _next = _prev = NULL;
|
||||||
|
_selected = e._selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
event::event ( const midievent &e ) : midievent( e )
|
||||||
|
{
|
||||||
|
_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
event::link ( event *event )
|
||||||
|
{
|
||||||
|
if ( event == NULL )
|
||||||
|
{
|
||||||
|
if ( _link )
|
||||||
|
{
|
||||||
|
_link->_link = NULL;
|
||||||
|
_link = NULL;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_link = event;
|
||||||
|
_link->_link = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
event *
|
||||||
|
event::link ( void ) const
|
||||||
|
{
|
||||||
|
return _link;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
event::linked ( void ) const
|
||||||
|
{
|
||||||
|
return _link != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
event::select ( void )
|
||||||
|
{
|
||||||
|
_selected = 1;
|
||||||
|
|
||||||
|
if ( _link )
|
||||||
|
_link->_selected = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
event::deselect ( void )
|
||||||
|
{
|
||||||
|
_selected = 0;
|
||||||
|
|
||||||
|
if ( _link )
|
||||||
|
_link->_selected = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
event::selected ( int n ) const
|
||||||
|
{
|
||||||
|
return _selected == n;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
event::selected ( void ) const
|
||||||
|
{
|
||||||
|
return _selected == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* override this so we can update linked event */
|
||||||
|
void
|
||||||
|
event::note ( char note )
|
||||||
|
{
|
||||||
|
midievent::note( note );
|
||||||
|
|
||||||
|
if ( _link )
|
||||||
|
_link->midievent::note( note );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stupid C++ makes us override the all polymorphic functions... */
|
||||||
|
unsigned char
|
||||||
|
event::note ( void ) const
|
||||||
|
{
|
||||||
|
return midievent::note();
|
||||||
|
}
|
||||||
|
|
||||||
|
tick_t
|
||||||
|
event::note_duration ( void ) const
|
||||||
|
{
|
||||||
|
return _link ? _link->timestamp() - timestamp() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
event::note_duration ( tick_t l )
|
||||||
|
{
|
||||||
|
if ( _link )
|
||||||
|
_link->timestamp( timestamp() + l );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
event::get_note_properties ( note_properties *p ) const
|
||||||
|
{
|
||||||
|
p->start = timestamp();
|
||||||
|
p->duration = note_duration();
|
||||||
|
p->velocity = note_velocity();
|
||||||
|
p->note = note();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
event::set_note_properties ( const note_properties *p )
|
||||||
|
{
|
||||||
|
timestamp( p->start );
|
||||||
|
note_duration( p->duration );
|
||||||
|
note_velocity( p->velocity );
|
||||||
|
note( p->note );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
|
||||||
|
/*******************************************************************************/
|
||||||
|
/* Copyright (C) 2007-2008 Jonathan Moore Liles */
|
||||||
|
/* */
|
||||||
|
/* 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 the file COPYING. If not,write to the Free Software */
|
||||||
|
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||||
|
/*******************************************************************************/
|
||||||
|
|
||||||
|
/* Higher level event interface than midievent, supporting
|
||||||
|
doublely-linked list, marking, selection, and linking of note
|
||||||
|
on/off pairs. */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "midievent.H"
|
||||||
|
|
||||||
|
namespace MIDI
|
||||||
|
{
|
||||||
|
class event_list;
|
||||||
|
|
||||||
|
class event;
|
||||||
|
class note_properties {
|
||||||
|
public:
|
||||||
|
tick_t start;
|
||||||
|
tick_t duration;
|
||||||
|
int note;
|
||||||
|
int velocity;
|
||||||
|
};
|
||||||
|
|
||||||
|
class event : public midievent
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/* these are only to be used by event_list class! */
|
||||||
|
event *_next;
|
||||||
|
event *_prev;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
event *_link; /* other event in pair */
|
||||||
|
|
||||||
|
byte_t _selected;
|
||||||
|
|
||||||
|
void _init ( void );
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
event();
|
||||||
|
~event();
|
||||||
|
event ( const event &e );
|
||||||
|
event ( const midievent &e );
|
||||||
|
|
||||||
|
event * next ( void ) const;
|
||||||
|
event * prev ( void ) const;
|
||||||
|
|
||||||
|
void link ( event *event );
|
||||||
|
event * link ( void ) const;
|
||||||
|
bool linked ( void ) const;
|
||||||
|
void select ( void );
|
||||||
|
void deselect ( void );
|
||||||
|
bool selected ( int n ) const;
|
||||||
|
bool selected ( void ) const;
|
||||||
|
void note ( char note );
|
||||||
|
unsigned char note ( void ) const;
|
||||||
|
tick_t note_duration ( void ) const;
|
||||||
|
void note_duration ( tick_t l );
|
||||||
|
|
||||||
|
void get_note_properties ( note_properties *e ) const;
|
||||||
|
void set_note_properties ( const note_properties *e );
|
||||||
|
|
||||||
|
friend class event_list;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
inline event *
|
||||||
|
event::next ( void ) const
|
||||||
|
{
|
||||||
|
return _next;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline event *
|
||||||
|
event::prev ( void ) const
|
||||||
|
{
|
||||||
|
return _prev;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,631 @@
|
||||||
|
|
||||||
|
/*******************************************************************************/
|
||||||
|
/* Copyright (C) 2008 Jonathan Moore Liles */
|
||||||
|
/* */
|
||||||
|
/* 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 the file COPYING. If not,write to the Free Software */
|
||||||
|
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||||
|
/*******************************************************************************/
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
#include "event_list.H"
|
||||||
|
|
||||||
|
/* The operations we perform on event lists are clumsy with STL lists
|
||||||
|
and iterators so we have a custom doubly-linked list implementation
|
||||||
|
here for complete control */
|
||||||
|
|
||||||
|
namespace MIDI
|
||||||
|
{
|
||||||
|
#define RFOR_ALL( it ) for ( event *next, * it = _tail; it && ((next = it ->_prev), true) ; it = next )
|
||||||
|
#define FOR_ALL( it ) for ( event *next, * it = _head; it && ((next = it ->_next), true) ; it = next )
|
||||||
|
// #define FOR_ALL( e ) for ( event * e = _head; e; e = e ->_next )
|
||||||
|
#define FOR_SELECTED( e ) FOR_ALL( e ) if ( e ->selected() )
|
||||||
|
#define RFOR_SELECTED( e ) RFOR_ALL( e ) if ( e ->selected() )
|
||||||
|
|
||||||
|
|
||||||
|
event_list::event_list ( void )
|
||||||
|
{
|
||||||
|
_head = NULL;
|
||||||
|
_tail = NULL;
|
||||||
|
_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
event_list::~event_list ( void )
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy constructor */
|
||||||
|
event_list::event_list ( const event_list &el )
|
||||||
|
{
|
||||||
|
_copy( &el );
|
||||||
|
}
|
||||||
|
|
||||||
|
event_list &
|
||||||
|
event_list::operator= ( const event_list &rhs )
|
||||||
|
{
|
||||||
|
if ( this != &rhs )
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
|
||||||
|
_copy( &rhs );
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
event_list &
|
||||||
|
event_list::operator= ( const list <midievent> &rhs )
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
|
||||||
|
for ( list <midievent>::const_iterator me = rhs.begin(); me != rhs.end(); me++ )
|
||||||
|
{
|
||||||
|
event *e = new event( *me );
|
||||||
|
|
||||||
|
_insert( NULL, e );
|
||||||
|
}
|
||||||
|
|
||||||
|
relink();
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** allow indexing */
|
||||||
|
event *
|
||||||
|
event_list::operator[] ( unsigned int index )
|
||||||
|
{
|
||||||
|
unsigned int i = 0;
|
||||||
|
for ( event *e = _head; e; (e = e->_next), ++i )
|
||||||
|
if ( i == index )
|
||||||
|
return e;
|
||||||
|
|
||||||
|
// all else fails.
|
||||||
|
return _tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
event_list::_copy ( const event_list *el )
|
||||||
|
{
|
||||||
|
if ( ! el->_head )
|
||||||
|
{
|
||||||
|
_head = _tail = NULL;
|
||||||
|
_size = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_head = new event( *(el->_head) );
|
||||||
|
_head->_prev = NULL;
|
||||||
|
|
||||||
|
event *p = _head;
|
||||||
|
|
||||||
|
for ( event *e = el->_head->_next; e; e = e->_next )
|
||||||
|
{
|
||||||
|
event *n = new event( *e );
|
||||||
|
|
||||||
|
n->_next = NULL;
|
||||||
|
p->_next = n;
|
||||||
|
n->_prev = p;
|
||||||
|
|
||||||
|
p = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
_tail = p;
|
||||||
|
|
||||||
|
_size = el->_size;
|
||||||
|
|
||||||
|
relink();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** insert event /n/ before event /o/ */
|
||||||
|
void
|
||||||
|
event_list::_insert ( event *o, event *n )
|
||||||
|
{
|
||||||
|
++_size;
|
||||||
|
|
||||||
|
if ( ! o )
|
||||||
|
{
|
||||||
|
n->_next = NULL;
|
||||||
|
n->_prev = _tail;
|
||||||
|
|
||||||
|
if ( _tail )
|
||||||
|
_tail->_next = n;
|
||||||
|
|
||||||
|
_tail = n;
|
||||||
|
if ( ! _head )
|
||||||
|
_head = n;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event *t = o->_prev;
|
||||||
|
|
||||||
|
o->_prev = n;
|
||||||
|
n->_next = o;
|
||||||
|
n->_prev = t;
|
||||||
|
|
||||||
|
if ( ! t )
|
||||||
|
_head = n;
|
||||||
|
else
|
||||||
|
t->_next = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
event_list::unlink ( event *e )
|
||||||
|
{
|
||||||
|
if ( e->_next )
|
||||||
|
e->_next->_prev = e->_prev;
|
||||||
|
else
|
||||||
|
_tail = e->_prev;
|
||||||
|
|
||||||
|
if ( e->_prev )
|
||||||
|
e->_prev->_next = e->_next;
|
||||||
|
else
|
||||||
|
_head = e->_next;
|
||||||
|
|
||||||
|
--_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
event_list::clear ( void )
|
||||||
|
{
|
||||||
|
for ( event *e = _head; e ; )
|
||||||
|
{
|
||||||
|
event *n = e->_next;
|
||||||
|
delete e;
|
||||||
|
e = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
_head = NULL;
|
||||||
|
_tail = NULL;
|
||||||
|
_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
event_list::mix ( event *ne )
|
||||||
|
{
|
||||||
|
FOR_ALL( e )
|
||||||
|
if ( *e == *ne )
|
||||||
|
{
|
||||||
|
/* already have an event like this, drop it */
|
||||||
|
|
||||||
|
if ( ne->linked() )
|
||||||
|
delete ne->link();
|
||||||
|
|
||||||
|
delete ne;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
insert( ne );
|
||||||
|
if ( ne->linked() )
|
||||||
|
insert( ne->link() );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** remove elements from list /el/ to this list */
|
||||||
|
void
|
||||||
|
event_list::merge ( event_list *el )
|
||||||
|
{
|
||||||
|
event *n;
|
||||||
|
for ( event *e = el->_head; e; e = n )
|
||||||
|
{
|
||||||
|
n = e->_next;
|
||||||
|
|
||||||
|
el->unlink( e );
|
||||||
|
|
||||||
|
insert( e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** unlink event e */
|
||||||
|
void
|
||||||
|
event_list::remove ( event *e )
|
||||||
|
{
|
||||||
|
unlink( e );
|
||||||
|
delete e;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** sorted insert /e/ */
|
||||||
|
void
|
||||||
|
event_list::insert ( event *e )
|
||||||
|
{
|
||||||
|
/* find the place to insert */
|
||||||
|
RFOR_ALL( i )
|
||||||
|
if ( *e >= *i )
|
||||||
|
{
|
||||||
|
_insert( i->_next, e );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_insert( _head, e );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** just append event without sorting */
|
||||||
|
void
|
||||||
|
event_list::append ( event *e )
|
||||||
|
{
|
||||||
|
_insert( NULL, e );
|
||||||
|
}
|
||||||
|
|
||||||
|
event *
|
||||||
|
event_list::first ( void ) const
|
||||||
|
{
|
||||||
|
return _head;
|
||||||
|
}
|
||||||
|
|
||||||
|
event *
|
||||||
|
event_list::last ( void ) const
|
||||||
|
{
|
||||||
|
return _tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*************/
|
||||||
|
/* Selection */
|
||||||
|
/*************/
|
||||||
|
|
||||||
|
/** select all events from /start/ to /end/ inclusive */
|
||||||
|
void
|
||||||
|
event_list::select ( tick_t start, tick_t end )
|
||||||
|
{
|
||||||
|
FOR_ALL( e )
|
||||||
|
{
|
||||||
|
tick_t ts = e->timestamp();
|
||||||
|
|
||||||
|
/* don't count note offs exactly on start */
|
||||||
|
if ( ts == start && e->is_note_off() )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ( ts >= start && ts < end )
|
||||||
|
e->select();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** select note evenets from /start/ to /end/ within range /hi/ through /lo/ */
|
||||||
|
void
|
||||||
|
event_list::select ( tick_t start, tick_t end, int hi, int lo )
|
||||||
|
{
|
||||||
|
FOR_ALL( e )
|
||||||
|
{
|
||||||
|
tick_t ts = e->timestamp();
|
||||||
|
|
||||||
|
/* don't count note offs exactly on start */
|
||||||
|
if ( ! e->is_note_on() )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ( ts >= start && ts < end &&
|
||||||
|
e->note() <= hi && e->note() >= lo )
|
||||||
|
e->select();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** select ALL events */
|
||||||
|
void
|
||||||
|
event_list::select_all ( void )
|
||||||
|
{
|
||||||
|
FOR_ALL( e )
|
||||||
|
e->select();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
event_list::select_none ( void )
|
||||||
|
{
|
||||||
|
FOR_ALL( e )
|
||||||
|
e->deselect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
event_list::invert_selection ( void )
|
||||||
|
{
|
||||||
|
FOR_ALL( e )
|
||||||
|
if ( ! e->is_note_off() )
|
||||||
|
{
|
||||||
|
if ( e->selected() )
|
||||||
|
e->deselect();
|
||||||
|
else
|
||||||
|
e->select();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** remove all selected events */
|
||||||
|
void
|
||||||
|
event_list::remove_selected ( void )
|
||||||
|
{
|
||||||
|
FOR_SELECTED( e )
|
||||||
|
{
|
||||||
|
remove( e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** transpose selected notes (ignoring other event types) by /n/ tones
|
||||||
|
* (may span octaves) */
|
||||||
|
void
|
||||||
|
event_list::transpose_selected ( int n )
|
||||||
|
{
|
||||||
|
FOR_SELECTED( e )
|
||||||
|
{
|
||||||
|
if ( e->is_note_on() )
|
||||||
|
e->note( e->note() + n );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** change all notes of value /from/ to /to/ */
|
||||||
|
void
|
||||||
|
event_list::rewrite_selected ( int from, int to )
|
||||||
|
{
|
||||||
|
FOR_SELECTED( e )
|
||||||
|
{
|
||||||
|
if ( e->is_note_on() && e->note() == from )
|
||||||
|
e->note( to );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** get timestamp of earliest selected event */
|
||||||
|
tick_t
|
||||||
|
event_list::selection_min ( void )
|
||||||
|
{
|
||||||
|
FOR_SELECTED( e )
|
||||||
|
return e->timestamp();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tick_t
|
||||||
|
event_list::selection_max ( void )
|
||||||
|
{
|
||||||
|
RFOR_SELECTED( e )
|
||||||
|
return e->timestamp();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** move selected events by offset /o/ */
|
||||||
|
void
|
||||||
|
event_list::move_selected ( long o )
|
||||||
|
{
|
||||||
|
if ( o < 0 )
|
||||||
|
if ( selection_min() < (tick_t)( 0 - o ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( o < 0 )
|
||||||
|
{
|
||||||
|
FOR_SELECTED( e )
|
||||||
|
move( e, o );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RFOR_SELECTED( e )
|
||||||
|
move( e, o );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
event_list::push_selection ( void )
|
||||||
|
{
|
||||||
|
FOR_ALL( e )
|
||||||
|
if ( e->_selected )
|
||||||
|
++e->_selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
event_list::pop_selection ( void )
|
||||||
|
{
|
||||||
|
FOR_ALL( e )
|
||||||
|
if ( e->_selected )
|
||||||
|
--e->_selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** verify that all note ons are linked to note offs */
|
||||||
|
bool
|
||||||
|
event_list::verify ( void ) const
|
||||||
|
{
|
||||||
|
FOR_ALL( e )
|
||||||
|
if ( e->is_note_on() && ! e->linked() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** link /e/ (a note on) with the next corresponding note off */
|
||||||
|
void
|
||||||
|
event_list::link ( event *on )
|
||||||
|
{
|
||||||
|
if ( ! on->is_note_on() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
for ( event *off = on->_next; off; off = off->_next )
|
||||||
|
{
|
||||||
|
if ( off->linked() )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ( off->is_note_off() &&
|
||||||
|
off->channel() == on->channel() &&
|
||||||
|
off->note() == on->note() )
|
||||||
|
{
|
||||||
|
on->link( off );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WARNING( "no corresponding note_off found for note on, repairing" );
|
||||||
|
|
||||||
|
event *off = new event( *on );
|
||||||
|
|
||||||
|
off->opcode( event::NOTE_OFF );
|
||||||
|
|
||||||
|
on->link( off );
|
||||||
|
|
||||||
|
insert( off );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** insert /l/ ticks of time at /start/ */
|
||||||
|
void
|
||||||
|
event_list::insert_time ( tick_t start, tick_t l )
|
||||||
|
{
|
||||||
|
FOR_ALL( e )
|
||||||
|
{
|
||||||
|
tick_t ts = e->timestamp();
|
||||||
|
|
||||||
|
if ( e->is_note_off() )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ( ts >= start )
|
||||||
|
{
|
||||||
|
if ( e->is_note_on() )
|
||||||
|
{
|
||||||
|
/* only notes ENTIRELY WITHIN the range will be moved */
|
||||||
|
e->timestamp( ts + l );
|
||||||
|
e->link()->timestamp( e->link()->timestamp() + l );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
e->timestamp( e->timestamp() + l );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** delete events in range and close the gap */
|
||||||
|
void
|
||||||
|
event_list::delete_time ( tick_t start, tick_t end )
|
||||||
|
{
|
||||||
|
tick_t l = end - start;
|
||||||
|
|
||||||
|
push_selection();
|
||||||
|
|
||||||
|
select( start, end );
|
||||||
|
|
||||||
|
remove_selected();
|
||||||
|
|
||||||
|
pop_selection();
|
||||||
|
|
||||||
|
/* cut out the slack */
|
||||||
|
FOR_ALL( e )
|
||||||
|
{
|
||||||
|
tick_t ts = e->timestamp();
|
||||||
|
|
||||||
|
if ( ts >= end )
|
||||||
|
e->timestamp( ts - l );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** link all note ons to subsequent note offs */
|
||||||
|
void
|
||||||
|
event_list::relink ( void )
|
||||||
|
{
|
||||||
|
/* clear links */
|
||||||
|
FOR_ALL( e )
|
||||||
|
e->link( NULL );
|
||||||
|
|
||||||
|
/* link */
|
||||||
|
FOR_ALL( on )
|
||||||
|
link( on );
|
||||||
|
|
||||||
|
if ( ! verify() )
|
||||||
|
FATAL( "event list failed verification" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** resort event /e/ */
|
||||||
|
void
|
||||||
|
event_list::sort ( event *e )
|
||||||
|
{
|
||||||
|
unlink( e );
|
||||||
|
|
||||||
|
insert( e );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** resort entire list */
|
||||||
|
void
|
||||||
|
event_list::sort ( void )
|
||||||
|
{
|
||||||
|
event_list *temp = new event_list( );
|
||||||
|
|
||||||
|
_head = temp->_head;
|
||||||
|
_tail = temp->_tail;
|
||||||
|
|
||||||
|
FOR_ALL( n )
|
||||||
|
temp->insert( n );
|
||||||
|
|
||||||
|
temp->_head = NULL;
|
||||||
|
|
||||||
|
delete temp;
|
||||||
|
|
||||||
|
relink();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** move event /e/ by /o/ ticks */
|
||||||
|
void
|
||||||
|
event_list::move ( event *e, long o )
|
||||||
|
{
|
||||||
|
e->timestamp( e->timestamp() + o );
|
||||||
|
|
||||||
|
sort( e );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
event_list::empty ( void ) const
|
||||||
|
{
|
||||||
|
return _head == NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
event_list::size ( void ) const
|
||||||
|
{
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
event_list::_hi_lo ( bool sel, int *hi, int *lo ) const
|
||||||
|
{
|
||||||
|
*hi = 0;
|
||||||
|
*lo = 127;
|
||||||
|
|
||||||
|
FOR_ALL( e )
|
||||||
|
{
|
||||||
|
if ( sel && ! e->selected() )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ( ! e->is_note_on() )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int n = e->note();
|
||||||
|
|
||||||
|
if ( n > *hi )
|
||||||
|
*hi = n;
|
||||||
|
|
||||||
|
if ( n < *lo )
|
||||||
|
*lo = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** set /hi/ and /lo/ to the lowest and highest pitched note events in
|
||||||
|
* this list, respectively */
|
||||||
|
void
|
||||||
|
event_list::hi_lo_note ( int *hi, int *lo ) const
|
||||||
|
{
|
||||||
|
_hi_lo( false, hi, lo );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
event_list::selected_hi_lo_note ( int *hi, int *lo ) const
|
||||||
|
{
|
||||||
|
_hi_lo( true, hi, lo );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
|
||||||
|
/*******************************************************************************/
|
||||||
|
/* Copyright (C) 2008 Jonathan Moore Liles */
|
||||||
|
/* */
|
||||||
|
/* 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 the file COPYING. If not,write to the Free Software */
|
||||||
|
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||||
|
/*******************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "event.H"
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
namespace MIDI {
|
||||||
|
using std::list;
|
||||||
|
|
||||||
|
class midievent;
|
||||||
|
|
||||||
|
class event_list {
|
||||||
|
|
||||||
|
event * _head;
|
||||||
|
event * _tail;
|
||||||
|
|
||||||
|
size_t _size;
|
||||||
|
|
||||||
|
void _insert ( event *o, event *n );
|
||||||
|
void _copy ( const event_list *el );
|
||||||
|
void _hi_lo ( bool sel, int *hi, int *lo ) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
event_list ( void );
|
||||||
|
~event_list ( void );
|
||||||
|
event_list ( const event_list &el );
|
||||||
|
|
||||||
|
void clear ( void );
|
||||||
|
void merge ( event_list *el );
|
||||||
|
void unlink ( event *e );
|
||||||
|
void remove ( event *e );
|
||||||
|
void insert ( event *e );
|
||||||
|
event * first ( void ) const;
|
||||||
|
event * last ( void ) const;
|
||||||
|
void select ( tick_t start, tick_t end );
|
||||||
|
void select ( tick_t start, tick_t end, int hi, int lo );
|
||||||
|
|
||||||
|
void select_all ( void );
|
||||||
|
void select_none ( void );
|
||||||
|
void invert_selection ( void );
|
||||||
|
|
||||||
|
void remove_selected ( void );
|
||||||
|
void transpose_selected ( int n );
|
||||||
|
tick_t selection_min ( void );
|
||||||
|
tick_t selection_max ( void );
|
||||||
|
void move_selected ( long o );
|
||||||
|
void push_selection ( void );
|
||||||
|
void pop_selection ( void );
|
||||||
|
bool verify ( void ) const;
|
||||||
|
void link ( event *on );
|
||||||
|
void insert_time ( tick_t start, tick_t l );
|
||||||
|
void delete_time ( tick_t start, tick_t end );
|
||||||
|
void relink ( void );
|
||||||
|
void sort ( event *e );
|
||||||
|
void sort ( void );
|
||||||
|
void move ( event *e, long o );
|
||||||
|
bool empty ( void ) const;
|
||||||
|
size_t size ( void ) const;
|
||||||
|
void append ( event *e );
|
||||||
|
void mix ( event *ne );
|
||||||
|
void hi_lo_note ( int *hi, int *lo ) const;
|
||||||
|
void rewrite_selected ( int from, int to );
|
||||||
|
void selected_hi_lo_note ( int *hi, int *lo ) const;
|
||||||
|
|
||||||
|
|
||||||
|
event_list & operator= ( const event_list &rhs );
|
||||||
|
event_list & operator= ( const list <midievent> &rhs );
|
||||||
|
event *operator[] ( unsigned int index );
|
||||||
|
|
||||||
|
// friend class event;
|
||||||
|
};
|
||||||
|
}
|
|
@ -21,6 +21,9 @@ dsp.C
|
||||||
file.C
|
file.C
|
||||||
MIDI/midievent.C
|
MIDI/midievent.C
|
||||||
string_util.C
|
string_util.C
|
||||||
|
MIDI/event_list.C
|
||||||
|
MIDI/event.C
|
||||||
|
MIDI/midievent.C
|
||||||
''',
|
''',
|
||||||
includes = '.',
|
includes = '.',
|
||||||
export_incdirs = [ '.', 'nonlib'],
|
export_incdirs = [ '.', 'nonlib'],
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -20,7 +20,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "grid.H"
|
#include "grid.H"
|
||||||
#include <FL/Fl_Widget.H>
|
#include <FL/Fl_Group.H>
|
||||||
|
|
||||||
#include <sigc++/sigc++.h>
|
#include <sigc++/sigc++.h>
|
||||||
using namespace sigc;
|
using namespace sigc;
|
||||||
|
@ -29,9 +29,19 @@ class Mapping;
|
||||||
|
|
||||||
enum { LEFT, RIGHT, UP, DOWN, TO_PLAYHEAD, TO_NEXT_NOTE, TO_PREV_NOTE };
|
enum { LEFT, RIGHT, UP, DOWN, TO_PLAYHEAD, TO_NEXT_NOTE, TO_PREV_NOTE };
|
||||||
|
|
||||||
|
class Fl_Scrollbar;
|
||||||
|
class Fl_Slider;
|
||||||
|
|
||||||
class Canvas : public Fl_Widget, public trackable
|
class Canvas : public Fl_Group, public trackable
|
||||||
{
|
{
|
||||||
|
class Canvas_Panzoomer;
|
||||||
|
|
||||||
|
Canvas_Panzoomer *panzoomer;
|
||||||
|
Fl_Slider *vzoom;
|
||||||
|
|
||||||
|
/* these are grid coords, not pixels */
|
||||||
|
int _old_scroll_x;
|
||||||
|
int _old_scroll_y;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
int origin_x, origin_y;
|
int origin_x, origin_y;
|
||||||
|
@ -79,8 +89,6 @@ class Canvas : public Fl_Widget, public trackable
|
||||||
|
|
||||||
void _update_row_mapping ( void );
|
void _update_row_mapping ( void );
|
||||||
|
|
||||||
void redraw_ruler ( void );
|
|
||||||
void redraw_mapping ( void );
|
|
||||||
void draw_mapping ( void );
|
void draw_mapping ( void );
|
||||||
void draw_ruler ( void );
|
void draw_ruler ( void );
|
||||||
|
|
||||||
|
@ -88,21 +96,24 @@ class Canvas : public Fl_Widget, public trackable
|
||||||
void _lr ( void );
|
void _lr ( void );
|
||||||
|
|
||||||
bool viewable_x ( int x );
|
bool viewable_x ( int x );
|
||||||
void draw_line ( int x, int flags );
|
|
||||||
|
|
||||||
void update_mapping ( void );
|
void update_mapping ( void );
|
||||||
|
|
||||||
|
static void cb_scroll ( Fl_Widget *w, void *v );
|
||||||
|
void cb_scroll ( Fl_Widget *w );
|
||||||
|
static void draw_clip ( void *v, int X, int Y, int W, int H );
|
||||||
|
void draw_clip ( int X, int Y, int W, int H );
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum { OFF, ON, TOGGLE };
|
enum { OFF, ON, TOGGLE };
|
||||||
|
|
||||||
signal <void> signal_settings_change;
|
signal <void> signal_settings_change;
|
||||||
signal <void> signal_draw;
|
|
||||||
signal <void> signal_resize;
|
|
||||||
signal <void> signal_pan;
|
|
||||||
|
|
||||||
Canvas ( int X, int Y, int W, int H, const char *L=0 );
|
Canvas ( int X, int Y, int W, int H, const char *L=0 );
|
||||||
|
virtual ~Canvas ( );
|
||||||
|
|
||||||
|
void redraw_playhead ( void );
|
||||||
void handle_event_change ( void );
|
void handle_event_change ( void );
|
||||||
void set ( int x, int y );
|
void set ( int x, int y );
|
||||||
void grid ( Grid *g );
|
void grid ( Grid *g );
|
||||||
|
@ -112,19 +123,20 @@ public:
|
||||||
void resize_grid ( void );
|
void resize_grid ( void );
|
||||||
void resize ( int x, int y, int w, int h );
|
void resize ( int x, int y, int w, int h );
|
||||||
void copy ( void );
|
void copy ( void );
|
||||||
void clear ( void );
|
|
||||||
void flip ( void );
|
|
||||||
void draw_row_name ( int y, const char *name, int color );
|
void draw_row_name ( int y, const char *name, int color );
|
||||||
void draw_shape ( int x, int y, int w, int color );
|
// void draw_shape ( int x, int y, int w, int color );
|
||||||
static void draw_dash ( int x, int y, int l, int color, void *userdata );
|
static void draw_dash ( tick_t x, int y, tick_t l, int color, int selected, void *userdata );
|
||||||
int draw_playhead ( void );
|
void draw_dash ( tick_t x, int y, tick_t w, int color, int selected ) const;
|
||||||
|
void damage_grid ( tick_t x, int y, tick_t w, int h );
|
||||||
|
void draw_overlay ( void );
|
||||||
|
void draw_playhead ( void );
|
||||||
void draw ( void );
|
void draw ( void );
|
||||||
/* void redraw ( void ); */
|
|
||||||
bool grid_pos ( int *x, int *y ) const;
|
bool grid_pos ( int *x, int *y ) const;
|
||||||
int is_row_name ( int x, int y );
|
int is_row_press ( void ) const;
|
||||||
void unset ( int x, int y );
|
void unset ( int x, int y );
|
||||||
void adj_color ( int x, int y, int n );
|
void adj_color ( int x, int y, int n );
|
||||||
void adj_length ( int x, int y, int n );
|
void adj_length ( int x, int y, int n );
|
||||||
|
void set_end ( int x, int y, int n );
|
||||||
void select ( int x, int y );
|
void select ( int x, int y );
|
||||||
void select_range ( void );
|
void select_range ( void );
|
||||||
void invert_selection ( void );
|
void invert_selection ( void );
|
||||||
|
@ -149,6 +161,8 @@ public:
|
||||||
|
|
||||||
void move_selected ( int dir, int n );
|
void move_selected ( int dir, int n );
|
||||||
|
|
||||||
|
virtual int handle ( int m );
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline int
|
inline int
|
||||||
|
|
|
@ -27,7 +27,7 @@ const int MAX_PATTERN = 128;
|
||||||
const unsigned int PPQN = 480;
|
const unsigned int PPQN = 480;
|
||||||
|
|
||||||
/* interval between GUI updates for playhead movement, etc. */
|
/* interval between GUI updates for playhead movement, etc. */
|
||||||
const double TRANSPORT_POLL_INTERVAL = 0.05;
|
const double TRANSPORT_POLL_INTERVAL = 0.02;
|
||||||
|
|
||||||
const char APP_NAME[] = "Non-Sequencer";
|
const char APP_NAME[] = "Non-Sequencer";
|
||||||
const char APP_TITLE[] = "The Non-Sequencer";
|
const char APP_TITLE[] = "The Non-Sequencer";
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
struct dash
|
|
||||||
{
|
|
||||||
tick_t timestamp;
|
|
||||||
tick_t length;
|
|
||||||
unsigned char color;
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,144 +0,0 @@
|
||||||
|
|
||||||
/*******************************************************************************/
|
|
||||||
/* Copyright (C) 2007-2008 Jonathan Moore Liles */
|
|
||||||
/* */
|
|
||||||
/* 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 the file COPYING. If not,write to the Free Software */
|
|
||||||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|
||||||
/*******************************************************************************/
|
|
||||||
|
|
||||||
/* Higher level event interface, supporting doublely-linked list,
|
|
||||||
marking, selection, and linking of note pairs. */
|
|
||||||
|
|
||||||
#include "event.H"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
void
|
|
||||||
event::_init ( void )
|
|
||||||
{
|
|
||||||
_link = _next = _prev = NULL;
|
|
||||||
_selected = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
event::event ( void )
|
|
||||||
{
|
|
||||||
_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
event::~event ( void )
|
|
||||||
{
|
|
||||||
_link = _next = _prev = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* copy constructor */
|
|
||||||
event::event ( const event &e ) : midievent( e )
|
|
||||||
{
|
|
||||||
_link = _next = _prev = NULL;
|
|
||||||
_selected = e._selected;
|
|
||||||
}
|
|
||||||
|
|
||||||
event::event ( const midievent &e ) : midievent( e )
|
|
||||||
{
|
|
||||||
_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
event::link ( event *event )
|
|
||||||
{
|
|
||||||
if ( event == NULL )
|
|
||||||
{
|
|
||||||
if ( _link )
|
|
||||||
{
|
|
||||||
_link->_link = NULL;
|
|
||||||
_link = NULL;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_link = event;
|
|
||||||
_link->_link = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
event *
|
|
||||||
event::link ( void ) const
|
|
||||||
{
|
|
||||||
return _link;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
event::linked ( void ) const
|
|
||||||
{
|
|
||||||
return _link != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
event::select ( void )
|
|
||||||
{
|
|
||||||
_selected = 1;
|
|
||||||
|
|
||||||
if ( _link )
|
|
||||||
_link->_selected = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
event::deselect ( void )
|
|
||||||
{
|
|
||||||
_selected = 0;
|
|
||||||
|
|
||||||
if ( _link )
|
|
||||||
_link->_selected = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
event::selected ( int n ) const
|
|
||||||
{
|
|
||||||
return _selected == n;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
event::selected ( void ) const
|
|
||||||
{
|
|
||||||
return _selected == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* override this so we can update linked event */
|
|
||||||
void
|
|
||||||
event::note ( char note )
|
|
||||||
{
|
|
||||||
midievent::note( note );
|
|
||||||
|
|
||||||
if ( _link )
|
|
||||||
_link->midievent::note( note );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* stupid C++ makes us override the all polymorphic functions... */
|
|
||||||
unsigned char
|
|
||||||
event::note ( void ) const
|
|
||||||
{
|
|
||||||
return midievent::note();
|
|
||||||
}
|
|
||||||
|
|
||||||
tick_t
|
|
||||||
event::note_duration ( void ) const
|
|
||||||
{
|
|
||||||
return _link ? _link->timestamp() - timestamp() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
event::note_duration ( tick_t l )
|
|
||||||
{
|
|
||||||
if ( _link )
|
|
||||||
_link->timestamp( timestamp() + l );
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
|
|
||||||
/*******************************************************************************/
|
|
||||||
/* Copyright (C) 2007-2008 Jonathan Moore Liles */
|
|
||||||
/* */
|
|
||||||
/* 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 the file COPYING. If not,write to the Free Software */
|
|
||||||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|
||||||
/*******************************************************************************/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "midievent.H"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
class event_list;
|
|
||||||
|
|
||||||
class event : public midievent
|
|
||||||
{
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/* these are only to be used by event_list class! */
|
|
||||||
event *_next;
|
|
||||||
event *_prev;
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
event *_link; /* other event in pair */
|
|
||||||
|
|
||||||
byte_t _selected;
|
|
||||||
|
|
||||||
void _init ( void );
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
event();
|
|
||||||
~event();
|
|
||||||
event ( const event &e );
|
|
||||||
event ( const midievent &e );
|
|
||||||
|
|
||||||
event * next ( void ) const;
|
|
||||||
event * prev ( void ) const;
|
|
||||||
|
|
||||||
void link ( event *event );
|
|
||||||
event * link ( void ) const;
|
|
||||||
bool linked ( void ) const;
|
|
||||||
void select ( void );
|
|
||||||
void deselect ( void );
|
|
||||||
bool selected ( int n ) const;
|
|
||||||
bool selected ( void ) const;
|
|
||||||
void note ( char note );
|
|
||||||
unsigned char note ( void ) const;
|
|
||||||
tick_t note_duration ( void ) const;
|
|
||||||
void note_duration ( tick_t l );
|
|
||||||
|
|
||||||
|
|
||||||
friend class event_list;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
inline event *
|
|
||||||
event::next ( void ) const
|
|
||||||
{
|
|
||||||
return _next;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline event *
|
|
||||||
event::prev ( void ) const
|
|
||||||
{
|
|
||||||
return _prev;
|
|
||||||
}
|
|
|
@ -1,627 +0,0 @@
|
||||||
|
|
||||||
/*******************************************************************************/
|
|
||||||
/* Copyright (C) 2008 Jonathan Moore Liles */
|
|
||||||
/* */
|
|
||||||
/* 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 the file COPYING. If not,write to the Free Software */
|
|
||||||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|
||||||
/*******************************************************************************/
|
|
||||||
|
|
||||||
#include "event_list.H"
|
|
||||||
|
|
||||||
/* The operations we perform on event lists are clumsy with STL lists
|
|
||||||
and iterators so we have a custom doubly-linked list implementation
|
|
||||||
here for complete control */
|
|
||||||
|
|
||||||
#define RFOR_ALL( it ) for ( event *next, * it = _tail; it && ((next = it ->_prev), true) ; it = next )
|
|
||||||
#define FOR_ALL( it ) for ( event *next, * it = _head; it && ((next = it ->_next), true) ; it = next )
|
|
||||||
// #define FOR_ALL( e ) for ( event * e = _head; e; e = e ->_next )
|
|
||||||
#define FOR_SELECTED( e ) FOR_ALL( e ) if ( e ->selected() )
|
|
||||||
#define RFOR_SELECTED( e ) RFOR_ALL( e ) if ( e ->selected() )
|
|
||||||
|
|
||||||
|
|
||||||
event_list::event_list ( void )
|
|
||||||
{
|
|
||||||
_head = NULL;
|
|
||||||
_tail = NULL;
|
|
||||||
_size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
event_list::~event_list ( void )
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* copy constructor */
|
|
||||||
event_list::event_list ( const event_list &el )
|
|
||||||
{
|
|
||||||
_copy( &el );
|
|
||||||
}
|
|
||||||
|
|
||||||
event_list &
|
|
||||||
event_list::operator= ( const event_list &rhs )
|
|
||||||
{
|
|
||||||
if ( this != &rhs )
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
|
|
||||||
_copy( &rhs );
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
event_list &
|
|
||||||
event_list::operator= ( const list <midievent> &rhs )
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
|
|
||||||
for ( list <midievent>::const_iterator me = rhs.begin(); me != rhs.end(); me++ )
|
|
||||||
{
|
|
||||||
event *e = new event( *me );
|
|
||||||
|
|
||||||
_insert( NULL, e );
|
|
||||||
}
|
|
||||||
|
|
||||||
relink();
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** allow indexing */
|
|
||||||
event *
|
|
||||||
event_list::operator[] ( unsigned int index )
|
|
||||||
{
|
|
||||||
unsigned int i = 0;
|
|
||||||
for ( event *e = _head; e; (e = e->_next), ++i )
|
|
||||||
if ( i == index )
|
|
||||||
return e;
|
|
||||||
|
|
||||||
// all else fails.
|
|
||||||
return _tail;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
event_list::_copy ( const event_list *el )
|
|
||||||
{
|
|
||||||
if ( ! el->_head )
|
|
||||||
{
|
|
||||||
_head = _tail = NULL;
|
|
||||||
_size = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_head = new event( *(el->_head) );
|
|
||||||
_head->_prev = NULL;
|
|
||||||
|
|
||||||
event *p = _head;
|
|
||||||
|
|
||||||
for ( event *e = el->_head->_next; e; e = e->_next )
|
|
||||||
{
|
|
||||||
event *n = new event( *e );
|
|
||||||
|
|
||||||
n->_next = NULL;
|
|
||||||
p->_next = n;
|
|
||||||
n->_prev = p;
|
|
||||||
|
|
||||||
p = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
_tail = p;
|
|
||||||
|
|
||||||
_size = el->_size;
|
|
||||||
|
|
||||||
relink();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** insert event /n/ before event /o/ */
|
|
||||||
void
|
|
||||||
event_list::_insert ( event *o, event *n )
|
|
||||||
{
|
|
||||||
++_size;
|
|
||||||
|
|
||||||
if ( ! o )
|
|
||||||
{
|
|
||||||
n->_next = NULL;
|
|
||||||
n->_prev = _tail;
|
|
||||||
|
|
||||||
if ( _tail )
|
|
||||||
_tail->_next = n;
|
|
||||||
|
|
||||||
_tail = n;
|
|
||||||
if ( ! _head )
|
|
||||||
_head = n;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
event *t = o->_prev;
|
|
||||||
|
|
||||||
o->_prev = n;
|
|
||||||
n->_next = o;
|
|
||||||
n->_prev = t;
|
|
||||||
|
|
||||||
if ( ! t )
|
|
||||||
_head = n;
|
|
||||||
else
|
|
||||||
t->_next = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
event_list::unlink ( event *e )
|
|
||||||
{
|
|
||||||
if ( e->_next )
|
|
||||||
e->_next->_prev = e->_prev;
|
|
||||||
else
|
|
||||||
_tail = e->_prev;
|
|
||||||
|
|
||||||
if ( e->_prev )
|
|
||||||
e->_prev->_next = e->_next;
|
|
||||||
else
|
|
||||||
_head = e->_next;
|
|
||||||
|
|
||||||
--_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
event_list::clear ( void )
|
|
||||||
{
|
|
||||||
for ( event *e = _head; e ; )
|
|
||||||
{
|
|
||||||
event *n = e->_next;
|
|
||||||
delete e;
|
|
||||||
e = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
_head = NULL;
|
|
||||||
_tail = NULL;
|
|
||||||
_size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
event_list::mix ( event *ne )
|
|
||||||
{
|
|
||||||
FOR_ALL( e )
|
|
||||||
if ( *e == *ne )
|
|
||||||
{
|
|
||||||
/* already have an event like this, drop it */
|
|
||||||
|
|
||||||
if ( ne->linked() )
|
|
||||||
delete ne->link();
|
|
||||||
|
|
||||||
delete ne;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
insert( ne );
|
|
||||||
if ( ne->linked() )
|
|
||||||
insert( ne->link() );
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/** remove elements from list /el/ to this list */
|
|
||||||
void
|
|
||||||
event_list::merge ( event_list *el )
|
|
||||||
{
|
|
||||||
event *n;
|
|
||||||
for ( event *e = el->_head; e; e = n )
|
|
||||||
{
|
|
||||||
n = e->_next;
|
|
||||||
|
|
||||||
el->unlink( e );
|
|
||||||
|
|
||||||
insert( e );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** unlink event e */
|
|
||||||
void
|
|
||||||
event_list::remove ( event *e )
|
|
||||||
{
|
|
||||||
unlink( e );
|
|
||||||
delete e;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** sorted insert /e/ */
|
|
||||||
void
|
|
||||||
event_list::insert ( event *e )
|
|
||||||
{
|
|
||||||
/* find the place to insert */
|
|
||||||
RFOR_ALL( i )
|
|
||||||
if ( *e >= *i )
|
|
||||||
{
|
|
||||||
_insert( i->_next, e );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_insert( _head, e );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** just append event without sorting */
|
|
||||||
void
|
|
||||||
event_list::append ( event *e )
|
|
||||||
{
|
|
||||||
_insert( NULL, e );
|
|
||||||
}
|
|
||||||
|
|
||||||
event *
|
|
||||||
event_list::first ( void ) const
|
|
||||||
{
|
|
||||||
return _head;
|
|
||||||
}
|
|
||||||
|
|
||||||
event *
|
|
||||||
event_list::last ( void ) const
|
|
||||||
{
|
|
||||||
return _tail;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*************/
|
|
||||||
/* Selection */
|
|
||||||
/*************/
|
|
||||||
|
|
||||||
/** select all events from /start/ to /end/ inclusive */
|
|
||||||
void
|
|
||||||
event_list::select ( tick_t start, tick_t end )
|
|
||||||
{
|
|
||||||
FOR_ALL( e )
|
|
||||||
{
|
|
||||||
tick_t ts = e->timestamp();
|
|
||||||
|
|
||||||
/* don't count note offs exactly on start */
|
|
||||||
if ( ts == start && e->is_note_off() )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ( ts >= start && ts < end )
|
|
||||||
e->select();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** select note evenets from /start/ to /end/ within range /hi/ through /lo/ */
|
|
||||||
void
|
|
||||||
event_list::select ( tick_t start, tick_t end, int hi, int lo )
|
|
||||||
{
|
|
||||||
FOR_ALL( e )
|
|
||||||
{
|
|
||||||
tick_t ts = e->timestamp();
|
|
||||||
|
|
||||||
/* don't count note offs exactly on start */
|
|
||||||
if ( ! e->is_note_on() )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ( ts >= start && ts < end &&
|
|
||||||
e->note() <= hi && e->note() >= lo )
|
|
||||||
e->select();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** select ALL events */
|
|
||||||
void
|
|
||||||
event_list::select_all ( void )
|
|
||||||
{
|
|
||||||
FOR_ALL( e )
|
|
||||||
e->select();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
event_list::select_none ( void )
|
|
||||||
{
|
|
||||||
FOR_ALL( e )
|
|
||||||
e->deselect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
event_list::invert_selection ( void )
|
|
||||||
{
|
|
||||||
FOR_ALL( e )
|
|
||||||
if ( ! e->is_note_off() )
|
|
||||||
{
|
|
||||||
if ( e->selected() )
|
|
||||||
e->deselect();
|
|
||||||
else
|
|
||||||
e->select();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** remove all selected events */
|
|
||||||
void
|
|
||||||
event_list::remove_selected ( void )
|
|
||||||
{
|
|
||||||
FOR_SELECTED( e )
|
|
||||||
{
|
|
||||||
remove( e );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** transpose selected notes (ignoring other event types) by /n/ tones
|
|
||||||
* (may span octaves) */
|
|
||||||
void
|
|
||||||
event_list::transpose_selected ( int n )
|
|
||||||
{
|
|
||||||
FOR_SELECTED( e )
|
|
||||||
{
|
|
||||||
if ( e->is_note_on() )
|
|
||||||
e->note( e->note() + n );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/** change all notes of value /from/ to /to/ */
|
|
||||||
void
|
|
||||||
event_list::rewrite_selected ( int from, int to )
|
|
||||||
{
|
|
||||||
FOR_SELECTED( e )
|
|
||||||
{
|
|
||||||
if ( e->is_note_on() && e->note() == from )
|
|
||||||
e->note( to );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** get timestamp of earliest selected event */
|
|
||||||
tick_t
|
|
||||||
event_list::selection_min ( void )
|
|
||||||
{
|
|
||||||
FOR_SELECTED( e )
|
|
||||||
return e->timestamp();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
tick_t
|
|
||||||
event_list::selection_max ( void )
|
|
||||||
{
|
|
||||||
RFOR_SELECTED( e )
|
|
||||||
return e->timestamp();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** move selected events by offset /o/ */
|
|
||||||
void
|
|
||||||
event_list::move_selected ( long o )
|
|
||||||
{
|
|
||||||
if ( o < 0 )
|
|
||||||
if ( selection_min() < (tick_t)( 0 - o ) )
|
|
||||||
return;
|
|
||||||
|
|
||||||
if ( o < 0 )
|
|
||||||
{
|
|
||||||
FOR_SELECTED( e )
|
|
||||||
move( e, o );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RFOR_SELECTED( e )
|
|
||||||
move( e, o );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
event_list::push_selection ( void )
|
|
||||||
{
|
|
||||||
FOR_ALL( e )
|
|
||||||
if ( e->_selected )
|
|
||||||
++e->_selected;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
event_list::pop_selection ( void )
|
|
||||||
{
|
|
||||||
FOR_ALL( e )
|
|
||||||
if ( e->_selected )
|
|
||||||
--e->_selected;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** verify that all note ons are linked to note offs */
|
|
||||||
bool
|
|
||||||
event_list::verify ( void ) const
|
|
||||||
{
|
|
||||||
FOR_ALL( e )
|
|
||||||
if ( e->is_note_on() && ! e->linked() )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** link /e/ (a note on) with the next corresponding note off */
|
|
||||||
void
|
|
||||||
event_list::link ( event *on )
|
|
||||||
{
|
|
||||||
if ( ! on->is_note_on() )
|
|
||||||
return;
|
|
||||||
|
|
||||||
for ( event *off = on->_next; off; off = off->_next )
|
|
||||||
{
|
|
||||||
if ( off->linked() )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ( off->is_note_off() &&
|
|
||||||
off->channel() == on->channel() &&
|
|
||||||
off->note() == on->note() )
|
|
||||||
{
|
|
||||||
on->link( off );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WARNING( "no corresponding note_off found for note on, repairing" );
|
|
||||||
|
|
||||||
event *off = new event( *on );
|
|
||||||
|
|
||||||
off->opcode( event::NOTE_OFF );
|
|
||||||
|
|
||||||
on->link( off );
|
|
||||||
|
|
||||||
insert( off );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** insert /l/ ticks of time at /start/ */
|
|
||||||
void
|
|
||||||
event_list::insert_time ( tick_t start, tick_t l )
|
|
||||||
{
|
|
||||||
FOR_ALL( e )
|
|
||||||
{
|
|
||||||
tick_t ts = e->timestamp();
|
|
||||||
|
|
||||||
if ( e->is_note_off() )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ( ts >= start )
|
|
||||||
{
|
|
||||||
if ( e->is_note_on() )
|
|
||||||
{
|
|
||||||
/* only notes ENTIRELY WITHIN the range will be moved */
|
|
||||||
e->timestamp( ts + l );
|
|
||||||
e->link()->timestamp( e->link()->timestamp() + l );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
e->timestamp( e->timestamp() + l );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sort();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** delete events in range and close the gap */
|
|
||||||
void
|
|
||||||
event_list::delete_time ( tick_t start, tick_t end )
|
|
||||||
{
|
|
||||||
tick_t l = end - start;
|
|
||||||
|
|
||||||
push_selection();
|
|
||||||
|
|
||||||
select( start, end );
|
|
||||||
|
|
||||||
remove_selected();
|
|
||||||
|
|
||||||
pop_selection();
|
|
||||||
|
|
||||||
/* cut out the slack */
|
|
||||||
FOR_ALL( e )
|
|
||||||
{
|
|
||||||
tick_t ts = e->timestamp();
|
|
||||||
|
|
||||||
if ( ts >= end )
|
|
||||||
e->timestamp( ts - l );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** link all note ons to subsequent note offs */
|
|
||||||
void
|
|
||||||
event_list::relink ( void )
|
|
||||||
{
|
|
||||||
/* clear links */
|
|
||||||
FOR_ALL( e )
|
|
||||||
e->link( NULL );
|
|
||||||
|
|
||||||
/* link */
|
|
||||||
FOR_ALL( on )
|
|
||||||
link( on );
|
|
||||||
|
|
||||||
if ( ! verify() )
|
|
||||||
ASSERTION( "event list failed verification" );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** resort event /e/ */
|
|
||||||
void
|
|
||||||
event_list::sort ( event *e )
|
|
||||||
{
|
|
||||||
unlink( e );
|
|
||||||
|
|
||||||
insert( e );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** resort entire list */
|
|
||||||
void
|
|
||||||
event_list::sort ( void )
|
|
||||||
{
|
|
||||||
event_list *temp = new event_list( );
|
|
||||||
|
|
||||||
_head = temp->_head;
|
|
||||||
_tail = temp->_tail;
|
|
||||||
|
|
||||||
FOR_ALL( n )
|
|
||||||
temp->insert( n );
|
|
||||||
|
|
||||||
temp->_head = NULL;
|
|
||||||
|
|
||||||
delete temp;
|
|
||||||
|
|
||||||
relink();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** move event /e/ by /o/ ticks */
|
|
||||||
void
|
|
||||||
event_list::move ( event *e, long o )
|
|
||||||
{
|
|
||||||
e->timestamp( e->timestamp() + o );
|
|
||||||
|
|
||||||
sort( e );
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
event_list::empty ( void ) const
|
|
||||||
{
|
|
||||||
return _head == NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
|
||||||
event_list::size ( void ) const
|
|
||||||
{
|
|
||||||
return _size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
event_list::_hi_lo ( bool sel, int *hi, int *lo ) const
|
|
||||||
{
|
|
||||||
*hi = 0;
|
|
||||||
*lo = 127;
|
|
||||||
|
|
||||||
FOR_ALL( e )
|
|
||||||
{
|
|
||||||
if ( sel && ! e->selected() )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ( ! e->is_note_on() )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int n = e->note();
|
|
||||||
|
|
||||||
if ( n > *hi )
|
|
||||||
*hi = n;
|
|
||||||
|
|
||||||
if ( n < *lo )
|
|
||||||
*lo = n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** set /hi/ and /lo/ to the lowest and highest pitched note events in
|
|
||||||
* this list, respectively */
|
|
||||||
void
|
|
||||||
event_list::hi_lo_note ( int *hi, int *lo ) const
|
|
||||||
{
|
|
||||||
_hi_lo( false, hi, lo );
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
event_list::selected_hi_lo_note ( int *hi, int *lo ) const
|
|
||||||
{
|
|
||||||
_hi_lo( true, hi, lo );
|
|
||||||
}
|
|
|
@ -1,89 +0,0 @@
|
||||||
|
|
||||||
/*******************************************************************************/
|
|
||||||
/* Copyright (C) 2008 Jonathan Moore Liles */
|
|
||||||
/* */
|
|
||||||
/* 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 the file COPYING. If not,write to the Free Software */
|
|
||||||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|
||||||
/*******************************************************************************/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "event.H"
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
using std::list;
|
|
||||||
|
|
||||||
class midievent;
|
|
||||||
|
|
||||||
class event_list {
|
|
||||||
|
|
||||||
event * _head;
|
|
||||||
event * _tail;
|
|
||||||
|
|
||||||
size_t _size;
|
|
||||||
|
|
||||||
void _insert ( event *o, event *n );
|
|
||||||
void _copy ( const event_list *el );
|
|
||||||
void _hi_lo ( bool sel, int *hi, int *lo ) const;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
event_list ( void );
|
|
||||||
~event_list ( void );
|
|
||||||
event_list ( const event_list &el );
|
|
||||||
|
|
||||||
void clear ( void );
|
|
||||||
void merge ( event_list *el );
|
|
||||||
void unlink ( event *e );
|
|
||||||
void remove ( event *e );
|
|
||||||
void insert ( event *e );
|
|
||||||
event * first ( void ) const;
|
|
||||||
event * last ( void ) const;
|
|
||||||
void select ( tick_t start, tick_t end );
|
|
||||||
void select ( tick_t start, tick_t end, int hi, int lo );
|
|
||||||
|
|
||||||
void select_all ( void );
|
|
||||||
void select_none ( void );
|
|
||||||
void invert_selection ( void );
|
|
||||||
|
|
||||||
void remove_selected ( void );
|
|
||||||
void transpose_selected ( int n );
|
|
||||||
tick_t selection_min ( void );
|
|
||||||
tick_t selection_max ( void );
|
|
||||||
void move_selected ( long o );
|
|
||||||
void push_selection ( void );
|
|
||||||
void pop_selection ( void );
|
|
||||||
bool verify ( void ) const;
|
|
||||||
void link ( event *on );
|
|
||||||
void insert_time ( tick_t start, tick_t l );
|
|
||||||
void delete_time ( tick_t start, tick_t end );
|
|
||||||
void relink ( void );
|
|
||||||
void sort ( event *e );
|
|
||||||
void sort ( void );
|
|
||||||
void move ( event *e, long o );
|
|
||||||
bool empty ( void ) const;
|
|
||||||
size_t size ( void ) const;
|
|
||||||
void append ( event *e );
|
|
||||||
void mix ( event *ne );
|
|
||||||
void hi_lo_note ( int *hi, int *lo ) const;
|
|
||||||
void rewrite_selected ( int from, int to );
|
|
||||||
void selected_hi_lo_note ( int *hi, int *lo ) const;
|
|
||||||
|
|
||||||
|
|
||||||
event_list & operator= ( const event_list &rhs );
|
|
||||||
event_list & operator= ( const list <midievent> &rhs );
|
|
||||||
event *operator[] ( unsigned int index );
|
|
||||||
|
|
||||||
// friend class event;
|
|
||||||
};
|
|
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
#include "smf.H"
|
#include "smf.H"
|
||||||
|
|
||||||
|
using namespace MIDI;
|
||||||
|
|
||||||
Grid::Grid ( void )
|
Grid::Grid ( void )
|
||||||
{
|
{
|
||||||
_name = NULL;
|
_name = NULL;
|
||||||
|
@ -44,7 +46,8 @@ Grid::Grid ( void )
|
||||||
d->length = 0;
|
d->length = 0;
|
||||||
|
|
||||||
_bpb = 4;
|
_bpb = 4;
|
||||||
_ppqn = 1;
|
/* how many grid positions there are per beat */
|
||||||
|
_ppqn = 4;
|
||||||
|
|
||||||
viewport.h = 32;
|
viewport.h = 32;
|
||||||
viewport.w = 32;
|
viewport.w = 32;
|
||||||
|
@ -184,31 +187,6 @@ Grid::_delete ( int x, int y )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
Grid::_get ( struct dash *d, int x, int y ) const
|
|
||||||
{
|
|
||||||
event *e = _event ( x, y, false );
|
|
||||||
|
|
||||||
if ( e )
|
|
||||||
{
|
|
||||||
tick_t ts = e->timestamp();
|
|
||||||
tick_t l = 0;
|
|
||||||
|
|
||||||
if ( e->linked() )
|
|
||||||
l = e->link()->timestamp() - ts;
|
|
||||||
else
|
|
||||||
WARNING( "Found unlinked note on" );
|
|
||||||
|
|
||||||
d->timestamp = ts_to_x( ts );
|
|
||||||
d->length = ts_to_x( l );
|
|
||||||
d->color = e->note_velocity();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Grid::clear ( void )
|
Grid::clear ( void )
|
||||||
{
|
{
|
||||||
|
@ -219,13 +197,6 @@ Grid::clear ( void )
|
||||||
unlock();
|
unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
Grid::get ( struct dash *d, int x, int y ) const
|
|
||||||
{
|
|
||||||
return _get( d, x, y );
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Grid::del ( int x, int y )
|
Grid::del ( int x, int y )
|
||||||
{
|
{
|
||||||
|
@ -318,8 +289,15 @@ Grid::expand ( void )
|
||||||
unlock();
|
unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** returns true if there is a note event at x,y */
|
||||||
|
bool
|
||||||
|
Grid::is_set ( int x, int y ) const
|
||||||
|
{
|
||||||
|
return _event( x, y, false );
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Grid::put ( int x, int y, tick_t l )
|
Grid::put ( int x, int y, tick_t l, int velocity )
|
||||||
{
|
{
|
||||||
|
|
||||||
int xl = ts_to_x( l );
|
int xl = ts_to_x( l );
|
||||||
|
@ -328,10 +306,8 @@ Grid::put ( int x, int y, tick_t l )
|
||||||
event *on = new event;
|
event *on = new event;
|
||||||
event *off = new event;
|
event *off = new event;
|
||||||
|
|
||||||
struct dash d;
|
|
||||||
|
|
||||||
// Don't allow overlap (Why not?)
|
// Don't allow overlap (Why not?)
|
||||||
if ( get( &d, x, y ) || get( &d, x + xl - 1, y ) )
|
if ( _event( x, y, false ) || _event( x + xl - 1, y, false ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DMESSAGE( "put %d,%d", x, y );
|
DMESSAGE( "put %d,%d", x, y );
|
||||||
|
@ -343,18 +319,19 @@ Grid::put ( int x, int y, tick_t l )
|
||||||
on->status( event::NOTE_ON );
|
on->status( event::NOTE_ON );
|
||||||
on->note( note );
|
on->note( note );
|
||||||
on->timestamp( ts );
|
on->timestamp( ts );
|
||||||
on->note_velocity( 64 );
|
on->note_velocity( velocity );
|
||||||
on->link( off );
|
on->link( off );
|
||||||
|
|
||||||
off->status( event::NOTE_OFF );
|
off->status( event::NOTE_OFF );
|
||||||
off->note( note );
|
off->note( note );
|
||||||
off->timestamp( ts + l );
|
off->timestamp( ts + l );
|
||||||
off->note_velocity( 64 );
|
off->note_velocity( velocity );
|
||||||
off->link( on );
|
off->link( on );
|
||||||
|
|
||||||
_rw->events.insert( on );
|
_rw->events.insert( on );
|
||||||
_rw->events.insert( off );
|
_rw->events.insert( off );
|
||||||
|
|
||||||
|
|
||||||
expand();
|
expand();
|
||||||
|
|
||||||
unlock();
|
unlock();
|
||||||
|
@ -457,6 +434,95 @@ Grid::adj_duration ( int x, int y, int l )
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Grid::set_duration ( int x, int y, int ex )
|
||||||
|
{
|
||||||
|
if ( ex < 1 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
lock();
|
||||||
|
|
||||||
|
event *e = _event( x, y, true );
|
||||||
|
|
||||||
|
if ( e )
|
||||||
|
{
|
||||||
|
DMESSAGE( "adjusting duration" );
|
||||||
|
|
||||||
|
e->note_duration( x_to_ts( ex ) );
|
||||||
|
|
||||||
|
_rw->events.sort( e->link() );
|
||||||
|
}
|
||||||
|
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Grid::get_note_properties ( int x, int y, note_properties *p ) const
|
||||||
|
{
|
||||||
|
const event *e = _event( x, y, false );
|
||||||
|
|
||||||
|
e->get_note_properties( p );
|
||||||
|
|
||||||
|
p->start = p->start;
|
||||||
|
p->duration = p->duration;
|
||||||
|
p->note = note_to_y( p->note );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* void */
|
||||||
|
/* Grid::set_note_properties ( int x, int y, const note_properties *p ) */
|
||||||
|
/* { */
|
||||||
|
/* lock(); */
|
||||||
|
|
||||||
|
/* const event *e = _event( x, y, true ); */
|
||||||
|
|
||||||
|
/* e->set_note_properties( p ); */
|
||||||
|
|
||||||
|
/* unlock(); */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** if there's a note at grid coordinates x,y, then adjust them to the beginning of the note */
|
||||||
|
int
|
||||||
|
Grid::get_start ( int *x, int *y ) const
|
||||||
|
{
|
||||||
|
const event *e = _event( *x, *y, false );
|
||||||
|
|
||||||
|
if ( e )
|
||||||
|
{
|
||||||
|
*x = ts_to_x( e->timestamp() );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Grid::set_end ( int x, int y, int ex )
|
||||||
|
{
|
||||||
|
lock();
|
||||||
|
|
||||||
|
event *e = _event( x, y, true );
|
||||||
|
|
||||||
|
if ( e )
|
||||||
|
{
|
||||||
|
DMESSAGE( "adjusting duration" );
|
||||||
|
|
||||||
|
tick_t ts = x_to_ts( ex );
|
||||||
|
|
||||||
|
if ( ts > e->timestamp() &&
|
||||||
|
ts - e->timestamp() > x_to_ts( 1 ) )
|
||||||
|
{
|
||||||
|
e->note_duration( ts - e->timestamp() );
|
||||||
|
|
||||||
|
_rw->events.sort( e->link() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Grid::toggle_select ( int x, int y )
|
Grid::toggle_select ( int x, int y )
|
||||||
{
|
{
|
||||||
|
@ -544,6 +610,16 @@ Grid::select_none ( void )
|
||||||
unlock();
|
unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Grid::select_all ( void )
|
||||||
|
{
|
||||||
|
lock();
|
||||||
|
|
||||||
|
_rw->events.select_all();
|
||||||
|
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Grid::invert_selection ( void )
|
Grid::invert_selection ( void )
|
||||||
{
|
{
|
||||||
|
@ -656,13 +732,13 @@ Grid::print ( void ) const
|
||||||
void
|
void
|
||||||
Grid::draw_notes ( draw_note_func_t draw_note, void *userdata ) const
|
Grid::draw_notes ( draw_note_func_t draw_note, void *userdata ) const
|
||||||
{
|
{
|
||||||
int bx = viewport.x;
|
/* int bx = viewport.x; */
|
||||||
int by = viewport.y;
|
/* int by = viewport.y; */
|
||||||
int bw = viewport.w;
|
/* int bw = viewport.w + 100; /\* FIXME: hack *\/ */
|
||||||
int bh = viewport.h;
|
/* int bh = viewport.h; */
|
||||||
|
|
||||||
const tick_t start = x_to_ts( bx );
|
/* const tick_t start = x_to_ts( bx ); */
|
||||||
const tick_t end = x_to_ts( bx + bw );
|
/* const tick_t end = x_to_ts( bx + bw ); */
|
||||||
|
|
||||||
data *d = const_cast< data *>( _rd );
|
data *d = const_cast< data *>( _rd );
|
||||||
|
|
||||||
|
@ -677,11 +753,13 @@ Grid::draw_notes ( draw_note_func_t draw_note, void *userdata ) const
|
||||||
|
|
||||||
const tick_t tse = e->link()->timestamp();
|
const tick_t tse = e->link()->timestamp();
|
||||||
|
|
||||||
if ( tse >= start && ts <= end )
|
/* if ( tse >= start && ts <= end ) */
|
||||||
draw_note( ts_to_x( ts ),
|
draw_note( // ts_to_x( ts ),
|
||||||
|
ts,
|
||||||
note_to_y( e->note() ),
|
note_to_y( e->note() ),
|
||||||
ts_to_x( tse - ts ),
|
tse - ts,
|
||||||
e->note_velocity(),
|
e->note_velocity(),
|
||||||
|
e->selected(),
|
||||||
userdata );
|
userdata );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -768,12 +846,17 @@ Grid::ppqn ( void ) const
|
||||||
void
|
void
|
||||||
Grid::resolution ( unsigned int n )
|
Grid::resolution ( unsigned int n )
|
||||||
{
|
{
|
||||||
if ( n < 4 )
|
/* if ( n < 4 ) */
|
||||||
ASSERTION( "bad resolution: %d", n );
|
/* ASSERTION( "bad resolution: %d", n ); */
|
||||||
|
|
||||||
_ppqn = n / 4;
|
// _ppqn = n / 4;
|
||||||
|
_ppqn = n;
|
||||||
DMESSAGE( "%d setting resolution to %d", n, _ppqn );
|
DMESSAGE( "%d setting resolution to %d", n, _ppqn );
|
||||||
|
|
||||||
|
/* ensure that the correct number of bars are in the viewport */
|
||||||
|
|
||||||
|
viewport.w = _ppqn * _bpb * 2;
|
||||||
|
|
||||||
signal_events_change();
|
signal_events_change();
|
||||||
|
|
||||||
signal_settings_change();
|
signal_settings_change();
|
||||||
|
|
|
@ -19,9 +19,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "event.H"
|
#include <MIDI/event.H>
|
||||||
#include "event_list.H"
|
#include <MIDI/event_list.H>
|
||||||
#include "dash.H"
|
|
||||||
#include "const.h"
|
#include "const.h"
|
||||||
#include "instrument.H"
|
#include "instrument.H"
|
||||||
|
|
||||||
|
@ -48,7 +47,7 @@ struct data {
|
||||||
|
|
||||||
tick_t length;
|
tick_t length;
|
||||||
int state;
|
int state;
|
||||||
event_list events;
|
MIDI::event_list events;
|
||||||
|
|
||||||
data( void )
|
data( void )
|
||||||
{
|
{
|
||||||
|
@ -131,9 +130,8 @@ protected:
|
||||||
list <data *> _history;
|
list <data *> _history;
|
||||||
|
|
||||||
void _remove_marked ( void );
|
void _remove_marked ( void );
|
||||||
event * _event ( int x, int y, bool write ) const;
|
MIDI::event * _event ( int x, int y, bool write ) const;
|
||||||
bool _delete ( int x, int y );
|
bool _delete ( int x, int y );
|
||||||
bool _get ( struct dash *d, int x, int y ) const;
|
|
||||||
void _link ( void );
|
void _link ( void );
|
||||||
void _relink ( void );
|
void _relink ( void );
|
||||||
void _fix_length ( void );
|
void _fix_length ( void );
|
||||||
|
@ -145,7 +143,7 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
typedef void draw_note_func_t ( int x, int y, int l, int velocity, void *userdata );
|
typedef void draw_note_func_t ( tick_t x, int y, tick_t l, int velocity, int selected, void *userdata );
|
||||||
|
|
||||||
void draw_notes ( draw_note_func_t draw_note, void *userdata ) const;
|
void draw_notes ( draw_note_func_t draw_note, void *userdata ) const;
|
||||||
|
|
||||||
|
@ -158,10 +156,12 @@ public:
|
||||||
virtual ~Grid ( void );
|
virtual ~Grid ( void );
|
||||||
Grid ( const Grid &rhs );
|
Grid ( const Grid &rhs );
|
||||||
|
|
||||||
|
virtual bool velocity_sensitive ( void ) const { return true; }
|
||||||
|
|
||||||
int y_to_note ( int y ) const;
|
int y_to_note ( int y ) const;
|
||||||
int note_to_y ( int n ) const;
|
int note_to_y ( int n ) const;
|
||||||
tick_t x_to_ts ( uint x ) const;
|
tick_t x_to_ts ( tick_t x ) const;
|
||||||
uint ts_to_x ( tick_t ts ) const;
|
tick_t ts_to_x ( tick_t ts ) const;
|
||||||
|
|
||||||
virtual Grid * create ( void ) = 0;
|
virtual Grid * create ( void ) = 0;
|
||||||
virtual Grid * clone ( void ) = 0;
|
virtual Grid * clone ( void ) = 0;
|
||||||
|
@ -170,17 +170,20 @@ public:
|
||||||
|
|
||||||
virtual Grid * by_number ( int n ) const = 0;
|
virtual Grid * by_number ( int n ) const = 0;
|
||||||
|
|
||||||
virtual void put ( int x, int y, tick_t l );
|
virtual void put ( int x, int y, tick_t l, int velocity = 64 );
|
||||||
|
virtual bool is_set ( int x, int y ) const;
|
||||||
|
|
||||||
void lock ( void );
|
void lock ( void );
|
||||||
void unlock ( void );
|
void unlock ( void );
|
||||||
void clear ( void );
|
void clear ( void );
|
||||||
int get ( struct dash *d, int x, int y ) const;
|
|
||||||
void del ( int x, int y );
|
void del ( int x, int y );
|
||||||
void adj_velocity ( int x, int y, int n );
|
void adj_velocity ( int x, int y, int n );
|
||||||
void adj_duration ( int x, int y, int l );
|
void adj_duration ( int x, int y, int l );
|
||||||
|
void set_duration ( int x, int y, int l );
|
||||||
|
void set_end ( int x, int y, int l );
|
||||||
|
int get_start ( int *x, int *y ) const;
|
||||||
void move ( int x, int y, int nx, int ny );
|
void move ( int x, int y, int nx, int ny );
|
||||||
void record_event ( event *e );
|
void record_event ( MIDI::event *e );
|
||||||
tick_t index ( void ) const;
|
tick_t index ( void ) const;
|
||||||
bool playing ( void ) const;
|
bool playing ( void ) const;
|
||||||
|
|
||||||
|
@ -219,6 +222,7 @@ public:
|
||||||
void select ( int start, int end, int t, int b );
|
void select ( int start, int end, int t, int b );
|
||||||
void delete_time ( int start, int end );
|
void delete_time ( int start, int end );
|
||||||
void select_none ( void );
|
void select_none ( void );
|
||||||
|
void select_all ( void );
|
||||||
void invert_selection ( void );
|
void invert_selection ( void );
|
||||||
|
|
||||||
void resolution ( unsigned int n );
|
void resolution ( unsigned int n );
|
||||||
|
@ -228,11 +232,19 @@ public:
|
||||||
void draw ( Canvas *c, int bx, int by, int bw, int bh );
|
void draw ( Canvas *c, int bx, int by, int bw, int bh );
|
||||||
void print ( void ) const;
|
void print ( void ) const;
|
||||||
|
|
||||||
event_list * events ( void ) const;
|
MIDI::event_list * events ( void ) const;
|
||||||
void events ( const event_list * el );
|
void events ( const MIDI::event_list * el );
|
||||||
|
|
||||||
|
void get_note_properties ( int x, int y, MIDI::note_properties *p ) const;
|
||||||
|
|
||||||
|
virtual tick_t default_length ( void ) const
|
||||||
|
{
|
||||||
|
return PPQN;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
inline int
|
inline int
|
||||||
Grid::y_to_note ( int y ) const
|
Grid::y_to_note ( int y ) const
|
||||||
{
|
{
|
||||||
|
@ -246,14 +258,14 @@ Grid::note_to_y ( int n ) const
|
||||||
}
|
}
|
||||||
|
|
||||||
inline tick_t
|
inline tick_t
|
||||||
Grid::x_to_ts ( unsigned int x ) const
|
Grid::x_to_ts ( tick_t x ) const
|
||||||
{
|
{
|
||||||
return (x * PPQN) / _ppqn;
|
return (x * PPQN) / _ppqn;
|
||||||
|
|
||||||
// return x * (PPQN / _ppqn);
|
// return x * (PPQN / _ppqn);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline unsigned int
|
inline tick_t
|
||||||
Grid::ts_to_x ( tick_t ts ) const
|
Grid::ts_to_x ( tick_t ts ) const
|
||||||
{
|
{
|
||||||
return (ts * _ppqn) / PPQN;
|
return (ts * _ppqn) / PPQN;
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
all:
|
|
||||||
@ make -s -C ..
|
|
|
@ -1,105 +0,0 @@
|
||||||
|
|
||||||
/*******************************************************************************/
|
|
||||||
/* Copyright (C) 2007-2008 Jonathan Moore Liles */
|
|
||||||
/* */
|
|
||||||
/* 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 the file COPYING. If not,write to the Free Software */
|
|
||||||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|
||||||
/*******************************************************************************/
|
|
||||||
|
|
||||||
/* This file contains ALL platform specific drawing code required by the canvas */
|
|
||||||
|
|
||||||
#include "ui.H"
|
|
||||||
#include "draw.H"
|
|
||||||
|
|
||||||
#include "../common.h"
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#include "../canvas.H"
|
|
||||||
|
|
||||||
struct color_table {
|
|
||||||
int state;
|
|
||||||
unsigned char r, g, b;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct color_table color_defs[] = {
|
|
||||||
{ EMPTY, 18, 18, 18 },
|
|
||||||
{ FULL, 255, 69, 0 },
|
|
||||||
{ PARTIAL, 0, 0, 0 },
|
|
||||||
{ CONTINUED, 80, 80, 80 },
|
|
||||||
{ LINE, 10, 10, 10 },
|
|
||||||
{ HIT, 255, 255, 255 },
|
|
||||||
{ PLAYHEAD, 10, 69, 10 },
|
|
||||||
{ SELECTED, 255, 10, 255 },
|
|
||||||
};
|
|
||||||
|
|
||||||
Fl_Color *state_colors;
|
|
||||||
|
|
||||||
Fl_Color velocity_colors[128];
|
|
||||||
Fl_Color velocity2_colors[128];
|
|
||||||
|
|
||||||
bool draw_borders = 1;
|
|
||||||
|
|
||||||
void
|
|
||||||
init_colors ( void )
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
/* velocity colors */
|
|
||||||
|
|
||||||
for ( i = 128; i--; )
|
|
||||||
{
|
|
||||||
// velocity_colors[i] = fl_color_average( FL_GRAY, fl_rgb_color( i * 2, 255 - i * 2, 32 ), 0.4 );
|
|
||||||
// velocity_colors[i] = fl_rgb_color( i * 2, 0, 0 );
|
|
||||||
velocity_colors[i] = fl_rgb_color( i, 0, 0 );
|
|
||||||
velocity2_colors[i] = fl_color_average( FL_WHITE, velocity_colors[i], 0.5 );
|
|
||||||
}
|
|
||||||
|
|
||||||
state_colors = (Fl_Color*)malloc(sizeof( Fl_Color ) * MAX_STATE );
|
|
||||||
|
|
||||||
for ( i = elementsof( color_defs ); i--; )
|
|
||||||
{
|
|
||||||
state_colors[ color_defs[i].state ] = fl_rgb_color( color_defs[i].r,
|
|
||||||
color_defs[i].g,
|
|
||||||
color_defs[i].b );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern UI *ui;
|
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
clear_status ( void * )
|
|
||||||
{
|
|
||||||
ui->status->label( NULL );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** inform the user of something via a status bar */
|
|
||||||
void
|
|
||||||
gui_status ( const char *fmt, ... )
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
|
|
||||||
static char pat[256];
|
|
||||||
|
|
||||||
if ( fmt )
|
|
||||||
{
|
|
||||||
va_start( args, fmt );
|
|
||||||
vsnprintf( pat, 256, fmt, args );
|
|
||||||
va_end( args );
|
|
||||||
}
|
|
||||||
|
|
||||||
ui->status->label( pat );
|
|
||||||
|
|
||||||
Fl::add_timeout( 5.0f, clear_status );
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
/* canvas node states */
|
|
||||||
enum {
|
|
||||||
/* real */
|
|
||||||
EMPTY, /* nothing */
|
|
||||||
FULL, /* dot or dash head */
|
|
||||||
PARTIAL,
|
|
||||||
CONTINUED, /* dash tail */
|
|
||||||
SELECTED,
|
|
||||||
/* virtual */
|
|
||||||
HIT, /* playhead hit */
|
|
||||||
LINE, /* beat line */
|
|
||||||
PLAYHEAD,
|
|
||||||
MAX_STATE,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define MAX_REAL_STATE HIT
|
|
||||||
|
|
||||||
#define STATE_MASK 0x0F
|
|
||||||
#define STATE_FLAG_MASK (~ (STATE_MASK) )
|
|
||||||
|
|
||||||
/* flags */
|
|
||||||
enum {
|
|
||||||
F_PLAYHEAD = 1 << 0, /* playhead is on item */
|
|
||||||
F_P1 = 1 << 1,
|
|
||||||
F_P2 = 1 << 2,
|
|
||||||
F_SELECTION = 1 << 3 /* item is part of the selection box */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void init_colors ( void );
|
|
||||||
void gui_status ( const char *fmt, ... );
|
|
|
@ -28,6 +28,15 @@ decl {\#include "../grid.H"} {private local
|
||||||
decl {\#include "../scale.H"} {private local
|
decl {\#include "../scale.H"} {private local
|
||||||
}
|
}
|
||||||
|
|
||||||
|
decl {\#include <MIDI/event.H>} {public global
|
||||||
|
}
|
||||||
|
|
||||||
|
decl {\#include <MIDI/event_list.H>} {selected public global
|
||||||
|
}
|
||||||
|
|
||||||
|
decl {using namespace MIDI;} {private local
|
||||||
|
}
|
||||||
|
|
||||||
decl {extern Fl_Color velocity_colors[];} {private local
|
decl {extern Fl_Color velocity_colors[];} {private local
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,9 +49,9 @@ class Event_Editor {open
|
||||||
}
|
}
|
||||||
decl {Grid *_grid;} {private local
|
decl {Grid *_grid;} {private local
|
||||||
}
|
}
|
||||||
decl {event_list *_old;} {private local
|
decl {MIDI::event_list *_old;} {private local
|
||||||
}
|
}
|
||||||
decl {event_list *_el;} {private local
|
decl {MIDI::event_list *_el;} {private local
|
||||||
}
|
}
|
||||||
decl {int _y;} {private local
|
decl {int _y;} {private local
|
||||||
}
|
}
|
||||||
|
@ -61,10 +70,9 @@ _el = _old = NULL;
|
||||||
o->hide();
|
o->hide();
|
||||||
|
|
||||||
Fl::delete_widget( o );} open
|
Fl::delete_widget( o );} open
|
||||||
xywh {966 99 655 805} type Double resizable
|
xywh {968 122 655 805} type Double resizable
|
||||||
code0 {\#include "event_edit.H"}
|
code0 {\#include "event_edit.H"}
|
||||||
code1 {\#include "../grid.H"}
|
code1 {\#include "../grid.H"} modal size_range {0 0 659 803} visible
|
||||||
code2 {\#include "../event_list.H"} modal size_range {0 0 659 803} visible
|
|
||||||
} {
|
} {
|
||||||
Fl_Scroll {} {
|
Fl_Scroll {} {
|
||||||
label {Event List} open
|
label {Event List} open
|
||||||
|
@ -192,7 +200,7 @@ update_widgets();} {}
|
||||||
code {int i = 0;
|
code {int i = 0;
|
||||||
if ( ! _el->empty() )
|
if ( ! _el->empty() )
|
||||||
|
|
||||||
for ( event* e = (*_el)[0]; e = e->next(); i++ )
|
for ( event* e = (*_el)[0]; ( e = e->next() ); i++ )
|
||||||
{
|
{
|
||||||
Event_Widget *ew;
|
Event_Widget *ew;
|
||||||
|
|
||||||
|
@ -253,9 +261,8 @@ while( w->shown() )
|
||||||
}
|
}
|
||||||
|
|
||||||
widget_class Event_Widget {user_data_type {void *} open
|
widget_class Event_Widget {user_data_type {void *} open
|
||||||
xywh {943 216 590 30} type Single
|
xywh {945 239 590 30} type Single
|
||||||
code0 {\#include "../event.H"}
|
code0 {_event = NULL;}
|
||||||
code1 {_event = NULL;}
|
|
||||||
class Fl_Group size_range {400 24 0 24} visible
|
class Fl_Group size_range {400 24 0 24} visible
|
||||||
} {
|
} {
|
||||||
decl {static const Fl_Color note_color = FL_BLACK;} {private local
|
decl {static const Fl_Color note_color = FL_BLACK;} {private local
|
||||||
|
@ -270,11 +277,11 @@ widget_class Event_Widget {user_data_type {void *} open
|
||||||
}
|
}
|
||||||
decl {static const Fl_Color pitch_color = FL_GREEN} {private local
|
decl {static const Fl_Color pitch_color = FL_GREEN} {private local
|
||||||
}
|
}
|
||||||
decl {event *_event;} {private local
|
decl {MIDI::event *_event;} {private local
|
||||||
}
|
}
|
||||||
decl {Fl_Group *tab;} {private local
|
decl {Fl_Group *tab;} {private local
|
||||||
}
|
}
|
||||||
Function {ev( event * e )} {open return_type void
|
Function {ev( MIDI::event * e )} {open return_type void
|
||||||
} {
|
} {
|
||||||
code {if ( e && ( _event == NULL ) )
|
code {if ( e && ( _event == NULL ) )
|
||||||
activate();
|
activate();
|
||||||
|
@ -374,7 +381,7 @@ name->redraw();
|
||||||
|
|
||||||
// redraw();} {}
|
// redraw();} {}
|
||||||
}
|
}
|
||||||
Function {ev( void )} {open return_type {event *}
|
Function {ev( void )} {open return_type {MIDI::event *}
|
||||||
} {
|
} {
|
||||||
code {return _event;} {}
|
code {return _event;} {}
|
||||||
}
|
}
|
||||||
|
@ -491,7 +498,7 @@ do_callback();}
|
||||||
Fl_Slider {} {
|
Fl_Slider {} {
|
||||||
label {Pressure:}
|
label {Pressure:}
|
||||||
user_data this
|
user_data this
|
||||||
callback cb_lsb selected
|
callback cb_lsb
|
||||||
xywh {359 0 230 24} type {Horz Fill} align 4 when 4 maximum 127 step 1
|
xywh {359 0 230 24} type {Horz Fill} align 4 when 4 maximum 127 step 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,347 +0,0 @@
|
||||||
|
|
||||||
/*******************************************************************************/
|
|
||||||
/* Copyright (C) 2007-2008 Jonathan Moore Liles */
|
|
||||||
/* */
|
|
||||||
/* 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 the file COPYING. If not,write to the Free Software */
|
|
||||||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|
||||||
/*******************************************************************************/
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
/* system */
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "../non.H"
|
|
||||||
#include "draw.H"
|
|
||||||
#include "../common.h"
|
|
||||||
|
|
||||||
#include "ui.H"
|
|
||||||
#include "../transport.H"
|
|
||||||
|
|
||||||
extern UI *ui;
|
|
||||||
|
|
||||||
void
|
|
||||||
async_exec ( const char *cmd )
|
|
||||||
{
|
|
||||||
if ( fork() )
|
|
||||||
{
|
|
||||||
printf( "Executed command \"%s\"\n", cmd );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
system( cmd );
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
canvas_input_callback ( O_Canvas *widget, Canvas *c, int m )
|
|
||||||
{
|
|
||||||
// MESSAGE( "Hello, my name is %s", widget->parent()->label() );
|
|
||||||
|
|
||||||
int ow, oh;
|
|
||||||
|
|
||||||
int x, y;
|
|
||||||
int processed = 1;
|
|
||||||
|
|
||||||
x = Fl::event_x();
|
|
||||||
y = Fl::event_y();
|
|
||||||
|
|
||||||
|
|
||||||
ow = c->grid()->viewport.w;
|
|
||||||
oh = c->grid()->viewport.h;
|
|
||||||
|
|
||||||
switch ( m )
|
|
||||||
{
|
|
||||||
case FL_KEYBOARD:
|
|
||||||
{
|
|
||||||
|
|
||||||
/* if ( Fl::event_state() & FL_ALT || Fl::event_state() & FL_CTRL ) */
|
|
||||||
/* // this is more than a simple keypress. */
|
|
||||||
/* return 0; */
|
|
||||||
|
|
||||||
|
|
||||||
if ( Fl::event_state() & FL_CTRL )
|
|
||||||
{
|
|
||||||
switch ( Fl::event_key() )
|
|
||||||
{
|
|
||||||
case FL_Delete:
|
|
||||||
c->delete_time();
|
|
||||||
break;
|
|
||||||
case FL_Insert:
|
|
||||||
c->insert_time();
|
|
||||||
break;
|
|
||||||
case FL_Right:
|
|
||||||
c->pan( TO_NEXT_NOTE, 0 );
|
|
||||||
break;
|
|
||||||
case FL_Left:
|
|
||||||
c->pan( TO_PREV_NOTE, 0 );
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if ( Fl::event_state() & FL_ALT )
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
switch ( Fl::event_key() )
|
|
||||||
{
|
|
||||||
case FL_Left:
|
|
||||||
c->pan( LEFT, 1 );
|
|
||||||
break;
|
|
||||||
case FL_Right:
|
|
||||||
c->pan( RIGHT, 1 );
|
|
||||||
break;
|
|
||||||
case FL_Up:
|
|
||||||
c->pan( UP, 1 );
|
|
||||||
break;
|
|
||||||
case FL_Down:
|
|
||||||
c->pan( DOWN, 1 );
|
|
||||||
break;
|
|
||||||
case FL_Delete:
|
|
||||||
if ( Fl::event_state() & FL_SHIFT )
|
|
||||||
c->grid()->clear();
|
|
||||||
else
|
|
||||||
c->grid()->delete_selected();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* have to do this to get shifted keys */
|
|
||||||
switch ( *Fl::event_text() )
|
|
||||||
{
|
|
||||||
case 'f':
|
|
||||||
c->pan( TO_PLAYHEAD, 0 );
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
c->select_range();
|
|
||||||
break;
|
|
||||||
case 'q':
|
|
||||||
c->grid()->select_none();
|
|
||||||
break;
|
|
||||||
case 'i':
|
|
||||||
c->invert_selection();
|
|
||||||
break;
|
|
||||||
case '1':
|
|
||||||
c->h_zoom( 2.0f );
|
|
||||||
break;
|
|
||||||
case '2':
|
|
||||||
c->h_zoom( 0.5f );
|
|
||||||
break;
|
|
||||||
case '3':
|
|
||||||
c->v_zoom( 2.0f );
|
|
||||||
break;
|
|
||||||
case '4':
|
|
||||||
c->v_zoom( 0.5f );
|
|
||||||
break;
|
|
||||||
case ' ':
|
|
||||||
transport.toggle();
|
|
||||||
break;
|
|
||||||
case '[':
|
|
||||||
{
|
|
||||||
Grid *g = NULL;
|
|
||||||
|
|
||||||
#define IS_PATTERN (widget->parent() == ui->pattern_tab)
|
|
||||||
#define IS_PHRASE (widget->parent() == ui->phrase_tab)
|
|
||||||
#define IS_SEQUENCE (widget->parent() == ui->sequence_tab)
|
|
||||||
|
|
||||||
/* is there no nicer way to do this shit in c++? */
|
|
||||||
g = c->grid()->by_number( c->grid()->number() - 1 );
|
|
||||||
|
|
||||||
if ( g )
|
|
||||||
{
|
|
||||||
c->grid( g );
|
|
||||||
processed = 2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ']':
|
|
||||||
{
|
|
||||||
Grid *g = NULL;
|
|
||||||
|
|
||||||
/* is there no nicer way to do this shit in c++? */
|
|
||||||
g = c->grid()->by_number( c->grid()->number() + 1 );
|
|
||||||
|
|
||||||
if ( g )
|
|
||||||
{
|
|
||||||
c->grid( g );
|
|
||||||
processed = 2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case '<':
|
|
||||||
c->move_selected( LEFT, 1 );
|
|
||||||
break;
|
|
||||||
case '>':
|
|
||||||
c->move_selected( RIGHT, 1 );
|
|
||||||
break;
|
|
||||||
case ',':
|
|
||||||
c->move_selected( UP, 1 );
|
|
||||||
break;
|
|
||||||
case '.':
|
|
||||||
c->move_selected( DOWN, 1 );
|
|
||||||
break;
|
|
||||||
case 'C':
|
|
||||||
c->crop();
|
|
||||||
break;
|
|
||||||
case 'c':
|
|
||||||
{
|
|
||||||
Grid *g = c->grid()->create();
|
|
||||||
|
|
||||||
if ( g )
|
|
||||||
{
|
|
||||||
c->grid( g );
|
|
||||||
|
|
||||||
ui->update_sequence_widgets();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'd':
|
|
||||||
{
|
|
||||||
MESSAGE( "duplicating thing" );
|
|
||||||
c->grid( c->grid()->clone() );
|
|
||||||
|
|
||||||
// number of phrases may have changed.
|
|
||||||
ui->update_sequence_widgets();
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
case 'D':
|
|
||||||
c->duplicate_range();
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
c->grid()->trim();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'm':
|
|
||||||
c->grid()->mode( c->grid()->mode() == MUTE ? PLAY : MUTE );
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
c->grid()->mode( c->grid()->mode() == SOLO ? PLAY : SOLO );
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
processed = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FL_PUSH:
|
|
||||||
{
|
|
||||||
switch ( Fl::event_button() )
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
int note;
|
|
||||||
if ( ( note = c->is_row_name( x, y ) ) >= 0 )
|
|
||||||
{
|
|
||||||
DMESSAGE( "click on row %d", note );
|
|
||||||
Instrument *i = ((pattern *)c->grid())->mapping.instrument();
|
|
||||||
|
|
||||||
if ( i )
|
|
||||||
{
|
|
||||||
ui->edit_instrument_row( i, note );
|
|
||||||
|
|
||||||
c->changed_mapping();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ( Fl::event_state() & FL_SHIFT )
|
|
||||||
{
|
|
||||||
c->start_cursor( x, y );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( IS_PATTERN && Fl::event_state() & ( FL_ALT | FL_CTRL ) )
|
|
||||||
c->randomize_row( y );
|
|
||||||
else
|
|
||||||
c->set( x, y );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
if ( Fl::event_state() & FL_SHIFT )
|
|
||||||
{
|
|
||||||
c->end_cursor( x, y );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
c->unset( x, y );
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
c->select( x, y );
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
processed = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FL_RELEASE:
|
|
||||||
break;
|
|
||||||
case FL_DRAG:
|
|
||||||
break;
|
|
||||||
/* case FL_DRAG: */
|
|
||||||
/* { */
|
|
||||||
/* if ( ! lmb_down ) */
|
|
||||||
/* break; */
|
|
||||||
|
|
||||||
/* // c->grid()->move( x, y, nx ); */
|
|
||||||
/* break; */
|
|
||||||
/* } */
|
|
||||||
case FL_MOUSEWHEEL:
|
|
||||||
{
|
|
||||||
if ( Fl::event_state() & FL_CTRL )
|
|
||||||
c->adj_length( x, y, (0 - Fl::event_dy()) );
|
|
||||||
else if ( Fl::event_state() & FL_ALT )
|
|
||||||
c->adj_color( x, y, (0 - Fl::event_dy()) * 5 );
|
|
||||||
else if ( Fl::event_state() & FL_SHIFT )
|
|
||||||
{
|
|
||||||
if ( Fl::event_dy() > 0 )
|
|
||||||
{
|
|
||||||
c->pan( RIGHT, Fl::event_dy() * 5 );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
c->pan( LEFT, 0 - Fl::event_dy() * 5 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ( Fl::event_dy() > 0 )
|
|
||||||
{
|
|
||||||
c->pan( DOWN, Fl::event_dy() * 1 );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
c->pan( UP, (0 - Fl::event_dy()) * 1 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
processed = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int nw, nh;
|
|
||||||
nw = c->grid()->viewport.w;
|
|
||||||
nh = c->grid()->viewport.h;
|
|
||||||
|
|
||||||
// layout of canvas changed... requires clearing.
|
|
||||||
if ( oh != nh || ow != nw )
|
|
||||||
return 3;
|
|
||||||
|
|
||||||
return processed;
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "../canvas.H"
|
|
||||||
#include "../common.h"
|
|
||||||
|
|
||||||
class O_Canvas;
|
|
||||||
|
|
||||||
void disp_message ( char *s );
|
|
||||||
void async_exec ( const char *cmd );
|
|
||||||
int canvas_input_callback ( O_Canvas *widget, Canvas *c, int m );
|
|
||||||
int disp_init ( int argc, char **argv );
|
|
File diff suppressed because it is too large
Load Diff
|
@ -33,8 +33,12 @@
|
||||||
|
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <MIDI/event.H>
|
||||||
|
using namespace MIDI;
|
||||||
|
|
||||||
using std::list;
|
using std::list;
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include <list>
|
#include <list>
|
||||||
using std::list;
|
using std::list;
|
||||||
|
|
||||||
#include "event.H"
|
#include <MIDI/midievent.H>
|
||||||
|
|
||||||
struct i_map {
|
struct i_map {
|
||||||
char *name;
|
char *name;
|
||||||
|
@ -55,7 +55,7 @@ public:
|
||||||
void note_name ( int n, char *s );
|
void note_name ( int n, char *s );
|
||||||
|
|
||||||
/* inspection */
|
/* inspection */
|
||||||
bool translate ( midievent *e ) const;
|
bool translate ( MIDI::midievent *e ) const;
|
||||||
const char * note_name ( int n ) const;
|
const char * note_name ( int n ) const;
|
||||||
int height ( void ) const;
|
int height ( void ) const;
|
||||||
const char * name ( void ) const;
|
const char * name ( void ) const;
|
||||||
|
|
|
@ -32,7 +32,10 @@
|
||||||
#include "transport.H"
|
#include "transport.H"
|
||||||
#include "pattern.H"
|
#include "pattern.H"
|
||||||
#include "phrase.H"
|
#include "phrase.H"
|
||||||
#include "event_list.H"
|
#include <MIDI/event_list.H>
|
||||||
|
#include <MIDI/midievent.H>
|
||||||
|
|
||||||
|
using namespace MIDI;
|
||||||
|
|
||||||
#ifdef JACK_MIDI_PROTO_API
|
#ifdef JACK_MIDI_PROTO_API
|
||||||
/* correct for prototype version of API */
|
/* correct for prototype version of API */
|
||||||
|
|
|
@ -1,18 +1,17 @@
|
||||||
|
|
||||||
#include <jack/jack.h>
|
#include <jack/jack.h>
|
||||||
|
#include <MIDI/midievent.H>
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
enum { CONTROL, PERFORMANCE };
|
enum { CONTROL, PERFORMANCE };
|
||||||
|
|
||||||
class midievent;
|
|
||||||
|
|
||||||
bool midi_input_event ( int port, midievent *e );
|
bool midi_input_event ( int port, MIDI::midievent *e );
|
||||||
bool midi_is_active ( void );
|
bool midi_is_active ( void );
|
||||||
midievent * midi_input_event ( int port );
|
MIDI::midievent * midi_input_event ( int port );
|
||||||
void midi_output_event ( int port, const midievent *e );
|
void midi_output_event ( int port, const MIDI::midievent *e );
|
||||||
void midi_output_event ( int port, const midievent *e, tick_t duration );
|
void midi_output_event ( int port, const MIDI::midievent *e, tick_t duration );
|
||||||
void midi_all_sound_off ( void );
|
void midi_all_sound_off ( void );
|
||||||
const char * midi_init ( const char *name );
|
const char * midi_init ( const char *name );
|
||||||
void midi_shutdown ( void );
|
void midi_shutdown ( void );
|
||||||
void midi_output_immediate_event ( int port, const midievent *e );
|
void midi_output_immediate_event ( int port, const MIDI::midievent *e );
|
||||||
|
|
|
@ -36,8 +36,6 @@
|
||||||
|
|
||||||
const double NSM_CHECK_INTERVAL = 0.25f;
|
const double NSM_CHECK_INTERVAL = 0.25f;
|
||||||
|
|
||||||
Canvas *pattern_c, *phrase_c, *trigger_c;
|
|
||||||
|
|
||||||
sequence *playlist;
|
sequence *playlist;
|
||||||
|
|
||||||
global_settings config;
|
global_settings config;
|
||||||
|
@ -59,10 +57,6 @@ quit ( void )
|
||||||
|
|
||||||
delete ui;
|
delete ui;
|
||||||
|
|
||||||
delete pattern_c;
|
|
||||||
delete phrase_c;
|
|
||||||
delete trigger_c;
|
|
||||||
|
|
||||||
midi_all_sound_off();
|
midi_all_sound_off();
|
||||||
|
|
||||||
// wait for it...
|
// wait for it...
|
||||||
|
@ -81,13 +75,14 @@ clear_song ( void )
|
||||||
{
|
{
|
||||||
// song.filename = NULL;
|
// song.filename = NULL;
|
||||||
|
|
||||||
pattern_c->grid( NULL );
|
ui->pattern_canvas_widget->grid( NULL );
|
||||||
phrase_c->grid( NULL );
|
ui->phrase_canvas_widget->grid( NULL );
|
||||||
|
|
||||||
playlist->reset();
|
playlist->reset();
|
||||||
playlist->insert( 0, 1 );
|
playlist->insert( 0, 1 );
|
||||||
pattern_c->grid( new pattern );
|
|
||||||
phrase_c->grid( new phrase );
|
ui->pattern_canvas_widget->grid( new pattern );
|
||||||
|
ui->phrase_canvas_widget->grid( new phrase );
|
||||||
|
|
||||||
song.dirty( false );
|
song.dirty( false );
|
||||||
}
|
}
|
||||||
|
@ -125,11 +120,11 @@ load_song ( const char *name )
|
||||||
|
|
||||||
MESSAGE( "loading song \"%s\"", name );
|
MESSAGE( "loading song \"%s\"", name );
|
||||||
|
|
||||||
Grid *pattern_grid = pattern_c->grid();
|
Grid *pattern_grid = ui->pattern_canvas_widget->grid();
|
||||||
Grid *phrase_grid = phrase_c->grid();
|
Grid *phrase_grid = ui->phrase_canvas_widget->grid();
|
||||||
|
|
||||||
pattern_c->grid( NULL );
|
ui->pattern_canvas_widget->grid( NULL );
|
||||||
phrase_c->grid( NULL );
|
ui->phrase_canvas_widget->grid( NULL );
|
||||||
|
|
||||||
if ( ! playlist->load( name ) )
|
if ( ! playlist->load( name ) )
|
||||||
{
|
{
|
||||||
|
@ -137,8 +132,8 @@ load_song ( const char *name )
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
pattern_c->grid( pattern::pattern_by_number( 1 ) );
|
ui->pattern_canvas_widget->grid( pattern::pattern_by_number( 1 ) );
|
||||||
phrase_c->grid( phrase::phrase_by_number( 1 ) );
|
ui->phrase_canvas_widget->grid( phrase::phrase_by_number( 1 ) );
|
||||||
|
|
||||||
song.filename = strdup( name );
|
song.filename = strdup( name );
|
||||||
|
|
||||||
|
@ -148,8 +143,8 @@ load_song ( const char *name )
|
||||||
|
|
||||||
failed:
|
failed:
|
||||||
|
|
||||||
pattern_c->grid( pattern_grid );
|
ui->pattern_canvas_widget->grid( pattern_grid );
|
||||||
phrase_c->grid( phrase_grid );
|
ui->phrase_canvas_widget->grid( phrase_grid );
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -237,26 +232,23 @@ main ( int argc, char **argv )
|
||||||
|
|
||||||
playlist = new sequence;
|
playlist = new sequence;
|
||||||
|
|
||||||
pattern_c = new Canvas(0,0,1,1);
|
|
||||||
phrase_c = new Canvas(0,0,1,1);
|
|
||||||
trigger_c = new Canvas(0,0,1,1);
|
|
||||||
|
|
||||||
nsm = new NSM_Client;
|
nsm = new NSM_Client;
|
||||||
|
|
||||||
song.filename = NULL;
|
song.filename = NULL;
|
||||||
clear_song();
|
|
||||||
|
|
||||||
pattern::signal_create_destroy.connect( mem_fun( phrase_c, &Canvas::v_zoom_fit ) );
|
|
||||||
pattern::signal_create_destroy.connect( mem_fun( song, &song_settings::set_dirty ) );
|
|
||||||
phrase::signal_create_destroy.connect( mem_fun( song, &song_settings::set_dirty ) );
|
|
||||||
|
|
||||||
//
|
|
||||||
song.dirty( false );
|
|
||||||
|
|
||||||
init_colors();
|
|
||||||
|
|
||||||
ui = new UI;
|
ui = new UI;
|
||||||
|
|
||||||
|
pattern::signal_create_destroy.connect( mem_fun( ui->phrase_canvas_widget, &Canvas::v_zoom_fit ) );
|
||||||
|
pattern::signal_create_destroy.connect( mem_fun( song, &song_settings::set_dirty ) );
|
||||||
|
phrase::signal_create_destroy.connect( mem_fun( song, &song_settings::set_dirty ) );
|
||||||
|
|
||||||
|
song.dirty( false );
|
||||||
|
|
||||||
|
clear_song();
|
||||||
|
|
||||||
|
#ifdef HAVE_XPM
|
||||||
|
ui->main_window->icon((char *)p);
|
||||||
|
#endif
|
||||||
ui->main_window->show( 0, 0 );
|
ui->main_window->show( 0, 0 );
|
||||||
|
|
||||||
instance_name = strdup( APP_NAME );
|
instance_name = strdup( APP_NAME );
|
||||||
|
|
|
@ -20,7 +20,9 @@
|
||||||
#include "mapping.H"
|
#include "mapping.H"
|
||||||
#include "stdlib.h"
|
#include "stdlib.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include <MIDI/midievent.H>
|
||||||
|
|
||||||
|
using namespace MIDI;
|
||||||
/* Is C++'s dispatching useless or what? */
|
/* Is C++'s dispatching useless or what? */
|
||||||
|
|
||||||
#define IS_INSTRUMENT ( _type == INSTRUMENT )
|
#define IS_INSTRUMENT ( _type == INSTRUMENT )
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include "scale.H"
|
#include "scale.H"
|
||||||
#include "instrument.H"
|
#include "instrument.H"
|
||||||
|
#include <MIDI/midievent.H>
|
||||||
|
|
||||||
/* C++'s inheritance system falls down dead for this application, so we
|
/* C++'s inheritance system falls down dead for this application, so we
|
||||||
have to do it backwards, using the base class (Mapping) as an interface
|
have to do it backwards, using the base class (Mapping) as an interface
|
||||||
|
@ -64,7 +65,7 @@ public:
|
||||||
void key ( int n );
|
void key ( int n );
|
||||||
|
|
||||||
/* inspection */
|
/* inspection */
|
||||||
bool translate ( midievent *e ) const;
|
bool translate ( MIDI::midievent *e ) const;
|
||||||
const char * note_name ( int n ) const;
|
const char * note_name ( int n ) const;
|
||||||
int velocity ( int n ) const;
|
int velocity ( int n ) const;
|
||||||
int key ( void ) const;
|
int key ( void ) const;
|
||||||
|
|
|
@ -1,218 +0,0 @@
|
||||||
|
|
||||||
/*******************************************************************************/
|
|
||||||
/* Copyright (C) 2008 Jonathan Moore Liles */
|
|
||||||
/* */
|
|
||||||
/* 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 the file COPYING. If not,write to the Free Software */
|
|
||||||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|
||||||
/*******************************************************************************/
|
|
||||||
|
|
||||||
/* raw MIDI events + timestamps. Some support for SysEx */
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "midievent.H"
|
|
||||||
|
|
||||||
static const char *opcode_names[] =
|
|
||||||
{
|
|
||||||
"Note Off",
|
|
||||||
"Note On",
|
|
||||||
"Aftertouch",
|
|
||||||
"Control Change",
|
|
||||||
"Program Change",
|
|
||||||
"Channel Pressure",
|
|
||||||
"Pitch Wheel"
|
|
||||||
};
|
|
||||||
|
|
||||||
midievent::midievent ( void )
|
|
||||||
{
|
|
||||||
_sysex = NULL;
|
|
||||||
_timestamp = 0;
|
|
||||||
_data.status = NOTE_OFF;
|
|
||||||
_data.msb = _data.lsb = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
midievent::~midievent ( void )
|
|
||||||
{
|
|
||||||
if ( _sysex )
|
|
||||||
delete _sysex;
|
|
||||||
|
|
||||||
_sysex = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
midievent::pitch ( void ) const
|
|
||||||
{
|
|
||||||
return ((_data.msb << 7) | _data.lsb) - 0x2000;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
midievent::pitch ( int n )
|
|
||||||
{
|
|
||||||
n += 0x2000;
|
|
||||||
|
|
||||||
_data.lsb = n & 0x7F;
|
|
||||||
_data.msb = (n >> 7) & 0x7F;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
midievent::data ( byte_t D1, byte_t D2 )
|
|
||||||
{
|
|
||||||
_data.lsb = D1 & 0x7F;
|
|
||||||
_data.msb = D2 & 0x7F;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
midievent::data ( byte_t *D1, byte_t *D2 ) const
|
|
||||||
{
|
|
||||||
*D1 = _data.lsb;
|
|
||||||
*D2 = _data.msb;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
midievent::raw ( byte_t *p, int l) const
|
|
||||||
{
|
|
||||||
memcpy( p, &_data, l );
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
midievent::size ( void ) const
|
|
||||||
{
|
|
||||||
return midievent::event_size( opcode() );
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
midievent::note_velocity ( int vel )
|
|
||||||
{
|
|
||||||
_data.msb = vel & 0x7F;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
midievent::note ( char note )
|
|
||||||
{
|
|
||||||
_data.lsb = note & 0x7F;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
unsigned char
|
|
||||||
midievent::note ( void ) const
|
|
||||||
{
|
|
||||||
return _data.lsb;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char
|
|
||||||
midievent::note_velocity ( void ) const
|
|
||||||
{
|
|
||||||
return _data.msb;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
midievent::is_same_note ( midievent * e ) const
|
|
||||||
{
|
|
||||||
return channel() == e->channel() && note() == e->note();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** get name from opcode */
|
|
||||||
const char *
|
|
||||||
midievent::name ( void ) const
|
|
||||||
{
|
|
||||||
return opcode_names[ (opcode() >> 4) - 8 ];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** get opcode from name */
|
|
||||||
int
|
|
||||||
midievent::name ( const char *name ) const
|
|
||||||
{
|
|
||||||
for ( unsigned int i = elementsof( opcode_names ); i--; )
|
|
||||||
if ( ! strcmp( name, opcode_names[ i ] ) )
|
|
||||||
return (i + 8) << 4;
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** print event in hexadecimal */
|
|
||||||
void
|
|
||||||
midievent::print ( void ) const
|
|
||||||
{
|
|
||||||
printf( "[%06ld] %02X %02X %02X\n",
|
|
||||||
_timestamp,
|
|
||||||
_data.status,
|
|
||||||
_data.lsb,
|
|
||||||
_data.msb );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** print event in english/decimal */
|
|
||||||
void
|
|
||||||
midievent::pretty_print ( void ) const
|
|
||||||
{
|
|
||||||
printf(
|
|
||||||
"[%06ld] %-15s c: %2d d1: %3d d2: %3d\n",
|
|
||||||
_timestamp,
|
|
||||||
name(),
|
|
||||||
channel(),
|
|
||||||
_data.lsb,
|
|
||||||
_data.msb );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*********/
|
|
||||||
/* Sysex */
|
|
||||||
/*********/
|
|
||||||
|
|
||||||
midievent::sysex::sysex ( void )
|
|
||||||
{
|
|
||||||
_data = NULL;
|
|
||||||
_size = 0;
|
|
||||||
_alloc = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
midievent::sysex::~sysex ( void )
|
|
||||||
{
|
|
||||||
if ( _data )
|
|
||||||
free( _data );
|
|
||||||
|
|
||||||
_data = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** add bytes to sysex message */
|
|
||||||
void
|
|
||||||
midievent::sysex::append ( byte_t *data, size_t size )
|
|
||||||
{
|
|
||||||
if ( _size + size > _alloc )
|
|
||||||
_data = (byte_t *)realloc( _data, _alloc += 256 );
|
|
||||||
|
|
||||||
memcpy( data + _size, data, size );
|
|
||||||
|
|
||||||
_size += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** return SysEx data */
|
|
||||||
const byte_t *
|
|
||||||
midievent::sysex::data ( void ) const
|
|
||||||
{
|
|
||||||
return _data;
|
|
||||||
}
|
|
||||||
|
|
||||||
long
|
|
||||||
midievent::sysex::size ( void ) const
|
|
||||||
{
|
|
||||||
return _size;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
midievent::operator== ( const midievent &rhs ) const
|
|
||||||
{
|
|
||||||
return _timestamp == rhs._timestamp &&
|
|
||||||
! bcmp( (void*)&_data, (void*)&rhs._data, size() );
|
|
||||||
}
|
|
|
@ -1,232 +0,0 @@
|
||||||
|
|
||||||
/*******************************************************************************/
|
|
||||||
/* Copyright (C) 2008 Jonathan Moore Liles */
|
|
||||||
/* */
|
|
||||||
/* 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 the file COPYING. If not,write to the Free Software */
|
|
||||||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|
||||||
/*******************************************************************************/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* raw MIDI event + timestamp */
|
|
||||||
class midievent
|
|
||||||
{
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
class sysex {
|
|
||||||
size_t _size, _alloc;
|
|
||||||
byte_t *_data;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
sysex ( void );
|
|
||||||
~sysex ( void );
|
|
||||||
|
|
||||||
void append ( byte_t *data, size_t size );
|
|
||||||
const byte_t * data ( void ) const;
|
|
||||||
long size ( void ) const;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
sysex *_sysex;
|
|
||||||
|
|
||||||
tick_t _timestamp; /* in ticks */
|
|
||||||
struct {
|
|
||||||
byte_t status, /* full status byte */
|
|
||||||
lsb, /* data 1 */
|
|
||||||
msb; /* data 2 */
|
|
||||||
} _data;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
event_size ( byte_t op )
|
|
||||||
{
|
|
||||||
switch ( op )
|
|
||||||
{
|
|
||||||
case NOTE_ON: case NOTE_OFF: case AFTERTOUCH:
|
|
||||||
case CONTROL_CHANGE: case PITCH_WHEEL:
|
|
||||||
return 3;
|
|
||||||
case PROGRAM_CHANGE: case CHANNEL_PRESSURE:
|
|
||||||
return 2;
|
|
||||||
default:
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* define MIDI status bytes */
|
|
||||||
enum {
|
|
||||||
STATUS_BIT = 0x80,
|
|
||||||
NOTE_OFF = 0x80,
|
|
||||||
NOTE_ON = 0x90,
|
|
||||||
AFTERTOUCH = 0xA0,
|
|
||||||
CONTROL_CHANGE = 0xB0,
|
|
||||||
PROGRAM_CHANGE = 0xC0,
|
|
||||||
CHANNEL_PRESSURE = 0xD0,
|
|
||||||
PITCH_WHEEL = 0xE0,
|
|
||||||
CLEAR_CHAN_MASK = 0xF0,
|
|
||||||
MIDI_CLOCK = 0xF8,
|
|
||||||
SYSEX = 0xF0,
|
|
||||||
SYSEX_END = 0xF7,
|
|
||||||
META = 0xFF
|
|
||||||
};
|
|
||||||
|
|
||||||
midievent ( void );
|
|
||||||
virtual ~midievent ( void );
|
|
||||||
|
|
||||||
tick_t timestamp ( void ) const;
|
|
||||||
void timestamp ( tick_t time );
|
|
||||||
void status ( byte_t status );
|
|
||||||
byte_t status ( void ) const;
|
|
||||||
void channel ( byte_t channel );
|
|
||||||
byte_t channel ( void ) const;
|
|
||||||
byte_t opcode ( void ) const;
|
|
||||||
void opcode ( byte_t o );
|
|
||||||
void lsb ( byte_t n );
|
|
||||||
void msb ( byte_t n );
|
|
||||||
int lsb ( void ) const;
|
|
||||||
int msb ( void ) const;
|
|
||||||
int pitch ( void ) const;
|
|
||||||
void pitch ( int n );
|
|
||||||
void data ( byte_t D1, byte_t D2 );
|
|
||||||
void data ( byte_t *D1, byte_t *D2 ) const;
|
|
||||||
void raw ( byte_t *p, int l) const;
|
|
||||||
int size ( void ) const;
|
|
||||||
void note_velocity ( int vel );
|
|
||||||
bool is_note_on ( void ) const;
|
|
||||||
bool is_note_off ( void ) const;
|
|
||||||
virtual unsigned char note ( void ) const;
|
|
||||||
virtual void note ( char note );
|
|
||||||
unsigned char note_velocity ( void ) const;
|
|
||||||
bool is_same_note ( midievent * e ) const;
|
|
||||||
const char * name ( void ) const;
|
|
||||||
int name ( const char *name ) const;
|
|
||||||
void print ( void ) const;
|
|
||||||
void pretty_print ( void ) const;
|
|
||||||
|
|
||||||
bool operator< ( const midievent &rhs ) const;
|
|
||||||
bool operator>= ( const midievent &rhs ) const;
|
|
||||||
|
|
||||||
bool operator== ( const midievent &rhs ) const;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**********************/
|
|
||||||
/* Inlined accessors */
|
|
||||||
/**********************/
|
|
||||||
|
|
||||||
|
|
||||||
inline tick_t
|
|
||||||
midievent::timestamp ( void ) const
|
|
||||||
{
|
|
||||||
return _timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
midievent::timestamp ( tick_t time )
|
|
||||||
{
|
|
||||||
_timestamp = time;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
midievent::status ( byte_t status )
|
|
||||||
{
|
|
||||||
_data.status = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline byte_t
|
|
||||||
midievent::status ( void ) const
|
|
||||||
{
|
|
||||||
return _data.status;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
midievent::channel ( byte_t channel )
|
|
||||||
{
|
|
||||||
_data.status = (_data.status & 0xF0) | (channel & 0x0F);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline byte_t
|
|
||||||
midievent::channel ( void ) const
|
|
||||||
{
|
|
||||||
return _data.status & 0x0F;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline byte_t
|
|
||||||
midievent::opcode ( void ) const
|
|
||||||
{
|
|
||||||
return _data.status & 0xF0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void
|
|
||||||
midievent::opcode ( byte_t opcode )
|
|
||||||
{
|
|
||||||
_data.status = (_data.status & 0x0F) | (opcode & 0xF0);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
midievent::lsb ( byte_t n )
|
|
||||||
{
|
|
||||||
_data.lsb = n & 0x7F;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
midievent::msb ( byte_t n )
|
|
||||||
{
|
|
||||||
_data.msb = n & 0x7F;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int
|
|
||||||
midievent::lsb ( void ) const
|
|
||||||
{
|
|
||||||
return _data.lsb;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int
|
|
||||||
midievent::msb ( void ) const
|
|
||||||
{
|
|
||||||
return _data.msb;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool
|
|
||||||
midievent::is_note_on ( void ) const
|
|
||||||
{
|
|
||||||
return (opcode() == NOTE_ON);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool
|
|
||||||
midievent::is_note_off ( void ) const
|
|
||||||
{
|
|
||||||
return (opcode() == NOTE_OFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool
|
|
||||||
midievent::operator< ( const midievent &rhs ) const
|
|
||||||
{
|
|
||||||
return _timestamp < rhs._timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool
|
|
||||||
midievent::operator>= ( const midievent &rhs ) const
|
|
||||||
{
|
|
||||||
return _timestamp >= rhs._timestamp;
|
|
||||||
}
|
|
|
@ -26,6 +26,9 @@
|
||||||
#include "transport.H"
|
#include "transport.H"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <MIDI/event_list.H>
|
||||||
|
using namespace MIDI;
|
||||||
|
|
||||||
event_list pattern::_recorded_events;
|
event_list pattern::_recorded_events;
|
||||||
vector <pattern*> pattern::_patterns;
|
vector <pattern*> pattern::_patterns;
|
||||||
int pattern::_solo;
|
int pattern::_solo;
|
||||||
|
@ -276,10 +279,26 @@ pattern::by_number ( int n ) const
|
||||||
return pattern::pattern_by_number( n );
|
return pattern::pattern_by_number( n );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** what to do when the row name is pressed */
|
||||||
|
void
|
||||||
|
pattern::row_name_press ( int y )
|
||||||
|
{
|
||||||
|
/* echo note */
|
||||||
|
midievent e;
|
||||||
|
|
||||||
|
e.status( event::NOTE_ON );
|
||||||
|
e.channel( _channel );
|
||||||
|
e.timestamp( default_length() );
|
||||||
|
e.note( y );
|
||||||
|
e.note_velocity( 64 );
|
||||||
|
|
||||||
|
midi_output_immediate_event ( _port, &e );
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pattern::put ( int x, int y, tick_t l )
|
pattern::put ( int x, int y, tick_t l )
|
||||||
{
|
{
|
||||||
l = l ? l : PPQN * 4 / _note;
|
l = l ? l : default_length();
|
||||||
|
|
||||||
Grid::put( x, y, l );
|
Grid::put( x, y, l );
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
#include "grid.H"
|
#include "grid.H"
|
||||||
#include "canvas.H"
|
#include "canvas.H"
|
||||||
#include "mapping.H"
|
#include "mapping.H"
|
||||||
// #include "event.H"
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -30,7 +29,7 @@ using std::vector;
|
||||||
|
|
||||||
class pattern : public Grid
|
class pattern : public Grid
|
||||||
{
|
{
|
||||||
static event_list _recorded_events;
|
static MIDI::event_list _recorded_events;
|
||||||
static vector <pattern *> _patterns;
|
static vector <pattern *> _patterns;
|
||||||
static int _solo;
|
static int _solo;
|
||||||
static int _pattern_recording;
|
static int _pattern_recording;
|
||||||
|
@ -68,7 +67,7 @@ public:
|
||||||
static pattern * import ( smf *f, int track );
|
static pattern * import ( smf *f, int track );
|
||||||
|
|
||||||
static pattern * recording ( void );
|
static pattern * recording ( void );
|
||||||
static void record_event ( const midievent *e );
|
static void record_event ( const MIDI::midievent *e );
|
||||||
|
|
||||||
pattern * create ( void );
|
pattern * create ( void );
|
||||||
pattern * by_number ( int n ) const;
|
pattern * by_number ( int n ) const;
|
||||||
|
@ -91,6 +90,7 @@ public:
|
||||||
int queue ( void ) const;
|
int queue ( void ) const;
|
||||||
|
|
||||||
void randomize_row ( int y, int feel, float probability );
|
void randomize_row ( int y, int feel, float probability );
|
||||||
|
void row_name_press ( int y );
|
||||||
|
|
||||||
int port ( void ) const;
|
int port ( void ) const;
|
||||||
void port ( int p );
|
void port ( int p );
|
||||||
|
@ -112,4 +112,9 @@ public:
|
||||||
int ppqn ( void ) const;
|
int ppqn ( void ) const;
|
||||||
void ppqn ( int n );
|
void ppqn ( int n );
|
||||||
|
|
||||||
|
virtual tick_t default_length ( void ) const
|
||||||
|
{
|
||||||
|
return PPQN * 4 / _note;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,12 +18,13 @@
|
||||||
/*******************************************************************************/
|
/*******************************************************************************/
|
||||||
|
|
||||||
#include "phrase.H"
|
#include "phrase.H"
|
||||||
#include "gui/draw.H"
|
|
||||||
#include "pattern.H"
|
#include "pattern.H"
|
||||||
#include "smf.H"
|
#include "smf.H"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
using namespace MIDI;
|
||||||
|
|
||||||
vector <phrase*> phrase::_phrases;
|
vector <phrase*> phrase::_phrases;
|
||||||
signal <void> phrase::signal_create_destroy;
|
signal <void> phrase::signal_create_destroy;
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,8 @@ public:
|
||||||
static phrase * phrase_by_number ( int n );
|
static phrase * phrase_by_number ( int n );
|
||||||
static void reset ( void );
|
static void reset ( void );
|
||||||
|
|
||||||
|
virtual bool velocity_sensitive ( void ) const { return false; }
|
||||||
|
|
||||||
phrase *create ( void );
|
phrase *create ( void );
|
||||||
phrase * by_number ( int n ) const;
|
phrase * by_number ( int n ) const;
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,9 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
#include "stdlib.h"
|
#include "stdlib.h"
|
||||||
|
#include <MIDI/midievent.H>
|
||||||
|
|
||||||
|
using namespace MIDI;
|
||||||
|
|
||||||
/* Define some scales. These don't really need to be stored on
|
/* Define some scales. These don't really need to be stored on
|
||||||
disk. Scales don't change that often. */
|
disk. Scales don't change that often. */
|
||||||
|
@ -189,13 +192,20 @@ const char *
|
||||||
Scale::note_name ( int k, int n ) const
|
Scale::note_name ( int k, int n ) const
|
||||||
{
|
{
|
||||||
/* all the magic is here */
|
/* all the magic is here */
|
||||||
|
static char s[5];
|
||||||
|
|
||||||
n %= 12;
|
const int mod_n = n % 12;
|
||||||
|
|
||||||
// FIXME: searching is not efficient!
|
// FIXME: searching is not efficient!
|
||||||
for ( int i = _notes; i-- ; )
|
for ( int i = _notes; i-- ; )
|
||||||
if ( n == (_degrees[ i ] + k) % 12 )
|
if ( mod_n == (_degrees[ i ] + k) % 12 )
|
||||||
return chromatic_names[ n ];
|
{
|
||||||
|
snprintf( s, sizeof(s), "%s%i",
|
||||||
|
chromatic_names[ mod_n ],
|
||||||
|
n / 12 );
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,7 @@
|
||||||
/*******************************************************************************/
|
/*******************************************************************************/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <MIDI/midievent.H>
|
||||||
#include "event.H"
|
|
||||||
|
|
||||||
class Scale
|
class Scale
|
||||||
{
|
{
|
||||||
|
@ -41,7 +40,7 @@ public:
|
||||||
static const char * chromatic_name ( int n );
|
static const char * chromatic_name ( int n );
|
||||||
static int octave ( int n );
|
static int octave ( int n );
|
||||||
|
|
||||||
bool translate ( int k, midievent *e ) const;
|
bool translate ( int k, MIDI::midievent *e ) const;
|
||||||
int note ( int k, int n ) const;
|
int note ( int k, int n ) const;
|
||||||
const char * note_name ( int k, int n ) const;
|
const char * note_name ( int k, int n ) const;
|
||||||
const char * name ( void ) const;
|
const char * name ( void ) const;
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "phrase.H"
|
#include "phrase.H"
|
||||||
#include "pattern.H"
|
#include "pattern.H"
|
||||||
|
|
||||||
|
using namespace MIDI;
|
||||||
|
|
||||||
smf::smf ( void )
|
smf::smf ( void )
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "grid.H"
|
#include "grid.H"
|
||||||
#include "event.H"
|
|
||||||
|
|
||||||
class pattern;
|
class pattern;
|
||||||
class phrase;
|
class phrase;
|
||||||
|
@ -104,7 +103,7 @@ public:
|
||||||
void write_meta_event ( byte_t type, int n );
|
void write_meta_event ( byte_t type, int n );
|
||||||
void write_meta_event ( byte_t type, const char *s );
|
void write_meta_event ( byte_t type, const char *s );
|
||||||
|
|
||||||
void write_event ( const midievent *e );
|
void write_event ( const MIDI::midievent *e );
|
||||||
void write_header ( int tracks );
|
void write_header ( int tracks );
|
||||||
|
|
||||||
void open_chunk ( const char *id );
|
void open_chunk ( const char *id );
|
||||||
|
@ -116,7 +115,7 @@ public:
|
||||||
|
|
||||||
void cue ( bool b );
|
void cue ( bool b );
|
||||||
|
|
||||||
list <midievent> * read_track_events ( tick_t *length );
|
list <MIDI::midievent> * read_track_events ( tick_t *length );
|
||||||
|
|
||||||
void write_phrase_info ( const phrase *p );
|
void write_phrase_info ( const phrase *p );
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
using namespace sigc;
|
using namespace sigc;
|
||||||
|
|
||||||
#include "event.H" // just for tick_t
|
#include <MIDI/types.h> // just for tick_t
|
||||||
|
|
||||||
#include <jack/transport.h>
|
#include <jack/transport.h>
|
||||||
|
|
||||||
|
|
|
@ -46,18 +46,13 @@ src/NSM.C
|
||||||
src/NSM/Client.C
|
src/NSM/Client.C
|
||||||
src/canvas.C
|
src/canvas.C
|
||||||
src/debug.C
|
src/debug.C
|
||||||
src/event.C
|
|
||||||
src/event_list.C
|
|
||||||
src/grid.C
|
src/grid.C
|
||||||
src/gui/draw.C
|
|
||||||
src/gui/event_edit.fl
|
src/gui/event_edit.fl
|
||||||
src/gui/input.C
|
|
||||||
src/gui/ui.fl
|
src/gui/ui.fl
|
||||||
src/instrument.C
|
src/instrument.C
|
||||||
src/jack.C
|
src/jack.C
|
||||||
src/main.C
|
src/main.C
|
||||||
src/mapping.C
|
src/mapping.C
|
||||||
src/midievent.C
|
|
||||||
src/pattern.C
|
src/pattern.C
|
||||||
src/phrase.C
|
src/phrase.C
|
||||||
src/scale.C
|
src/scale.C
|
||||||
|
|
Loading…
Reference in New Issue