| @@ -20,7 +20,7 @@ | |||
| #include <FL/Fl.H> | |||
| #include <FL/Fl_Double_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_draw.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 ); | |||
| { | |||
| @@ -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 | |||
| MIDI/midievent.C | |||
| string_util.C | |||
| MIDI/event_list.C | |||
| MIDI/event.C | |||
| MIDI/midievent.C | |||
| ''', | |||
| includes = '.', | |||
| export_incdirs = [ '.', 'nonlib'], | |||
| @@ -20,7 +20,7 @@ | |||
| #pragma once | |||
| #include "grid.H" | |||
| #include <FL/Fl_Widget.H> | |||
| #include <FL/Fl_Group.H> | |||
| #include <sigc++/sigc++.h> | |||
| using namespace sigc; | |||
| @@ -29,9 +29,19 @@ class Mapping; | |||
| 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 { | |||
| int origin_x, origin_y; | |||
| @@ -79,8 +89,6 @@ class Canvas : public Fl_Widget, public trackable | |||
| void _update_row_mapping ( void ); | |||
| void redraw_ruler ( void ); | |||
| void redraw_mapping ( void ); | |||
| void draw_mapping ( void ); | |||
| void draw_ruler ( void ); | |||
| @@ -88,21 +96,24 @@ class Canvas : public Fl_Widget, public trackable | |||
| void _lr ( void ); | |||
| bool viewable_x ( int x ); | |||
| void draw_line ( int x, int flags ); | |||
| 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: | |||
| enum { OFF, ON, TOGGLE }; | |||
| 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 ); | |||
| virtual ~Canvas ( ); | |||
| void redraw_playhead ( void ); | |||
| void handle_event_change ( void ); | |||
| void set ( int x, int y ); | |||
| void grid ( Grid *g ); | |||
| @@ -112,19 +123,20 @@ public: | |||
| void resize_grid ( void ); | |||
| void resize ( int x, int y, int w, int h ); | |||
| void copy ( void ); | |||
| void clear ( void ); | |||
| void flip ( void ); | |||
| 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 redraw ( void ); */ | |||
| 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 adj_color ( 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_range ( void ); | |||
| void invert_selection ( void ); | |||
| @@ -149,6 +161,8 @@ public: | |||
| void move_selected ( int dir, int n ); | |||
| virtual int handle ( int m ); | |||
| }; | |||
| inline int | |||
| @@ -27,7 +27,7 @@ const int MAX_PATTERN = 128; | |||
| const unsigned int PPQN = 480; | |||
| /* 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_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" | |||
| using namespace MIDI; | |||
| Grid::Grid ( void ) | |||
| { | |||
| _name = NULL; | |||
| @@ -44,7 +46,8 @@ Grid::Grid ( void ) | |||
| d->length = 0; | |||
| _bpb = 4; | |||
| _ppqn = 1; | |||
| /* how many grid positions there are per beat */ | |||
| _ppqn = 4; | |||
| viewport.h = 32; | |||
| viewport.w = 32; | |||
| @@ -184,31 +187,6 @@ Grid::_delete ( int x, int y ) | |||
| 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 | |||
| Grid::clear ( void ) | |||
| { | |||
| @@ -219,13 +197,6 @@ Grid::clear ( void ) | |||
| unlock(); | |||
| } | |||
| int | |||
| Grid::get ( struct dash *d, int x, int y ) const | |||
| { | |||
| return _get( d, x, y ); | |||
| } | |||
| void | |||
| Grid::del ( int x, int y ) | |||
| { | |||
| @@ -318,8 +289,15 @@ Grid::expand ( void ) | |||
| 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 | |||
| 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 ); | |||
| @@ -328,10 +306,8 @@ Grid::put ( int x, int y, tick_t l ) | |||
| event *on = new event; | |||
| event *off = new event; | |||
| struct dash d; | |||
| // 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; | |||
| 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->note( note ); | |||
| on->timestamp( ts ); | |||
| on->note_velocity( 64 ); | |||
| on->note_velocity( velocity ); | |||
| on->link( off ); | |||
| off->status( event::NOTE_OFF ); | |||
| off->note( note ); | |||
| off->timestamp( ts + l ); | |||
| off->note_velocity( 64 ); | |||
| off->note_velocity( velocity ); | |||
| off->link( on ); | |||
| _rw->events.insert( on ); | |||
| _rw->events.insert( off ); | |||
| expand(); | |||
| 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 | |||
| Grid::toggle_select ( int x, int y ) | |||
| { | |||
| @@ -544,6 +610,16 @@ Grid::select_none ( void ) | |||
| unlock(); | |||
| } | |||
| void | |||
| Grid::select_all ( void ) | |||
| { | |||
| lock(); | |||
| _rw->events.select_all(); | |||
| unlock(); | |||
| } | |||
| void | |||
| Grid::invert_selection ( void ) | |||
| { | |||
| @@ -656,13 +732,13 @@ Grid::print ( void ) const | |||
| void | |||
| 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 ); | |||
| @@ -677,12 +753,14 @@ Grid::draw_notes ( draw_note_func_t draw_note, void *userdata ) const | |||
| 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 | |||
| 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 ); | |||
| /* ensure that the correct number of bars are in the viewport */ | |||
| viewport.w = _ppqn * _bpb * 2; | |||
| signal_events_change(); | |||
| signal_settings_change(); | |||
| @@ -19,9 +19,8 @@ | |||
| #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 "instrument.H" | |||
| @@ -48,7 +47,7 @@ struct data { | |||
| tick_t length; | |||
| int state; | |||
| event_list events; | |||
| MIDI::event_list events; | |||
| data( void ) | |||
| { | |||
| @@ -107,7 +106,7 @@ protected: | |||
| char *_notes; | |||
| char *_name; | |||
| int _number; | |||
| bool _suspend_update; | |||
| unsigned int _bpb; /* beats per bar */ | |||
| @@ -131,9 +130,8 @@ protected: | |||
| list <data *> _history; | |||
| 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 _get ( struct dash *d, int x, int y ) const; | |||
| void _link ( void ); | |||
| void _relink ( void ); | |||
| void _fix_length ( void ); | |||
| @@ -145,7 +143,7 @@ private: | |||
| 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; | |||
| @@ -158,10 +156,12 @@ public: | |||
| virtual ~Grid ( void ); | |||
| Grid ( const Grid &rhs ); | |||
| virtual bool velocity_sensitive ( void ) const { return true; } | |||
| int y_to_note ( int y ) 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 * clone ( void ) = 0; | |||
| @@ -170,17 +170,20 @@ public: | |||
| 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 unlock ( void ); | |||
| void clear ( void ); | |||
| int get ( struct dash *d, int x, int y ) const; | |||
| void del ( int x, int y ); | |||
| void adj_velocity ( int x, int y, int n ); | |||
| 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 record_event ( event *e ); | |||
| void record_event ( MIDI::event *e ); | |||
| tick_t index ( void ) const; | |||
| bool playing ( void ) const; | |||
| @@ -219,6 +222,7 @@ public: | |||
| void select ( int start, int end, int t, int b ); | |||
| void delete_time ( int start, int end ); | |||
| void select_none ( void ); | |||
| void select_all ( void ); | |||
| void invert_selection ( void ); | |||
| void resolution ( unsigned int n ); | |||
| @@ -228,11 +232,19 @@ public: | |||
| void draw ( Canvas *c, int bx, int by, int bw, int bh ); | |||
| 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 | |||
| Grid::y_to_note ( int y ) const | |||
| { | |||
| @@ -246,14 +258,14 @@ Grid::note_to_y ( int n ) const | |||
| } | |||
| 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); | |||
| } | |||
| inline unsigned int | |||
| inline tick_t | |||
| Grid::ts_to_x ( tick_t ts ) const | |||
| { | |||
| 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 <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 | |||
| } | |||
| @@ -40,9 +49,9 @@ class Event_Editor {open | |||
| } | |||
| 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 | |||
| } | |||
| @@ -61,10 +70,9 @@ _el = _old = NULL; | |||
| o->hide(); | |||
| 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"} | |||
| 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 {} { | |||
| label {Event List} open | |||
| @@ -192,7 +200,7 @@ update_widgets();} {} | |||
| code {int i = 0; | |||
| if ( ! _el->empty() ) | |||
| for ( event* e = (*_el)[0]; e = e->next(); i++ ) | |||
| for ( event* e = (*_el)[0]; ( e = e->next() ); i++ ) | |||
| { | |||
| Event_Widget *ew; | |||
| @@ -253,9 +261,8 @@ while( w->shown() ) | |||
| } | |||
| 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 | |||
| } { | |||
| 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 {event *_event;} {private local | |||
| decl {MIDI::event *_event;} {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 ) ) | |||
| activate(); | |||
| @@ -374,7 +381,7 @@ name->redraw(); | |||
| // redraw();} {} | |||
| } | |||
| Function {ev( void )} {open return_type {event *} | |||
| Function {ev( void )} {open return_type {MIDI::event *} | |||
| } { | |||
| code {return _event;} {} | |||
| } | |||
| @@ -491,7 +498,7 @@ do_callback();} | |||
| Fl_Slider {} { | |||
| label {Pressure:} | |||
| 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 | |||
| } | |||
| } | |||
| @@ -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 <string> | |||
| #include <MIDI/event.H> | |||
| using namespace MIDI; | |||
| using std::list; | |||
| using std::string; | |||
| @@ -22,7 +22,7 @@ | |||
| #include <list> | |||
| using std::list; | |||
| #include "event.H" | |||
| #include <MIDI/midievent.H> | |||
| struct i_map { | |||
| char *name; | |||
| @@ -55,7 +55,7 @@ public: | |||
| void note_name ( int n, char *s ); | |||
| /* inspection */ | |||
| bool translate ( midievent *e ) const; | |||
| bool translate ( MIDI::midievent *e ) const; | |||
| const char * note_name ( int n ) const; | |||
| int height ( void ) const; | |||
| const char * name ( void ) const; | |||
| @@ -32,7 +32,10 @@ | |||
| #include "transport.H" | |||
| #include "pattern.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 | |||
| /* correct for prototype version of API */ | |||
| @@ -1,18 +1,17 @@ | |||
| #include <jack/jack.h> | |||
| #include <MIDI/midievent.H> | |||
| #include "common.h" | |||
| 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 ); | |||
| 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 ); | |||
| const char * midi_init ( const char *name ); | |||
| 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; | |||
| Canvas *pattern_c, *phrase_c, *trigger_c; | |||
| sequence *playlist; | |||
| global_settings config; | |||
| @@ -59,10 +57,6 @@ quit ( void ) | |||
| delete ui; | |||
| delete pattern_c; | |||
| delete phrase_c; | |||
| delete trigger_c; | |||
| midi_all_sound_off(); | |||
| // wait for it... | |||
| @@ -81,13 +75,14 @@ clear_song ( void ) | |||
| { | |||
| // 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->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 ); | |||
| } | |||
| @@ -125,11 +120,11 @@ load_song ( const char *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 ) ) | |||
| { | |||
| @@ -137,8 +132,8 @@ load_song ( const char *name ) | |||
| 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 ); | |||
| @@ -148,8 +143,8 @@ load_song ( const char *name ) | |||
| 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; | |||
| } | |||
| @@ -237,26 +232,23 @@ main ( int argc, char **argv ) | |||
| 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; | |||
| 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 ) ); | |||
| phrase::signal_create_destroy.connect( mem_fun( song, &song_settings::set_dirty ) ); | |||
| // | |||
| 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 ); | |||
| instance_name = strdup( APP_NAME ); | |||
| @@ -20,7 +20,9 @@ | |||
| #include "mapping.H" | |||
| #include "stdlib.h" | |||
| #include "common.h" | |||
| #include <MIDI/midievent.H> | |||
| using namespace MIDI; | |||
| /* Is C++'s dispatching useless or what? */ | |||
| #define IS_INSTRUMENT ( _type == INSTRUMENT ) | |||
| @@ -21,6 +21,7 @@ | |||
| #include "scale.H" | |||
| #include "instrument.H" | |||
| #include <MIDI/midievent.H> | |||
| /* 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 | |||
| @@ -64,7 +65,7 @@ public: | |||
| void key ( int n ); | |||
| /* inspection */ | |||
| bool translate ( midievent *e ) const; | |||
| bool translate ( MIDI::midievent *e ) const; | |||
| const char * note_name ( int n ) const; | |||
| int velocity ( int n ) 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 <math.h> | |||
| #include <MIDI/event_list.H> | |||
| using namespace MIDI; | |||
| event_list pattern::_recorded_events; | |||
| vector <pattern*> pattern::_patterns; | |||
| int pattern::_solo; | |||
| @@ -276,10 +279,26 @@ pattern::by_number ( int n ) const | |||
| 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 | |||
| 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 ); | |||
| @@ -22,7 +22,6 @@ | |||
| #include "grid.H" | |||
| #include "canvas.H" | |||
| #include "mapping.H" | |||
| // #include "event.H" | |||
| #include "common.h" | |||
| #include <vector> | |||
| @@ -30,7 +29,7 @@ using std::vector; | |||
| class pattern : public Grid | |||
| { | |||
| static event_list _recorded_events; | |||
| static MIDI::event_list _recorded_events; | |||
| static vector <pattern *> _patterns; | |||
| static int _solo; | |||
| static int _pattern_recording; | |||
| @@ -68,7 +67,7 @@ public: | |||
| static pattern * import ( smf *f, int track ); | |||
| static pattern * recording ( void ); | |||
| static void record_event ( const midievent *e ); | |||
| static void record_event ( const MIDI::midievent *e ); | |||
| pattern * create ( void ); | |||
| pattern * by_number ( int n ) const; | |||
| @@ -91,6 +90,7 @@ public: | |||
| int queue ( void ) const; | |||
| void randomize_row ( int y, int feel, float probability ); | |||
| void row_name_press ( int y ); | |||
| int port ( void ) const; | |||
| void port ( int p ); | |||
| @@ -112,4 +112,9 @@ public: | |||
| int ppqn ( void ) const; | |||
| void ppqn ( int n ); | |||
| virtual tick_t default_length ( void ) const | |||
| { | |||
| return PPQN * 4 / _note; | |||
| } | |||
| }; | |||
| @@ -18,12 +18,13 @@ | |||
| /*******************************************************************************/ | |||
| #include "phrase.H" | |||
| #include "gui/draw.H" | |||
| #include "pattern.H" | |||
| #include "smf.H" | |||
| #include "common.h" | |||
| #include <math.h> | |||
| using namespace MIDI; | |||
| vector <phrase*> phrase::_phrases; | |||
| signal <void> phrase::signal_create_destroy; | |||
| @@ -46,6 +46,8 @@ public: | |||
| static phrase * phrase_by_number ( int n ); | |||
| static void reset ( void ); | |||
| virtual bool velocity_sensitive ( void ) const { return false; } | |||
| phrase *create ( void ); | |||
| phrase * by_number ( int n ) const; | |||
| @@ -21,6 +21,9 @@ | |||
| #include "common.h" | |||
| #include "stdlib.h" | |||
| #include <MIDI/midievent.H> | |||
| using namespace MIDI; | |||
| /* Define some scales. These don't really need to be stored on | |||
| disk. Scales don't change that often. */ | |||
| @@ -189,13 +192,20 @@ const char * | |||
| Scale::note_name ( int k, int n ) const | |||
| { | |||
| /* all the magic is here */ | |||
| static char s[5]; | |||
| n %= 12; | |||
| const int mod_n = n % 12; | |||
| // FIXME: searching is not efficient! | |||
| 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; | |||
| } | |||
| @@ -18,8 +18,7 @@ | |||
| /*******************************************************************************/ | |||
| #pragma once | |||
| #include "event.H" | |||
| #include <MIDI/midievent.H> | |||
| class Scale | |||
| { | |||
| @@ -41,7 +40,7 @@ public: | |||
| static const char * chromatic_name ( 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; | |||
| const char * note_name ( int k, int n ) const; | |||
| const char * name ( void ) const; | |||
| @@ -21,6 +21,7 @@ | |||
| #include "phrase.H" | |||
| #include "pattern.H" | |||
| using namespace MIDI; | |||
| smf::smf ( void ) | |||
| { | |||
| @@ -20,7 +20,6 @@ | |||
| #pragma once | |||
| #include "grid.H" | |||
| #include "event.H" | |||
| class pattern; | |||
| class phrase; | |||
| @@ -104,7 +103,7 @@ public: | |||
| void write_meta_event ( byte_t type, int n ); | |||
| 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 open_chunk ( const char *id ); | |||
| @@ -116,7 +115,7 @@ public: | |||
| 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 ); | |||
| @@ -23,7 +23,7 @@ | |||
| using namespace sigc; | |||
| #include "event.H" // just for tick_t | |||
| #include <MIDI/types.h> // just for tick_t | |||
| #include <jack/transport.h> | |||
| @@ -46,18 +46,13 @@ src/NSM.C | |||
| src/NSM/Client.C | |||
| src/canvas.C | |||
| src/debug.C | |||
| src/event.C | |||
| src/event_list.C | |||
| src/grid.C | |||
| src/gui/draw.C | |||
| src/gui/event_edit.fl | |||
| src/gui/input.C | |||
| src/gui/ui.fl | |||
| src/instrument.C | |||
| src/jack.C | |||
| src/main.C | |||
| src/mapping.C | |||
| src/midievent.C | |||
| src/pattern.C | |||
| src/phrase.C | |||
| src/scale.C | |||