@@ -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'], | ||||
@@ -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 ); | |||||
static void draw_dash ( int x, int y, int l, int color, void *userdata ); | |||||
int draw_playhead ( void ); | |||||
// void draw_shape ( int x, int y, int w, int color ); | |||||
static void draw_dash ( tick_t x, int y, tick_t l, int color, int selected, void *userdata ); | |||||
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 by = viewport.y; | |||||
int bw = viewport.w; | |||||
int bh = viewport.h; | |||||
/* int bx = viewport.x; */ | |||||
/* int by = viewport.y; */ | |||||
/* int bw = viewport.w + 100; /\* FIXME: hack *\/ */ | |||||
/* int bh = viewport.h; */ | |||||
const tick_t start = x_to_ts( bx ); | |||||
const tick_t end = x_to_ts( bx + bw ); | |||||
/* const tick_t start = x_to_ts( bx ); */ | |||||
/* const tick_t end = x_to_ts( bx + bw ); */ | |||||
data *d = const_cast< data *>( _rd ); | data *d = const_cast< data *>( _rd ); | ||||
@@ -677,12 +753,14 @@ 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 ) | |||||
draw_note( ts_to_x( ts ), | |||||
note_to_y( e->note() ), | |||||
ts_to_x( tse - ts ), | |||||
e->note_velocity(), | |||||
userdata ); | |||||
/* if ( tse >= start && ts <= end ) */ | |||||
draw_note( // ts_to_x( ts ), | |||||
ts, | |||||
note_to_y( e->note() ), | |||||
tse - ts, | |||||
e->note_velocity(), | |||||
e->selected(), | |||||
userdata ); | |||||
} | } | ||||
} | } | ||||
@@ -768,12 +846,17 @@ Grid::ppqn ( void ) const | |||||
void | void | ||||
Grid::resolution ( unsigned int n ) | Grid::resolution ( unsigned int n ) | ||||
{ | { | ||||
if ( n < 4 ) | |||||
ASSERTION( "bad resolution: %d", n ); | |||||
/* if ( n < 4 ) */ | |||||
/* 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 "event_list.H" | |||||
#include "dash.H" | |||||
#include <MIDI/event.H> | |||||
#include <MIDI/event_list.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 ) | ||||
{ | { | ||||
@@ -107,7 +106,7 @@ protected: | |||||
char *_notes; | char *_notes; | ||||
char *_name; | char *_name; | ||||
int _number; | int _number; | ||||
bool _suspend_update; | bool _suspend_update; | ||||
unsigned int _bpb; /* beats per bar */ | unsigned int _bpb; /* beats per bar */ | ||||
@@ -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; | |||||
uint ts_to_x ( tick_t ts ) const; | |||||
tick_t x_to_ts ( tick_t x ) 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; | |||||
void events ( const event_list * el ); | |||||
MIDI::event_list * events ( void ) const; | |||||
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"} | |||||
code2 {\#include "../event_list.H"} modal size_range {0 0 659 803} visible | |||||
code1 {\#include "../grid.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 | |||||
code0 {\#include "../event.H"} | |||||
code1 {_event = NULL;} | |||||
xywh {945 239 590 30} type Single | |||||
code0 {_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 ); |
@@ -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 ); | |||||
void midi_output_event ( int port, const midievent *e ); | |||||
void midi_output_event ( int port, const midievent *e, tick_t duration ); | |||||
MIDI::midievent * midi_input_event ( int port ); | |||||
void midi_output_event ( int port, const MIDI::midievent *e ); | |||||
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 ); | |||||
phrase_c->grid( NULL ); | |||||
ui->pattern_canvas_widget->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 *phrase_grid = phrase_c->grid(); | |||||
Grid *pattern_grid = ui->pattern_canvas_widget->grid(); | |||||
Grid *phrase_grid = ui->phrase_canvas_widget->grid(); | |||||
pattern_c->grid( NULL ); | |||||
phrase_c->grid( NULL ); | |||||
ui->pattern_canvas_widget->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 ) ); | |||||
phrase_c->grid( phrase::phrase_by_number( 1 ) ); | |||||
ui->pattern_canvas_widget->grid( pattern::pattern_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 ); | |||||
phrase_c->grid( phrase_grid ); | |||||
ui->pattern_canvas_widget->grid( pattern_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 ) ); | |||||
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 ) ); | pattern::signal_create_destroy.connect( mem_fun( song, &song_settings::set_dirty ) ); | ||||
phrase::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 ); | song.dirty( false ); | ||||
init_colors(); | |||||
ui = new UI; | |||||
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 ) | |||||
return chromatic_names[ n ]; | |||||
if ( mod_n == (_degrees[ i ] + k) % 12 ) | |||||
{ | |||||
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 "event.H" | |||||
#include <MIDI/midievent.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 | ||||