Sequencer: More simplification of pattern drawing.

pull/116/head
Jonathan Moore Liles 2012-10-28 22:31:29 -07:00
parent cec17e7990
commit a872d99e9b
42 changed files with 2808 additions and 2948 deletions

View File

@ -20,7 +20,7 @@
#include <FL/Fl.H> #include <FL/Fl.H>
#include <FL/Fl_Double_Window.H> #include <FL/Fl_Double_Window.H>
#include <FL/Fl_Single_Window.H> #include <FL/Fl_Single_Window.H>
#include <FL/Fl_Scalepack.H> #include <FL/Fl_Pack.H>
#include <FL/Fl_Choice.H> #include <FL/Fl_Choice.H>
#include <FL/fl_draw.H> #include <FL/fl_draw.H>
#include <sys/time.h> #include <sys/time.h>
@ -131,7 +131,7 @@ main ( int argc, char **argv )
} }
{ {
Fl_Scalepack *o = new Fl_Scalepack( 0, 24, 800, 600 - 24 ); Fl_Pack *o = new Fl_Pack( 0, 24, 800, 600 - 24 );
o->type( 0 ); o->type( 0 );
{ {

162
nonlib/MIDI/event.C Normal file
View File

@ -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 );
}
}

99
nonlib/MIDI/event.H Normal file
View File

@ -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;
}
}

631
nonlib/MIDI/event_list.C Normal file
View File

@ -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 );
}
}

91
nonlib/MIDI/event_list.H Normal file
View File

@ -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;
};
}

View File

@ -21,6 +21,9 @@ dsp.C
file.C file.C
MIDI/midievent.C MIDI/midievent.C
string_util.C string_util.C
MIDI/event_list.C
MIDI/event.C
MIDI/midievent.C
''', ''',
includes = '.', includes = '.',
export_incdirs = [ '.', 'nonlib'], export_incdirs = [ '.', 'nonlib'],

File diff suppressed because it is too large Load Diff

View File

@ -20,7 +20,7 @@
#pragma once #pragma once
#include "grid.H" #include "grid.H"
#include <FL/Fl_Widget.H> #include <FL/Fl_Group.H>
#include <sigc++/sigc++.h> #include <sigc++/sigc++.h>
using namespace sigc; using namespace sigc;
@ -29,9 +29,19 @@ class Mapping;
enum { LEFT, RIGHT, UP, DOWN, TO_PLAYHEAD, TO_NEXT_NOTE, TO_PREV_NOTE }; enum { LEFT, RIGHT, UP, DOWN, TO_PLAYHEAD, TO_NEXT_NOTE, TO_PREV_NOTE };
class Fl_Scrollbar;
class Fl_Slider;
class Canvas : public Fl_Widget, public trackable class Canvas : public Fl_Group, public trackable
{ {
class Canvas_Panzoomer;
Canvas_Panzoomer *panzoomer;
Fl_Slider *vzoom;
/* these are grid coords, not pixels */
int _old_scroll_x;
int _old_scroll_y;
struct { struct {
int origin_x, origin_y; int origin_x, origin_y;
@ -79,8 +89,6 @@ class Canvas : public Fl_Widget, public trackable
void _update_row_mapping ( void ); void _update_row_mapping ( void );
void redraw_ruler ( void );
void redraw_mapping ( void );
void draw_mapping ( void ); void draw_mapping ( void );
void draw_ruler ( void ); void draw_ruler ( void );
@ -88,21 +96,24 @@ class Canvas : public Fl_Widget, public trackable
void _lr ( void ); void _lr ( void );
bool viewable_x ( int x ); bool viewable_x ( int x );
void draw_line ( int x, int flags );
void update_mapping ( void ); void update_mapping ( void );
static void cb_scroll ( Fl_Widget *w, void *v );
void cb_scroll ( Fl_Widget *w );
static void draw_clip ( void *v, int X, int Y, int W, int H );
void draw_clip ( int X, int Y, int W, int H );
public: public:
enum { OFF, ON, TOGGLE }; enum { OFF, ON, TOGGLE };
signal <void> signal_settings_change; signal <void> signal_settings_change;
signal <void> signal_draw;
signal <void> signal_resize;
signal <void> signal_pan;
Canvas ( int X, int Y, int W, int H, const char *L=0 ); Canvas ( int X, int Y, int W, int H, const char *L=0 );
virtual ~Canvas ( );
void redraw_playhead ( void );
void handle_event_change ( void ); void handle_event_change ( void );
void set ( int x, int y ); void set ( int x, int y );
void grid ( Grid *g ); void grid ( Grid *g );
@ -112,19 +123,20 @@ public:
void resize_grid ( void ); void resize_grid ( void );
void resize ( int x, int y, int w, int h ); void resize ( int x, int y, int w, int h );
void copy ( void ); void copy ( void );
void clear ( void );
void flip ( void );
void draw_row_name ( int y, const char *name, int color ); void draw_row_name ( int y, const char *name, int color );
void draw_shape ( int x, int y, int w, int color ); // void draw_shape ( int x, int y, int w, int color );
static void draw_dash ( int x, int y, int l, int color, void *userdata ); static void draw_dash ( tick_t x, int y, tick_t l, int color, int selected, void *userdata );
int draw_playhead ( void ); void draw_dash ( tick_t x, int y, tick_t w, int color, int selected ) const;
void damage_grid ( tick_t x, int y, tick_t w, int h );
void draw_overlay ( void );
void draw_playhead ( void );
void draw ( void ); void draw ( void );
/* void redraw ( void ); */
bool grid_pos ( int *x, int *y ) const; bool grid_pos ( int *x, int *y ) const;
int is_row_name ( int x, int y ); int is_row_press ( void ) const;
void unset ( int x, int y ); void unset ( int x, int y );
void adj_color ( int x, int y, int n ); void adj_color ( int x, int y, int n );
void adj_length ( int x, int y, int n ); void adj_length ( int x, int y, int n );
void set_end ( int x, int y, int n );
void select ( int x, int y ); void select ( int x, int y );
void select_range ( void ); void select_range ( void );
void invert_selection ( void ); void invert_selection ( void );
@ -149,6 +161,8 @@ public:
void move_selected ( int dir, int n ); void move_selected ( int dir, int n );
virtual int handle ( int m );
}; };
inline int inline int

View File

@ -27,7 +27,7 @@ const int MAX_PATTERN = 128;
const unsigned int PPQN = 480; const unsigned int PPQN = 480;
/* interval between GUI updates for playhead movement, etc. */ /* interval between GUI updates for playhead movement, etc. */
const double TRANSPORT_POLL_INTERVAL = 0.05; const double TRANSPORT_POLL_INTERVAL = 0.02;
const char APP_NAME[] = "Non-Sequencer"; const char APP_NAME[] = "Non-Sequencer";
const char APP_TITLE[] = "The Non-Sequencer"; const char APP_TITLE[] = "The Non-Sequencer";

View File

@ -1,10 +0,0 @@
#pragma once
struct dash
{
tick_t timestamp;
tick_t length;
unsigned char color;
};

View File

@ -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 );
}

View File

@ -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;
}

View File

@ -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 );
}

View File

@ -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;
};

View File

@ -25,6 +25,8 @@
#include "smf.H" #include "smf.H"
using namespace MIDI;
Grid::Grid ( void ) Grid::Grid ( void )
{ {
_name = NULL; _name = NULL;
@ -44,7 +46,8 @@ Grid::Grid ( void )
d->length = 0; d->length = 0;
_bpb = 4; _bpb = 4;
_ppqn = 1; /* how many grid positions there are per beat */
_ppqn = 4;
viewport.h = 32; viewport.h = 32;
viewport.w = 32; viewport.w = 32;
@ -184,31 +187,6 @@ Grid::_delete ( int x, int y )
return false; return false;
} }
bool
Grid::_get ( struct dash *d, int x, int y ) const
{
event *e = _event ( x, y, false );
if ( e )
{
tick_t ts = e->timestamp();
tick_t l = 0;
if ( e->linked() )
l = e->link()->timestamp() - ts;
else
WARNING( "Found unlinked note on" );
d->timestamp = ts_to_x( ts );
d->length = ts_to_x( l );
d->color = e->note_velocity();
return true;
}
return false;
}
void void
Grid::clear ( void ) Grid::clear ( void )
{ {
@ -219,13 +197,6 @@ Grid::clear ( void )
unlock(); unlock();
} }
int
Grid::get ( struct dash *d, int x, int y ) const
{
return _get( d, x, y );
}
void void
Grid::del ( int x, int y ) Grid::del ( int x, int y )
{ {
@ -318,8 +289,15 @@ Grid::expand ( void )
unlock(); unlock();
} }
/** returns true if there is a note event at x,y */
bool
Grid::is_set ( int x, int y ) const
{
return _event( x, y, false );
}
void void
Grid::put ( int x, int y, tick_t l ) Grid::put ( int x, int y, tick_t l, int velocity )
{ {
int xl = ts_to_x( l ); int xl = ts_to_x( l );
@ -328,10 +306,8 @@ Grid::put ( int x, int y, tick_t l )
event *on = new event; event *on = new event;
event *off = new event; event *off = new event;
struct dash d;
// Don't allow overlap (Why not?) // Don't allow overlap (Why not?)
if ( get( &d, x, y ) || get( &d, x + xl - 1, y ) ) if ( _event( x, y, false ) || _event( x + xl - 1, y, false ) )
return; return;
DMESSAGE( "put %d,%d", x, y ); DMESSAGE( "put %d,%d", x, y );
@ -343,18 +319,19 @@ Grid::put ( int x, int y, tick_t l )
on->status( event::NOTE_ON ); on->status( event::NOTE_ON );
on->note( note ); on->note( note );
on->timestamp( ts ); on->timestamp( ts );
on->note_velocity( 64 ); on->note_velocity( velocity );
on->link( off ); on->link( off );
off->status( event::NOTE_OFF ); off->status( event::NOTE_OFF );
off->note( note ); off->note( note );
off->timestamp( ts + l ); off->timestamp( ts + l );
off->note_velocity( 64 ); off->note_velocity( velocity );
off->link( on ); off->link( on );
_rw->events.insert( on ); _rw->events.insert( on );
_rw->events.insert( off ); _rw->events.insert( off );
expand(); expand();
unlock(); unlock();
@ -457,6 +434,95 @@ Grid::adj_duration ( int x, int y, int l )
} }
void
Grid::set_duration ( int x, int y, int ex )
{
if ( ex < 1 )
return;
lock();
event *e = _event( x, y, true );
if ( e )
{
DMESSAGE( "adjusting duration" );
e->note_duration( x_to_ts( ex ) );
_rw->events.sort( e->link() );
}
unlock();
}
void
Grid::get_note_properties ( int x, int y, note_properties *p ) const
{
const event *e = _event( x, y, false );
e->get_note_properties( p );
p->start = p->start;
p->duration = p->duration;
p->note = note_to_y( p->note );
}
/* void */
/* Grid::set_note_properties ( int x, int y, const note_properties *p ) */
/* { */
/* lock(); */
/* const event *e = _event( x, y, true ); */
/* e->set_note_properties( p ); */
/* unlock(); */
/* } */
/** if there's a note at grid coordinates x,y, then adjust them to the beginning of the note */
int
Grid::get_start ( int *x, int *y ) const
{
const event *e = _event( *x, *y, false );
if ( e )
{
*x = ts_to_x( e->timestamp() );
return 1;
}
else
return 0;
}
void
Grid::set_end ( int x, int y, int ex )
{
lock();
event *e = _event( x, y, true );
if ( e )
{
DMESSAGE( "adjusting duration" );
tick_t ts = x_to_ts( ex );
if ( ts > e->timestamp() &&
ts - e->timestamp() > x_to_ts( 1 ) )
{
e->note_duration( ts - e->timestamp() );
_rw->events.sort( e->link() );
}
}
unlock();
}
void void
Grid::toggle_select ( int x, int y ) Grid::toggle_select ( int x, int y )
{ {
@ -544,6 +610,16 @@ Grid::select_none ( void )
unlock(); unlock();
} }
void
Grid::select_all ( void )
{
lock();
_rw->events.select_all();
unlock();
}
void void
Grid::invert_selection ( void ) Grid::invert_selection ( void )
{ {
@ -656,13 +732,13 @@ Grid::print ( void ) const
void void
Grid::draw_notes ( draw_note_func_t draw_note, void *userdata ) const Grid::draw_notes ( draw_note_func_t draw_note, void *userdata ) const
{ {
int bx = viewport.x; /* int bx = viewport.x; */
int by = viewport.y; /* int by = viewport.y; */
int bw = viewport.w; /* int bw = viewport.w + 100; /\* FIXME: hack *\/ */
int bh = viewport.h; /* int bh = viewport.h; */
const tick_t start = x_to_ts( bx ); /* const tick_t start = x_to_ts( bx ); */
const tick_t end = x_to_ts( bx + bw ); /* const tick_t end = x_to_ts( bx + bw ); */
data *d = const_cast< data *>( _rd ); data *d = const_cast< data *>( _rd );
@ -677,12 +753,14 @@ Grid::draw_notes ( draw_note_func_t draw_note, void *userdata ) const
const tick_t tse = e->link()->timestamp(); const tick_t tse = e->link()->timestamp();
if ( tse >= start && ts <= end ) /* if ( tse >= start && ts <= end ) */
draw_note( ts_to_x( ts ), draw_note( // ts_to_x( ts ),
note_to_y( e->note() ), ts,
ts_to_x( tse - ts ), note_to_y( e->note() ),
e->note_velocity(), tse - ts,
userdata ); e->note_velocity(),
e->selected(),
userdata );
} }
} }
@ -768,12 +846,17 @@ Grid::ppqn ( void ) const
void void
Grid::resolution ( unsigned int n ) Grid::resolution ( unsigned int n )
{ {
if ( n < 4 ) /* if ( n < 4 ) */
ASSERTION( "bad resolution: %d", n ); /* ASSERTION( "bad resolution: %d", n ); */
_ppqn = n / 4; // _ppqn = n / 4;
_ppqn = n;
DMESSAGE( "%d setting resolution to %d", n, _ppqn ); DMESSAGE( "%d setting resolution to %d", n, _ppqn );
/* ensure that the correct number of bars are in the viewport */
viewport.w = _ppqn * _bpb * 2;
signal_events_change(); signal_events_change();
signal_settings_change(); signal_settings_change();

View File

@ -19,9 +19,8 @@
#pragma once #pragma once
#include "event.H" #include <MIDI/event.H>
#include "event_list.H" #include <MIDI/event_list.H>
#include "dash.H"
#include "const.h" #include "const.h"
#include "instrument.H" #include "instrument.H"
@ -48,7 +47,7 @@ struct data {
tick_t length; tick_t length;
int state; int state;
event_list events; MIDI::event_list events;
data( void ) data( void )
{ {
@ -107,7 +106,7 @@ protected:
char *_notes; char *_notes;
char *_name; char *_name;
int _number; int _number;
bool _suspend_update; bool _suspend_update;
unsigned int _bpb; /* beats per bar */ unsigned int _bpb; /* beats per bar */
@ -131,9 +130,8 @@ protected:
list <data *> _history; list <data *> _history;
void _remove_marked ( void ); void _remove_marked ( void );
event * _event ( int x, int y, bool write ) const; MIDI::event * _event ( int x, int y, bool write ) const;
bool _delete ( int x, int y ); bool _delete ( int x, int y );
bool _get ( struct dash *d, int x, int y ) const;
void _link ( void ); void _link ( void );
void _relink ( void ); void _relink ( void );
void _fix_length ( void ); void _fix_length ( void );
@ -145,7 +143,7 @@ private:
public: public:
typedef void draw_note_func_t ( int x, int y, int l, int velocity, void *userdata ); typedef void draw_note_func_t ( tick_t x, int y, tick_t l, int velocity, int selected, void *userdata );
void draw_notes ( draw_note_func_t draw_note, void *userdata ) const; void draw_notes ( draw_note_func_t draw_note, void *userdata ) const;
@ -158,10 +156,12 @@ public:
virtual ~Grid ( void ); virtual ~Grid ( void );
Grid ( const Grid &rhs ); Grid ( const Grid &rhs );
virtual bool velocity_sensitive ( void ) const { return true; }
int y_to_note ( int y ) const; int y_to_note ( int y ) const;
int note_to_y ( int n ) const; int note_to_y ( int n ) const;
tick_t x_to_ts ( uint x ) const; tick_t x_to_ts ( tick_t x ) const;
uint ts_to_x ( tick_t ts ) const; tick_t ts_to_x ( tick_t ts ) const;
virtual Grid * create ( void ) = 0; virtual Grid * create ( void ) = 0;
virtual Grid * clone ( void ) = 0; virtual Grid * clone ( void ) = 0;
@ -170,17 +170,20 @@ public:
virtual Grid * by_number ( int n ) const = 0; virtual Grid * by_number ( int n ) const = 0;
virtual void put ( int x, int y, tick_t l ); virtual void put ( int x, int y, tick_t l, int velocity = 64 );
virtual bool is_set ( int x, int y ) const;
void lock ( void ); void lock ( void );
void unlock ( void ); void unlock ( void );
void clear ( void ); void clear ( void );
int get ( struct dash *d, int x, int y ) const;
void del ( int x, int y ); void del ( int x, int y );
void adj_velocity ( int x, int y, int n ); void adj_velocity ( int x, int y, int n );
void adj_duration ( int x, int y, int l ); void adj_duration ( int x, int y, int l );
void set_duration ( int x, int y, int l );
void set_end ( int x, int y, int l );
int get_start ( int *x, int *y ) const;
void move ( int x, int y, int nx, int ny ); void move ( int x, int y, int nx, int ny );
void record_event ( event *e ); void record_event ( MIDI::event *e );
tick_t index ( void ) const; tick_t index ( void ) const;
bool playing ( void ) const; bool playing ( void ) const;
@ -219,6 +222,7 @@ public:
void select ( int start, int end, int t, int b ); void select ( int start, int end, int t, int b );
void delete_time ( int start, int end ); void delete_time ( int start, int end );
void select_none ( void ); void select_none ( void );
void select_all ( void );
void invert_selection ( void ); void invert_selection ( void );
void resolution ( unsigned int n ); void resolution ( unsigned int n );
@ -228,11 +232,19 @@ public:
void draw ( Canvas *c, int bx, int by, int bw, int bh ); void draw ( Canvas *c, int bx, int by, int bw, int bh );
void print ( void ) const; void print ( void ) const;
event_list * events ( void ) const; MIDI::event_list * events ( void ) const;
void events ( const event_list * el ); void events ( const MIDI::event_list * el );
void get_note_properties ( int x, int y, MIDI::note_properties *p ) const;
virtual tick_t default_length ( void ) const
{
return PPQN;
}
}; };
inline int inline int
Grid::y_to_note ( int y ) const Grid::y_to_note ( int y ) const
{ {
@ -246,14 +258,14 @@ Grid::note_to_y ( int n ) const
} }
inline tick_t inline tick_t
Grid::x_to_ts ( unsigned int x ) const Grid::x_to_ts ( tick_t x ) const
{ {
return (x * PPQN) / _ppqn; return (x * PPQN) / _ppqn;
// return x * (PPQN / _ppqn); // return x * (PPQN / _ppqn);
} }
inline unsigned int inline tick_t
Grid::ts_to_x ( tick_t ts ) const Grid::ts_to_x ( tick_t ts ) const
{ {
return (ts * _ppqn) / PPQN; return (ts * _ppqn) / PPQN;

View File

@ -1,4 +0,0 @@
all:
@ make -s -C ..

View File

@ -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 );
}

View File

@ -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, ... );

View File

@ -28,6 +28,15 @@ decl {\#include "../grid.H"} {private local
decl {\#include "../scale.H"} {private local decl {\#include "../scale.H"} {private local
} }
decl {\#include <MIDI/event.H>} {public global
}
decl {\#include <MIDI/event_list.H>} {selected public global
}
decl {using namespace MIDI;} {private local
}
decl {extern Fl_Color velocity_colors[];} {private local decl {extern Fl_Color velocity_colors[];} {private local
} }
@ -40,9 +49,9 @@ class Event_Editor {open
} }
decl {Grid *_grid;} {private local decl {Grid *_grid;} {private local
} }
decl {event_list *_old;} {private local decl {MIDI::event_list *_old;} {private local
} }
decl {event_list *_el;} {private local decl {MIDI::event_list *_el;} {private local
} }
decl {int _y;} {private local decl {int _y;} {private local
} }
@ -61,10 +70,9 @@ _el = _old = NULL;
o->hide(); o->hide();
Fl::delete_widget( o );} open Fl::delete_widget( o );} open
xywh {966 99 655 805} type Double resizable xywh {968 122 655 805} type Double resizable
code0 {\#include "event_edit.H"} code0 {\#include "event_edit.H"}
code1 {\#include "../grid.H"} code1 {\#include "../grid.H"} modal size_range {0 0 659 803} visible
code2 {\#include "../event_list.H"} modal size_range {0 0 659 803} visible
} { } {
Fl_Scroll {} { Fl_Scroll {} {
label {Event List} open label {Event List} open
@ -192,7 +200,7 @@ update_widgets();} {}
code {int i = 0; code {int i = 0;
if ( ! _el->empty() ) if ( ! _el->empty() )
for ( event* e = (*_el)[0]; e = e->next(); i++ ) for ( event* e = (*_el)[0]; ( e = e->next() ); i++ )
{ {
Event_Widget *ew; Event_Widget *ew;
@ -253,9 +261,8 @@ while( w->shown() )
} }
widget_class Event_Widget {user_data_type {void *} open widget_class Event_Widget {user_data_type {void *} open
xywh {943 216 590 30} type Single xywh {945 239 590 30} type Single
code0 {\#include "../event.H"} code0 {_event = NULL;}
code1 {_event = NULL;}
class Fl_Group size_range {400 24 0 24} visible class Fl_Group size_range {400 24 0 24} visible
} { } {
decl {static const Fl_Color note_color = FL_BLACK;} {private local decl {static const Fl_Color note_color = FL_BLACK;} {private local
@ -270,11 +277,11 @@ widget_class Event_Widget {user_data_type {void *} open
} }
decl {static const Fl_Color pitch_color = FL_GREEN} {private local decl {static const Fl_Color pitch_color = FL_GREEN} {private local
} }
decl {event *_event;} {private local decl {MIDI::event *_event;} {private local
} }
decl {Fl_Group *tab;} {private local decl {Fl_Group *tab;} {private local
} }
Function {ev( event * e )} {open return_type void Function {ev( MIDI::event * e )} {open return_type void
} { } {
code {if ( e && ( _event == NULL ) ) code {if ( e && ( _event == NULL ) )
activate(); activate();
@ -374,7 +381,7 @@ name->redraw();
// redraw();} {} // redraw();} {}
} }
Function {ev( void )} {open return_type {event *} Function {ev( void )} {open return_type {MIDI::event *}
} { } {
code {return _event;} {} code {return _event;} {}
} }
@ -491,7 +498,7 @@ do_callback();}
Fl_Slider {} { Fl_Slider {} {
label {Pressure:} label {Pressure:}
user_data this user_data this
callback cb_lsb selected callback cb_lsb
xywh {359 0 230 24} type {Horz Fill} align 4 when 4 maximum 127 step 1 xywh {359 0 230 24} type {Horz Fill} align 4 when 4 maximum 127 step 1
} }
} }

View File

@ -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;
}

View File

@ -1,12 +0,0 @@
#pragma once
#include "../canvas.H"
#include "../common.h"
class O_Canvas;
void disp_message ( char *s );
void async_exec ( const char *cmd );
int canvas_input_callback ( O_Canvas *widget, Canvas *c, int m );
int disp_init ( int argc, char **argv );

File diff suppressed because it is too large Load Diff

View File

@ -33,8 +33,12 @@
#include <list> #include <list>
#include <string> #include <string>
#include <MIDI/event.H>
using namespace MIDI;
using std::list; using std::list;
using std::string; using std::string;

View File

@ -22,7 +22,7 @@
#include <list> #include <list>
using std::list; using std::list;
#include "event.H" #include <MIDI/midievent.H>
struct i_map { struct i_map {
char *name; char *name;
@ -55,7 +55,7 @@ public:
void note_name ( int n, char *s ); void note_name ( int n, char *s );
/* inspection */ /* inspection */
bool translate ( midievent *e ) const; bool translate ( MIDI::midievent *e ) const;
const char * note_name ( int n ) const; const char * note_name ( int n ) const;
int height ( void ) const; int height ( void ) const;
const char * name ( void ) const; const char * name ( void ) const;

View File

@ -32,7 +32,10 @@
#include "transport.H" #include "transport.H"
#include "pattern.H" #include "pattern.H"
#include "phrase.H" #include "phrase.H"
#include "event_list.H" #include <MIDI/event_list.H>
#include <MIDI/midievent.H>
using namespace MIDI;
#ifdef JACK_MIDI_PROTO_API #ifdef JACK_MIDI_PROTO_API
/* correct for prototype version of API */ /* correct for prototype version of API */

View File

@ -1,18 +1,17 @@
#include <jack/jack.h> #include <jack/jack.h>
#include <MIDI/midievent.H>
#include "common.h" #include "common.h"
enum { CONTROL, PERFORMANCE }; enum { CONTROL, PERFORMANCE };
class midievent;
bool midi_input_event ( int port, midievent *e ); bool midi_input_event ( int port, MIDI::midievent *e );
bool midi_is_active ( void ); bool midi_is_active ( void );
midievent * midi_input_event ( int port ); MIDI::midievent * midi_input_event ( int port );
void midi_output_event ( int port, const midievent *e ); void midi_output_event ( int port, const MIDI::midievent *e );
void midi_output_event ( int port, const midievent *e, tick_t duration ); void midi_output_event ( int port, const MIDI::midievent *e, tick_t duration );
void midi_all_sound_off ( void ); void midi_all_sound_off ( void );
const char * midi_init ( const char *name ); const char * midi_init ( const char *name );
void midi_shutdown ( void ); void midi_shutdown ( void );
void midi_output_immediate_event ( int port, const midievent *e ); void midi_output_immediate_event ( int port, const MIDI::midievent *e );

View File

@ -36,8 +36,6 @@
const double NSM_CHECK_INTERVAL = 0.25f; const double NSM_CHECK_INTERVAL = 0.25f;
Canvas *pattern_c, *phrase_c, *trigger_c;
sequence *playlist; sequence *playlist;
global_settings config; global_settings config;
@ -59,10 +57,6 @@ quit ( void )
delete ui; delete ui;
delete pattern_c;
delete phrase_c;
delete trigger_c;
midi_all_sound_off(); midi_all_sound_off();
// wait for it... // wait for it...
@ -81,13 +75,14 @@ clear_song ( void )
{ {
// song.filename = NULL; // song.filename = NULL;
pattern_c->grid( NULL ); ui->pattern_canvas_widget->grid( NULL );
phrase_c->grid( NULL ); ui->phrase_canvas_widget->grid( NULL );
playlist->reset(); playlist->reset();
playlist->insert( 0, 1 ); playlist->insert( 0, 1 );
pattern_c->grid( new pattern );
phrase_c->grid( new phrase ); ui->pattern_canvas_widget->grid( new pattern );
ui->phrase_canvas_widget->grid( new phrase );
song.dirty( false ); song.dirty( false );
} }
@ -125,11 +120,11 @@ load_song ( const char *name )
MESSAGE( "loading song \"%s\"", name ); MESSAGE( "loading song \"%s\"", name );
Grid *pattern_grid = pattern_c->grid(); Grid *pattern_grid = ui->pattern_canvas_widget->grid();
Grid *phrase_grid = phrase_c->grid(); Grid *phrase_grid = ui->phrase_canvas_widget->grid();
pattern_c->grid( NULL ); ui->pattern_canvas_widget->grid( NULL );
phrase_c->grid( NULL ); ui->phrase_canvas_widget->grid( NULL );
if ( ! playlist->load( name ) ) if ( ! playlist->load( name ) )
{ {
@ -137,8 +132,8 @@ load_song ( const char *name )
goto failed; goto failed;
} }
pattern_c->grid( pattern::pattern_by_number( 1 ) ); ui->pattern_canvas_widget->grid( pattern::pattern_by_number( 1 ) );
phrase_c->grid( phrase::phrase_by_number( 1 ) ); ui->phrase_canvas_widget->grid( phrase::phrase_by_number( 1 ) );
song.filename = strdup( name ); song.filename = strdup( name );
@ -148,8 +143,8 @@ load_song ( const char *name )
failed: failed:
pattern_c->grid( pattern_grid ); ui->pattern_canvas_widget->grid( pattern_grid );
phrase_c->grid( phrase_grid ); ui->phrase_canvas_widget->grid( phrase_grid );
return false; return false;
} }
@ -237,26 +232,23 @@ main ( int argc, char **argv )
playlist = new sequence; playlist = new sequence;
pattern_c = new Canvas(0,0,1,1);
phrase_c = new Canvas(0,0,1,1);
trigger_c = new Canvas(0,0,1,1);
nsm = new NSM_Client; nsm = new NSM_Client;
song.filename = NULL; song.filename = NULL;
clear_song();
pattern::signal_create_destroy.connect( mem_fun( phrase_c, &Canvas::v_zoom_fit ) );
pattern::signal_create_destroy.connect( mem_fun( song, &song_settings::set_dirty ) );
phrase::signal_create_destroy.connect( mem_fun( song, &song_settings::set_dirty ) );
//
song.dirty( false );
init_colors();
ui = new UI; ui = new UI;
pattern::signal_create_destroy.connect( mem_fun( ui->phrase_canvas_widget, &Canvas::v_zoom_fit ) );
pattern::signal_create_destroy.connect( mem_fun( song, &song_settings::set_dirty ) );
phrase::signal_create_destroy.connect( mem_fun( song, &song_settings::set_dirty ) );
song.dirty( false );
clear_song();
#ifdef HAVE_XPM
ui->main_window->icon((char *)p);
#endif
ui->main_window->show( 0, 0 ); ui->main_window->show( 0, 0 );
instance_name = strdup( APP_NAME ); instance_name = strdup( APP_NAME );

View File

@ -20,7 +20,9 @@
#include "mapping.H" #include "mapping.H"
#include "stdlib.h" #include "stdlib.h"
#include "common.h" #include "common.h"
#include <MIDI/midievent.H>
using namespace MIDI;
/* Is C++'s dispatching useless or what? */ /* Is C++'s dispatching useless or what? */
#define IS_INSTRUMENT ( _type == INSTRUMENT ) #define IS_INSTRUMENT ( _type == INSTRUMENT )

View File

@ -21,6 +21,7 @@
#include "scale.H" #include "scale.H"
#include "instrument.H" #include "instrument.H"
#include <MIDI/midievent.H>
/* C++'s inheritance system falls down dead for this application, so we /* C++'s inheritance system falls down dead for this application, so we
have to do it backwards, using the base class (Mapping) as an interface have to do it backwards, using the base class (Mapping) as an interface
@ -64,7 +65,7 @@ public:
void key ( int n ); void key ( int n );
/* inspection */ /* inspection */
bool translate ( midievent *e ) const; bool translate ( MIDI::midievent *e ) const;
const char * note_name ( int n ) const; const char * note_name ( int n ) const;
int velocity ( int n ) const; int velocity ( int n ) const;
int key ( void ) const; int key ( void ) const;

View File

@ -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() );
}

View File

@ -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;
}

View File

@ -26,6 +26,9 @@
#include "transport.H" #include "transport.H"
#include <math.h> #include <math.h>
#include <MIDI/event_list.H>
using namespace MIDI;
event_list pattern::_recorded_events; event_list pattern::_recorded_events;
vector <pattern*> pattern::_patterns; vector <pattern*> pattern::_patterns;
int pattern::_solo; int pattern::_solo;
@ -276,10 +279,26 @@ pattern::by_number ( int n ) const
return pattern::pattern_by_number( n ); return pattern::pattern_by_number( n );
} }
/** what to do when the row name is pressed */
void
pattern::row_name_press ( int y )
{
/* echo note */
midievent e;
e.status( event::NOTE_ON );
e.channel( _channel );
e.timestamp( default_length() );
e.note( y );
e.note_velocity( 64 );
midi_output_immediate_event ( _port, &e );
}
void void
pattern::put ( int x, int y, tick_t l ) pattern::put ( int x, int y, tick_t l )
{ {
l = l ? l : PPQN * 4 / _note; l = l ? l : default_length();
Grid::put( x, y, l ); Grid::put( x, y, l );

View File

@ -22,7 +22,6 @@
#include "grid.H" #include "grid.H"
#include "canvas.H" #include "canvas.H"
#include "mapping.H" #include "mapping.H"
// #include "event.H"
#include "common.h" #include "common.h"
#include <vector> #include <vector>
@ -30,7 +29,7 @@ using std::vector;
class pattern : public Grid class pattern : public Grid
{ {
static event_list _recorded_events; static MIDI::event_list _recorded_events;
static vector <pattern *> _patterns; static vector <pattern *> _patterns;
static int _solo; static int _solo;
static int _pattern_recording; static int _pattern_recording;
@ -68,7 +67,7 @@ public:
static pattern * import ( smf *f, int track ); static pattern * import ( smf *f, int track );
static pattern * recording ( void ); static pattern * recording ( void );
static void record_event ( const midievent *e ); static void record_event ( const MIDI::midievent *e );
pattern * create ( void ); pattern * create ( void );
pattern * by_number ( int n ) const; pattern * by_number ( int n ) const;
@ -91,6 +90,7 @@ public:
int queue ( void ) const; int queue ( void ) const;
void randomize_row ( int y, int feel, float probability ); void randomize_row ( int y, int feel, float probability );
void row_name_press ( int y );
int port ( void ) const; int port ( void ) const;
void port ( int p ); void port ( int p );
@ -112,4 +112,9 @@ public:
int ppqn ( void ) const; int ppqn ( void ) const;
void ppqn ( int n ); void ppqn ( int n );
virtual tick_t default_length ( void ) const
{
return PPQN * 4 / _note;
}
}; };

View File

@ -18,12 +18,13 @@
/*******************************************************************************/ /*******************************************************************************/
#include "phrase.H" #include "phrase.H"
#include "gui/draw.H"
#include "pattern.H" #include "pattern.H"
#include "smf.H" #include "smf.H"
#include "common.h" #include "common.h"
#include <math.h> #include <math.h>
using namespace MIDI;
vector <phrase*> phrase::_phrases; vector <phrase*> phrase::_phrases;
signal <void> phrase::signal_create_destroy; signal <void> phrase::signal_create_destroy;

View File

@ -46,6 +46,8 @@ public:
static phrase * phrase_by_number ( int n ); static phrase * phrase_by_number ( int n );
static void reset ( void ); static void reset ( void );
virtual bool velocity_sensitive ( void ) const { return false; }
phrase *create ( void ); phrase *create ( void );
phrase * by_number ( int n ) const; phrase * by_number ( int n ) const;

View File

@ -21,6 +21,9 @@
#include "common.h" #include "common.h"
#include "stdlib.h" #include "stdlib.h"
#include <MIDI/midievent.H>
using namespace MIDI;
/* Define some scales. These don't really need to be stored on /* Define some scales. These don't really need to be stored on
disk. Scales don't change that often. */ disk. Scales don't change that often. */
@ -189,13 +192,20 @@ const char *
Scale::note_name ( int k, int n ) const Scale::note_name ( int k, int n ) const
{ {
/* all the magic is here */ /* all the magic is here */
static char s[5];
n %= 12; const int mod_n = n % 12;
// FIXME: searching is not efficient! // FIXME: searching is not efficient!
for ( int i = _notes; i-- ; ) for ( int i = _notes; i-- ; )
if ( n == (_degrees[ i ] + k) % 12 ) if ( mod_n == (_degrees[ i ] + k) % 12 )
return chromatic_names[ n ]; {
snprintf( s, sizeof(s), "%s%i",
chromatic_names[ mod_n ],
n / 12 );
return s;
}
return NULL; return NULL;
} }

View File

@ -18,8 +18,7 @@
/*******************************************************************************/ /*******************************************************************************/
#pragma once #pragma once
#include <MIDI/midievent.H>
#include "event.H"
class Scale class Scale
{ {
@ -41,7 +40,7 @@ public:
static const char * chromatic_name ( int n ); static const char * chromatic_name ( int n );
static int octave ( int n ); static int octave ( int n );
bool translate ( int k, midievent *e ) const; bool translate ( int k, MIDI::midievent *e ) const;
int note ( int k, int n ) const; int note ( int k, int n ) const;
const char * note_name ( int k, int n ) const; const char * note_name ( int k, int n ) const;
const char * name ( void ) const; const char * name ( void ) const;

View File

@ -21,6 +21,7 @@
#include "phrase.H" #include "phrase.H"
#include "pattern.H" #include "pattern.H"
using namespace MIDI;
smf::smf ( void ) smf::smf ( void )
{ {

View File

@ -20,7 +20,6 @@
#pragma once #pragma once
#include "grid.H" #include "grid.H"
#include "event.H"
class pattern; class pattern;
class phrase; class phrase;
@ -104,7 +103,7 @@ public:
void write_meta_event ( byte_t type, int n ); void write_meta_event ( byte_t type, int n );
void write_meta_event ( byte_t type, const char *s ); void write_meta_event ( byte_t type, const char *s );
void write_event ( const midievent *e ); void write_event ( const MIDI::midievent *e );
void write_header ( int tracks ); void write_header ( int tracks );
void open_chunk ( const char *id ); void open_chunk ( const char *id );
@ -116,7 +115,7 @@ public:
void cue ( bool b ); void cue ( bool b );
list <midievent> * read_track_events ( tick_t *length ); list <MIDI::midievent> * read_track_events ( tick_t *length );
void write_phrase_info ( const phrase *p ); void write_phrase_info ( const phrase *p );

View File

@ -23,7 +23,7 @@
using namespace sigc; using namespace sigc;
#include "event.H" // just for tick_t #include <MIDI/types.h> // just for tick_t
#include <jack/transport.h> #include <jack/transport.h>

View File

@ -46,18 +46,13 @@ src/NSM.C
src/NSM/Client.C src/NSM/Client.C
src/canvas.C src/canvas.C
src/debug.C src/debug.C
src/event.C
src/event_list.C
src/grid.C src/grid.C
src/gui/draw.C
src/gui/event_edit.fl src/gui/event_edit.fl
src/gui/input.C
src/gui/ui.fl src/gui/ui.fl
src/instrument.C src/instrument.C
src/jack.C src/jack.C
src/main.C src/main.C
src/mapping.C src/mapping.C
src/midievent.C
src/pattern.C src/pattern.C
src/phrase.C src/phrase.C
src/scale.C src/scale.C