Sequencer: More simplification of pattern drawing.

This commit is contained in:
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_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 );
{

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
MIDI/midievent.C
string_util.C
MIDI/event_list.C
MIDI/event.C
MIDI/midievent.C
''',
includes = '.',
export_incdirs = [ '.', 'nonlib'],

File diff suppressed because it is too large Load Diff

View File

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

View File

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

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"
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();

View File

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

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

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 <string>
#include <MIDI/event.H>
using namespace MIDI;
using std::list;
using std::string;

View File

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

View File

@ -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 */

View File

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

View File

@ -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 ) );
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;
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 );
instance_name = strdup( APP_NAME );

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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