Browse Source

Sequencer: More simplification of pattern drawing.

tags/non-daw-v1.2.0
Jonathan Moore Liles 9 years ago
parent
commit
a872d99e9b
42 changed files with 2777 additions and 2917 deletions
  1. +2
    -2
      FL/util/ntk-perf.C
  2. +162
    -0
      nonlib/MIDI/event.C
  3. +99
    -0
      nonlib/MIDI/event.H
  4. +631
    -0
      nonlib/MIDI/event_list.C
  5. +91
    -0
      nonlib/MIDI/event_list.H
  6. +3
    -0
      nonlib/wscript
  7. +927
    -318
      sequencer/src/canvas.C
  8. +29
    -15
      sequencer/src/canvas.H
  9. +1
    -1
      sequencer/src/const.h
  10. +0
    -10
      sequencer/src/dash.H
  11. +0
    -144
      sequencer/src/event.C
  12. +0
    -83
      sequencer/src/event.H
  13. +0
    -627
      sequencer/src/event_list.C
  14. +0
    -89
      sequencer/src/event_list.H
  15. +137
    -54
      sequencer/src/grid.C
  16. +29
    -17
      sequencer/src/grid.H
  17. +0
    -4
      sequencer/src/gui/Makefile
  18. +0
    -105
      sequencer/src/gui/draw.C
  19. +0
    -34
      sequencer/src/gui/draw.H
  20. +20
    -13
      sequencer/src/gui/event_edit.fl
  21. +0
    -347
      sequencer/src/gui/input.C
  22. +0
    -12
      sequencer/src/gui/input.H
  23. +555
    -533
      sequencer/src/gui/ui.fl
  24. +4
    -0
      sequencer/src/instrument.C
  25. +2
    -2
      sequencer/src/instrument.H
  26. +4
    -1
      sequencer/src/jack.C
  27. +6
    -7
      sequencer/src/jack.H
  28. +20
    -28
      sequencer/src/main.C
  29. +2
    -0
      sequencer/src/mapping.C
  30. +2
    -1
      sequencer/src/mapping.H
  31. +0
    -218
      sequencer/src/midievent.C
  32. +0
    -232
      sequencer/src/midievent.H
  33. +20
    -1
      sequencer/src/pattern.C
  34. +8
    -3
      sequencer/src/pattern.H
  35. +2
    -1
      sequencer/src/phrase.C
  36. +2
    -0
      sequencer/src/phrase.H
  37. +13
    -3
      sequencer/src/scale.C
  38. +2
    -3
      sequencer/src/scale.H
  39. +1
    -0
      sequencer/src/smf.C
  40. +2
    -3
      sequencer/src/smf.H
  41. +1
    -1
      sequencer/src/transport.H
  42. +0
    -5
      sequencer/wscript

+ 2
- 2
FL/util/ntk-perf.C 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
- 0
nonlib/MIDI/event.C 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
- 0
nonlib/MIDI/event.H 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
- 0
nonlib/MIDI/event_list.C 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
- 0
nonlib/MIDI/event_list.H 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;
};
}

+ 3
- 0
nonlib/wscript 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'],


+ 927
- 318
sequencer/src/canvas.C
File diff suppressed because it is too large
View File


+ 29
- 15
sequencer/src/canvas.H 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


+ 1
- 1
sequencer/src/const.h 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";


+ 0
- 10
sequencer/src/dash.H View File

@@ -1,10 +0,0 @@

#pragma once

struct dash
{
tick_t timestamp;
tick_t length;
unsigned char color;
};


+ 0
- 144
sequencer/src/event.C 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 );
}

+ 0
- 83
sequencer/src/event.H 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;
}

+ 0
- 627
sequencer/src/event_list.C 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 );
}

+ 0
- 89
sequencer/src/event_list.H 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;
};

+ 137
- 54
sequencer/src/grid.C 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;