Sequencer: More simplification of pattern drawing.
This commit is contained in:
parent
cec17e7990
commit
a872d99e9b
|
@ -20,7 +20,7 @@
|
|||
#include <FL/Fl.H>
|
||||
#include <FL/Fl_Double_Window.H>
|
||||
#include <FL/Fl_Single_Window.H>
|
||||
#include <FL/Fl_Scalepack.H>
|
||||
#include <FL/Fl_Pack.H>
|
||||
#include <FL/Fl_Choice.H>
|
||||
#include <FL/fl_draw.H>
|
||||
#include <sys/time.h>
|
||||
|
@ -131,7 +131,7 @@ main ( int argc, char **argv )
|
|||
}
|
||||
|
||||
{
|
||||
Fl_Scalepack *o = new Fl_Scalepack( 0, 24, 800, 600 - 24 );
|
||||
Fl_Pack *o = new Fl_Pack( 0, 24, 800, 600 - 24 );
|
||||
o->type( 0 );
|
||||
|
||||
{
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
|
||||
/*******************************************************************************/
|
||||
/* Copyright (C) 2007-2008 Jonathan Moore Liles */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it and/or modify it */
|
||||
/* under the terms of the GNU General Public License as published by the */
|
||||
/* Free Software Foundation; either version 2 of the License, or (at your */
|
||||
/* option) any later version. */
|
||||
/* */
|
||||
/* This program is distributed in the hope that it will be useful, but WITHOUT */
|
||||
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
|
||||
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
|
||||
/* more details. */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General Public License along */
|
||||
/* with This program; see the file COPYING. If not,write to the Free Software */
|
||||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
/*******************************************************************************/
|
||||
|
||||
#include "event.H"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace MIDI
|
||||
{
|
||||
void
|
||||
event::_init ( void )
|
||||
{
|
||||
_link = _next = _prev = NULL;
|
||||
_selected = 0;
|
||||
}
|
||||
|
||||
event::event ( void )
|
||||
{
|
||||
_init();
|
||||
}
|
||||
|
||||
event::~event ( void )
|
||||
{
|
||||
_link = _next = _prev = NULL;
|
||||
}
|
||||
|
||||
/* copy constructor */
|
||||
event::event ( const event &e ) : midievent( e )
|
||||
{
|
||||
_link = _next = _prev = NULL;
|
||||
_selected = e._selected;
|
||||
}
|
||||
|
||||
event::event ( const midievent &e ) : midievent( e )
|
||||
{
|
||||
_init();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
event::link ( event *event )
|
||||
{
|
||||
if ( event == NULL )
|
||||
{
|
||||
if ( _link )
|
||||
{
|
||||
_link->_link = NULL;
|
||||
_link = NULL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
_link = event;
|
||||
_link->_link = this;
|
||||
}
|
||||
|
||||
event *
|
||||
event::link ( void ) const
|
||||
{
|
||||
return _link;
|
||||
}
|
||||
|
||||
bool
|
||||
event::linked ( void ) const
|
||||
{
|
||||
return _link != NULL;
|
||||
}
|
||||
|
||||
void
|
||||
event::select ( void )
|
||||
{
|
||||
_selected = 1;
|
||||
|
||||
if ( _link )
|
||||
_link->_selected = 1;
|
||||
}
|
||||
|
||||
void
|
||||
event::deselect ( void )
|
||||
{
|
||||
_selected = 0;
|
||||
|
||||
if ( _link )
|
||||
_link->_selected = 0;
|
||||
}
|
||||
|
||||
bool
|
||||
event::selected ( int n ) const
|
||||
{
|
||||
return _selected == n;
|
||||
}
|
||||
|
||||
bool
|
||||
event::selected ( void ) const
|
||||
{
|
||||
return _selected == 1;
|
||||
}
|
||||
|
||||
/* override this so we can update linked event */
|
||||
void
|
||||
event::note ( char note )
|
||||
{
|
||||
midievent::note( note );
|
||||
|
||||
if ( _link )
|
||||
_link->midievent::note( note );
|
||||
}
|
||||
|
||||
/* stupid C++ makes us override the all polymorphic functions... */
|
||||
unsigned char
|
||||
event::note ( void ) const
|
||||
{
|
||||
return midievent::note();
|
||||
}
|
||||
|
||||
tick_t
|
||||
event::note_duration ( void ) const
|
||||
{
|
||||
return _link ? _link->timestamp() - timestamp() : 0;
|
||||
}
|
||||
|
||||
void
|
||||
event::note_duration ( tick_t l )
|
||||
{
|
||||
if ( _link )
|
||||
_link->timestamp( timestamp() + l );
|
||||
}
|
||||
|
||||
void
|
||||
event::get_note_properties ( note_properties *p ) const
|
||||
{
|
||||
p->start = timestamp();
|
||||
p->duration = note_duration();
|
||||
p->velocity = note_velocity();
|
||||
p->note = note();
|
||||
}
|
||||
|
||||
void
|
||||
event::set_note_properties ( const note_properties *p )
|
||||
{
|
||||
timestamp( p->start );
|
||||
note_duration( p->duration );
|
||||
note_velocity( p->velocity );
|
||||
note( p->note );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
|
||||
/*******************************************************************************/
|
||||
/* Copyright (C) 2007-2008 Jonathan Moore Liles */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it and/or modify it */
|
||||
/* under the terms of the GNU General Public License as published by the */
|
||||
/* Free Software Foundation; either version 2 of the License, or (at your */
|
||||
/* option) any later version. */
|
||||
/* */
|
||||
/* This program is distributed in the hope that it will be useful, but WITHOUT */
|
||||
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
|
||||
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
|
||||
/* more details. */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General Public License along */
|
||||
/* with This program; see the file COPYING. If not,write to the Free Software */
|
||||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
/*******************************************************************************/
|
||||
|
||||
/* Higher level event interface than midievent, supporting
|
||||
doublely-linked list, marking, selection, and linking of note
|
||||
on/off pairs. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "midievent.H"
|
||||
|
||||
namespace MIDI
|
||||
{
|
||||
class event_list;
|
||||
|
||||
class event;
|
||||
class note_properties {
|
||||
public:
|
||||
tick_t start;
|
||||
tick_t duration;
|
||||
int note;
|
||||
int velocity;
|
||||
};
|
||||
|
||||
class event : public midievent
|
||||
{
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
/* these are only to be used by event_list class! */
|
||||
event *_next;
|
||||
event *_prev;
|
||||
|
||||
private:
|
||||
|
||||
event *_link; /* other event in pair */
|
||||
|
||||
byte_t _selected;
|
||||
|
||||
void _init ( void );
|
||||
|
||||
public:
|
||||
|
||||
event();
|
||||
~event();
|
||||
event ( const event &e );
|
||||
event ( const midievent &e );
|
||||
|
||||
event * next ( void ) const;
|
||||
event * prev ( void ) const;
|
||||
|
||||
void link ( event *event );
|
||||
event * link ( void ) const;
|
||||
bool linked ( void ) const;
|
||||
void select ( void );
|
||||
void deselect ( void );
|
||||
bool selected ( int n ) const;
|
||||
bool selected ( void ) const;
|
||||
void note ( char note );
|
||||
unsigned char note ( void ) const;
|
||||
tick_t note_duration ( void ) const;
|
||||
void note_duration ( tick_t l );
|
||||
|
||||
void get_note_properties ( note_properties *e ) const;
|
||||
void set_note_properties ( const note_properties *e );
|
||||
|
||||
friend class event_list;
|
||||
|
||||
};
|
||||
|
||||
inline event *
|
||||
event::next ( void ) const
|
||||
{
|
||||
return _next;
|
||||
}
|
||||
|
||||
inline event *
|
||||
event::prev ( void ) const
|
||||
{
|
||||
return _prev;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,631 @@
|
|||
|
||||
/*******************************************************************************/
|
||||
/* Copyright (C) 2008 Jonathan Moore Liles */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it and/or modify it */
|
||||
/* under the terms of the GNU General Public License as published by the */
|
||||
/* Free Software Foundation; either version 2 of the License, or (at your */
|
||||
/* option) any later version. */
|
||||
/* */
|
||||
/* This program is distributed in the hope that it will be useful, but WITHOUT */
|
||||
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
|
||||
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
|
||||
/* more details. */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General Public License along */
|
||||
/* with This program; see the file COPYING. If not,write to the Free Software */
|
||||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
/*******************************************************************************/
|
||||
|
||||
#include "debug.h"
|
||||
#include "event_list.H"
|
||||
|
||||
/* The operations we perform on event lists are clumsy with STL lists
|
||||
and iterators so we have a custom doubly-linked list implementation
|
||||
here for complete control */
|
||||
|
||||
namespace MIDI
|
||||
{
|
||||
#define RFOR_ALL( it ) for ( event *next, * it = _tail; it && ((next = it ->_prev), true) ; it = next )
|
||||
#define FOR_ALL( it ) for ( event *next, * it = _head; it && ((next = it ->_next), true) ; it = next )
|
||||
// #define FOR_ALL( e ) for ( event * e = _head; e; e = e ->_next )
|
||||
#define FOR_SELECTED( e ) FOR_ALL( e ) if ( e ->selected() )
|
||||
#define RFOR_SELECTED( e ) RFOR_ALL( e ) if ( e ->selected() )
|
||||
|
||||
|
||||
event_list::event_list ( void )
|
||||
{
|
||||
_head = NULL;
|
||||
_tail = NULL;
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
event_list::~event_list ( void )
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
/* copy constructor */
|
||||
event_list::event_list ( const event_list &el )
|
||||
{
|
||||
_copy( &el );
|
||||
}
|
||||
|
||||
event_list &
|
||||
event_list::operator= ( const event_list &rhs )
|
||||
{
|
||||
if ( this != &rhs )
|
||||
{
|
||||
clear();
|
||||
|
||||
_copy( &rhs );
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
event_list &
|
||||
event_list::operator= ( const list <midievent> &rhs )
|
||||
{
|
||||
clear();
|
||||
|
||||
for ( list <midievent>::const_iterator me = rhs.begin(); me != rhs.end(); me++ )
|
||||
{
|
||||
event *e = new event( *me );
|
||||
|
||||
_insert( NULL, e );
|
||||
}
|
||||
|
||||
relink();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** allow indexing */
|
||||
event *
|
||||
event_list::operator[] ( unsigned int index )
|
||||
{
|
||||
unsigned int i = 0;
|
||||
for ( event *e = _head; e; (e = e->_next), ++i )
|
||||
if ( i == index )
|
||||
return e;
|
||||
|
||||
// all else fails.
|
||||
return _tail;
|
||||
}
|
||||
|
||||
void
|
||||
event_list::_copy ( const event_list *el )
|
||||
{
|
||||
if ( ! el->_head )
|
||||
{
|
||||
_head = _tail = NULL;
|
||||
_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
_head = new event( *(el->_head) );
|
||||
_head->_prev = NULL;
|
||||
|
||||
event *p = _head;
|
||||
|
||||
for ( event *e = el->_head->_next; e; e = e->_next )
|
||||
{
|
||||
event *n = new event( *e );
|
||||
|
||||
n->_next = NULL;
|
||||
p->_next = n;
|
||||
n->_prev = p;
|
||||
|
||||
p = n;
|
||||
}
|
||||
|
||||
_tail = p;
|
||||
|
||||
_size = el->_size;
|
||||
|
||||
relink();
|
||||
}
|
||||
|
||||
/** insert event /n/ before event /o/ */
|
||||
void
|
||||
event_list::_insert ( event *o, event *n )
|
||||
{
|
||||
++_size;
|
||||
|
||||
if ( ! o )
|
||||
{
|
||||
n->_next = NULL;
|
||||
n->_prev = _tail;
|
||||
|
||||
if ( _tail )
|
||||
_tail->_next = n;
|
||||
|
||||
_tail = n;
|
||||
if ( ! _head )
|
||||
_head = n;
|
||||
return;
|
||||
}
|
||||
|
||||
event *t = o->_prev;
|
||||
|
||||
o->_prev = n;
|
||||
n->_next = o;
|
||||
n->_prev = t;
|
||||
|
||||
if ( ! t )
|
||||
_head = n;
|
||||
else
|
||||
t->_next = n;
|
||||
}
|
||||
|
||||
void
|
||||
event_list::unlink ( event *e )
|
||||
{
|
||||
if ( e->_next )
|
||||
e->_next->_prev = e->_prev;
|
||||
else
|
||||
_tail = e->_prev;
|
||||
|
||||
if ( e->_prev )
|
||||
e->_prev->_next = e->_next;
|
||||
else
|
||||
_head = e->_next;
|
||||
|
||||
--_size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
event_list::clear ( void )
|
||||
{
|
||||
for ( event *e = _head; e ; )
|
||||
{
|
||||
event *n = e->_next;
|
||||
delete e;
|
||||
e = n;
|
||||
}
|
||||
|
||||
_head = NULL;
|
||||
_tail = NULL;
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
void
|
||||
event_list::mix ( event *ne )
|
||||
{
|
||||
FOR_ALL( e )
|
||||
if ( *e == *ne )
|
||||
{
|
||||
/* already have an event like this, drop it */
|
||||
|
||||
if ( ne->linked() )
|
||||
delete ne->link();
|
||||
|
||||
delete ne;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
insert( ne );
|
||||
if ( ne->linked() )
|
||||
insert( ne->link() );
|
||||
|
||||
}
|
||||
|
||||
/** remove elements from list /el/ to this list */
|
||||
void
|
||||
event_list::merge ( event_list *el )
|
||||
{
|
||||
event *n;
|
||||
for ( event *e = el->_head; e; e = n )
|
||||
{
|
||||
n = e->_next;
|
||||
|
||||
el->unlink( e );
|
||||
|
||||
insert( e );
|
||||
}
|
||||
}
|
||||
|
||||
/** unlink event e */
|
||||
void
|
||||
event_list::remove ( event *e )
|
||||
{
|
||||
unlink( e );
|
||||
delete e;
|
||||
}
|
||||
|
||||
/** sorted insert /e/ */
|
||||
void
|
||||
event_list::insert ( event *e )
|
||||
{
|
||||
/* find the place to insert */
|
||||
RFOR_ALL( i )
|
||||
if ( *e >= *i )
|
||||
{
|
||||
_insert( i->_next, e );
|
||||
return;
|
||||
}
|
||||
|
||||
_insert( _head, e );
|
||||
}
|
||||
|
||||
/** just append event without sorting */
|
||||
void
|
||||
event_list::append ( event *e )
|
||||
{
|
||||
_insert( NULL, e );
|
||||
}
|
||||
|
||||
event *
|
||||
event_list::first ( void ) const
|
||||
{
|
||||
return _head;
|
||||
}
|
||||
|
||||
event *
|
||||
event_list::last ( void ) const
|
||||
{
|
||||
return _tail;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************/
|
||||
/* Selection */
|
||||
/*************/
|
||||
|
||||
/** select all events from /start/ to /end/ inclusive */
|
||||
void
|
||||
event_list::select ( tick_t start, tick_t end )
|
||||
{
|
||||
FOR_ALL( e )
|
||||
{
|
||||
tick_t ts = e->timestamp();
|
||||
|
||||
/* don't count note offs exactly on start */
|
||||
if ( ts == start && e->is_note_off() )
|
||||
continue;
|
||||
|
||||
if ( ts >= start && ts < end )
|
||||
e->select();
|
||||
}
|
||||
}
|
||||
|
||||
/** select note evenets from /start/ to /end/ within range /hi/ through /lo/ */
|
||||
void
|
||||
event_list::select ( tick_t start, tick_t end, int hi, int lo )
|
||||
{
|
||||
FOR_ALL( e )
|
||||
{
|
||||
tick_t ts = e->timestamp();
|
||||
|
||||
/* don't count note offs exactly on start */
|
||||
if ( ! e->is_note_on() )
|
||||
continue;
|
||||
|
||||
if ( ts >= start && ts < end &&
|
||||
e->note() <= hi && e->note() >= lo )
|
||||
e->select();
|
||||
}
|
||||
}
|
||||
|
||||
/** select ALL events */
|
||||
void
|
||||
event_list::select_all ( void )
|
||||
{
|
||||
FOR_ALL( e )
|
||||
e->select();
|
||||
}
|
||||
|
||||
void
|
||||
event_list::select_none ( void )
|
||||
{
|
||||
FOR_ALL( e )
|
||||
e->deselect();
|
||||
}
|
||||
|
||||
void
|
||||
event_list::invert_selection ( void )
|
||||
{
|
||||
FOR_ALL( e )
|
||||
if ( ! e->is_note_off() )
|
||||
{
|
||||
if ( e->selected() )
|
||||
e->deselect();
|
||||
else
|
||||
e->select();
|
||||
}
|
||||
}
|
||||
|
||||
/** remove all selected events */
|
||||
void
|
||||
event_list::remove_selected ( void )
|
||||
{
|
||||
FOR_SELECTED( e )
|
||||
{
|
||||
remove( e );
|
||||
}
|
||||
}
|
||||
|
||||
/** transpose selected notes (ignoring other event types) by /n/ tones
|
||||
* (may span octaves) */
|
||||
void
|
||||
event_list::transpose_selected ( int n )
|
||||
{
|
||||
FOR_SELECTED( e )
|
||||
{
|
||||
if ( e->is_note_on() )
|
||||
e->note( e->note() + n );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** change all notes of value /from/ to /to/ */
|
||||
void
|
||||
event_list::rewrite_selected ( int from, int to )
|
||||
{
|
||||
FOR_SELECTED( e )
|
||||
{
|
||||
if ( e->is_note_on() && e->note() == from )
|
||||
e->note( to );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** get timestamp of earliest selected event */
|
||||
tick_t
|
||||
event_list::selection_min ( void )
|
||||
{
|
||||
FOR_SELECTED( e )
|
||||
return e->timestamp();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
tick_t
|
||||
event_list::selection_max ( void )
|
||||
{
|
||||
RFOR_SELECTED( e )
|
||||
return e->timestamp();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** move selected events by offset /o/ */
|
||||
void
|
||||
event_list::move_selected ( long o )
|
||||
{
|
||||
if ( o < 0 )
|
||||
if ( selection_min() < (tick_t)( 0 - o ) )
|
||||
return;
|
||||
|
||||
if ( o < 0 )
|
||||
{
|
||||
FOR_SELECTED( e )
|
||||
move( e, o );
|
||||
}
|
||||
else
|
||||
{
|
||||
RFOR_SELECTED( e )
|
||||
move( e, o );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
event_list::push_selection ( void )
|
||||
{
|
||||
FOR_ALL( e )
|
||||
if ( e->_selected )
|
||||
++e->_selected;
|
||||
}
|
||||
|
||||
void
|
||||
event_list::pop_selection ( void )
|
||||
{
|
||||
FOR_ALL( e )
|
||||
if ( e->_selected )
|
||||
--e->_selected;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** verify that all note ons are linked to note offs */
|
||||
bool
|
||||
event_list::verify ( void ) const
|
||||
{
|
||||
FOR_ALL( e )
|
||||
if ( e->is_note_on() && ! e->linked() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** link /e/ (a note on) with the next corresponding note off */
|
||||
void
|
||||
event_list::link ( event *on )
|
||||
{
|
||||
if ( ! on->is_note_on() )
|
||||
return;
|
||||
|
||||
for ( event *off = on->_next; off; off = off->_next )
|
||||
{
|
||||
if ( off->linked() )
|
||||
continue;
|
||||
|
||||
if ( off->is_note_off() &&
|
||||
off->channel() == on->channel() &&
|
||||
off->note() == on->note() )
|
||||
{
|
||||
on->link( off );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
WARNING( "no corresponding note_off found for note on, repairing" );
|
||||
|
||||
event *off = new event( *on );
|
||||
|
||||
off->opcode( event::NOTE_OFF );
|
||||
|
||||
on->link( off );
|
||||
|
||||
insert( off );
|
||||
}
|
||||
|
||||
/** insert /l/ ticks of time at /start/ */
|
||||
void
|
||||
event_list::insert_time ( tick_t start, tick_t l )
|
||||
{
|
||||
FOR_ALL( e )
|
||||
{
|
||||
tick_t ts = e->timestamp();
|
||||
|
||||
if ( e->is_note_off() )
|
||||
continue;
|
||||
|
||||
if ( ts >= start )
|
||||
{
|
||||
if ( e->is_note_on() )
|
||||
{
|
||||
/* only notes ENTIRELY WITHIN the range will be moved */
|
||||
e->timestamp( ts + l );
|
||||
e->link()->timestamp( e->link()->timestamp() + l );
|
||||
}
|
||||
else
|
||||
e->timestamp( e->timestamp() + l );
|
||||
}
|
||||
}
|
||||
|
||||
sort();
|
||||
}
|
||||
|
||||
/** delete events in range and close the gap */
|
||||
void
|
||||
event_list::delete_time ( tick_t start, tick_t end )
|
||||
{
|
||||
tick_t l = end - start;
|
||||
|
||||
push_selection();
|
||||
|
||||
select( start, end );
|
||||
|
||||
remove_selected();
|
||||
|
||||
pop_selection();
|
||||
|
||||
/* cut out the slack */
|
||||
FOR_ALL( e )
|
||||
{
|
||||
tick_t ts = e->timestamp();
|
||||
|
||||
if ( ts >= end )
|
||||
e->timestamp( ts - l );
|
||||
}
|
||||
}
|
||||
|
||||
/** link all note ons to subsequent note offs */
|
||||
void
|
||||
event_list::relink ( void )
|
||||
{
|
||||
/* clear links */
|
||||
FOR_ALL( e )
|
||||
e->link( NULL );
|
||||
|
||||
/* link */
|
||||
FOR_ALL( on )
|
||||
link( on );
|
||||
|
||||
if ( ! verify() )
|
||||
FATAL( "event list failed verification" );
|
||||
}
|
||||
|
||||
/** resort event /e/ */
|
||||
void
|
||||
event_list::sort ( event *e )
|
||||
{
|
||||
unlink( e );
|
||||
|
||||
insert( e );
|
||||
}
|
||||
|
||||
/** resort entire list */
|
||||
void
|
||||
event_list::sort ( void )
|
||||
{
|
||||
event_list *temp = new event_list( );
|
||||
|
||||
_head = temp->_head;
|
||||
_tail = temp->_tail;
|
||||
|
||||
FOR_ALL( n )
|
||||
temp->insert( n );
|
||||
|
||||
temp->_head = NULL;
|
||||
|
||||
delete temp;
|
||||
|
||||
relink();
|
||||
}
|
||||
|
||||
/** move event /e/ by /o/ ticks */
|
||||
void
|
||||
event_list::move ( event *e, long o )
|
||||
{
|
||||
e->timestamp( e->timestamp() + o );
|
||||
|
||||
sort( e );
|
||||
}
|
||||
|
||||
bool
|
||||
event_list::empty ( void ) const
|
||||
{
|
||||
return _head == NULL;
|
||||
}
|
||||
|
||||
size_t
|
||||
event_list::size ( void ) const
|
||||
{
|
||||
return _size;
|
||||
}
|
||||
|
||||
void
|
||||
event_list::_hi_lo ( bool sel, int *hi, int *lo ) const
|
||||
{
|
||||
*hi = 0;
|
||||
*lo = 127;
|
||||
|
||||
FOR_ALL( e )
|
||||
{
|
||||
if ( sel && ! e->selected() )
|
||||
continue;
|
||||
|
||||
if ( ! e->is_note_on() )
|
||||
continue;
|
||||
|
||||
int n = e->note();
|
||||
|
||||
if ( n > *hi )
|
||||
*hi = n;
|
||||
|
||||
if ( n < *lo )
|
||||
*lo = n;
|
||||
}
|
||||
}
|
||||
|
||||
/** set /hi/ and /lo/ to the lowest and highest pitched note events in
|
||||
* this list, respectively */
|
||||
void
|
||||
event_list::hi_lo_note ( int *hi, int *lo ) const
|
||||
{
|
||||
_hi_lo( false, hi, lo );
|
||||
}
|
||||
|
||||
void
|
||||
event_list::selected_hi_lo_note ( int *hi, int *lo ) const
|
||||
{
|
||||
_hi_lo( true, hi, lo );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
|
||||
/*******************************************************************************/
|
||||
/* Copyright (C) 2008 Jonathan Moore Liles */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it and/or modify it */
|
||||
/* under the terms of the GNU General Public License as published by the */
|
||||
/* Free Software Foundation; either version 2 of the License, or (at your */
|
||||
/* option) any later version. */
|
||||
/* */
|
||||
/* This program is distributed in the hope that it will be useful, but WITHOUT */
|
||||
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
|
||||
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
|
||||
/* more details. */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General Public License along */
|
||||
/* with This program; see the file COPYING. If not,write to the Free Software */
|
||||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
/*******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "event.H"
|
||||
#include <list>
|
||||
|
||||
namespace MIDI {
|
||||
using std::list;
|
||||
|
||||
class midievent;
|
||||
|
||||
class event_list {
|
||||
|
||||
event * _head;
|
||||
event * _tail;
|
||||
|
||||
size_t _size;
|
||||
|
||||
void _insert ( event *o, event *n );
|
||||
void _copy ( const event_list *el );
|
||||
void _hi_lo ( bool sel, int *hi, int *lo ) const;
|
||||
|
||||
public:
|
||||
|
||||
event_list ( void );
|
||||
~event_list ( void );
|
||||
event_list ( const event_list &el );
|
||||
|
||||
void clear ( void );
|
||||
void merge ( event_list *el );
|
||||
void unlink ( event *e );
|
||||
void remove ( event *e );
|
||||
void insert ( event *e );
|
||||
event * first ( void ) const;
|
||||
event * last ( void ) const;
|
||||
void select ( tick_t start, tick_t end );
|
||||
void select ( tick_t start, tick_t end, int hi, int lo );
|
||||
|
||||
void select_all ( void );
|
||||
void select_none ( void );
|
||||
void invert_selection ( void );
|
||||
|
||||
void remove_selected ( void );
|
||||
void transpose_selected ( int n );
|
||||
tick_t selection_min ( void );
|
||||
tick_t selection_max ( void );
|
||||
void move_selected ( long o );
|
||||
void push_selection ( void );
|
||||
void pop_selection ( void );
|
||||
bool verify ( void ) const;
|
||||
void link ( event *on );
|
||||
void insert_time ( tick_t start, tick_t l );
|
||||
void delete_time ( tick_t start, tick_t end );
|
||||
void relink ( void );
|
||||
void sort ( event *e );
|
||||
void sort ( void );
|
||||
void move ( event *e, long o );
|
||||
bool empty ( void ) const;
|
||||
size_t size ( void ) const;
|
||||
void append ( event *e );
|
||||
void mix ( event *ne );
|
||||
void hi_lo_note ( int *hi, int *lo ) const;
|
||||
void rewrite_selected ( int from, int to );
|
||||
void selected_hi_lo_note ( int *hi, int *lo ) const;
|
||||
|
||||
|
||||
event_list & operator= ( const event_list &rhs );
|
||||
event_list & operator= ( const list <midievent> &rhs );
|
||||
event *operator[] ( unsigned int index );
|
||||
|
||||
// friend class event;
|
||||
};
|
||||
}
|
|
@ -21,6 +21,9 @@ dsp.C
|
|||
file.C
|
||||
MIDI/midievent.C
|
||||
string_util.C
|
||||
MIDI/event_list.C
|
||||
MIDI/event.C
|
||||
MIDI/midievent.C
|
||||
''',
|
||||
includes = '.',
|
||||
export_incdirs = [ '.', 'nonlib'],
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -20,7 +20,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "grid.H"
|
||||
#include <FL/Fl_Widget.H>
|
||||
#include <FL/Fl_Group.H>
|
||||
|
||||
#include <sigc++/sigc++.h>
|
||||
using namespace sigc;
|
||||
|
@ -29,9 +29,19 @@ class Mapping;
|
|||
|
||||
enum { LEFT, RIGHT, UP, DOWN, TO_PLAYHEAD, TO_NEXT_NOTE, TO_PREV_NOTE };
|
||||
|
||||
class Fl_Scrollbar;
|
||||
class Fl_Slider;
|
||||
|
||||
class Canvas : public Fl_Widget, public trackable
|
||||
class Canvas : public Fl_Group, public trackable
|
||||
{
|
||||
class Canvas_Panzoomer;
|
||||
|
||||
Canvas_Panzoomer *panzoomer;
|
||||
Fl_Slider *vzoom;
|
||||
|
||||
/* these are grid coords, not pixels */
|
||||
int _old_scroll_x;
|
||||
int _old_scroll_y;
|
||||
|
||||
struct {
|
||||
int origin_x, origin_y;
|
||||
|
@ -79,8 +89,6 @@ class Canvas : public Fl_Widget, public trackable
|
|||
|
||||
void _update_row_mapping ( void );
|
||||
|
||||
void redraw_ruler ( void );
|
||||
void redraw_mapping ( void );
|
||||
void draw_mapping ( void );
|
||||
void draw_ruler ( void );
|
||||
|
||||
|
@ -88,21 +96,24 @@ class Canvas : public Fl_Widget, public trackable
|
|||
void _lr ( void );
|
||||
|
||||
bool viewable_x ( int x );
|
||||
void draw_line ( int x, int flags );
|
||||
|
||||
void update_mapping ( void );
|
||||
|
||||
static void cb_scroll ( Fl_Widget *w, void *v );
|
||||
void cb_scroll ( Fl_Widget *w );
|
||||
static void draw_clip ( void *v, int X, int Y, int W, int H );
|
||||
void draw_clip ( int X, int Y, int W, int H );
|
||||
|
||||
public:
|
||||
|
||||
enum { OFF, ON, TOGGLE };
|
||||
|
||||
signal <void> signal_settings_change;
|
||||
signal <void> signal_draw;
|
||||
signal <void> signal_resize;
|
||||
signal <void> signal_pan;
|
||||
|
||||
Canvas ( int X, int Y, int W, int H, const char *L=0 );
|
||||
virtual ~Canvas ( );
|
||||
|
||||
void redraw_playhead ( void );
|
||||
void handle_event_change ( void );
|
||||
void set ( int x, int y );
|
||||
void grid ( Grid *g );
|
||||
|
@ -112,19 +123,20 @@ public:
|
|||
void resize_grid ( void );
|
||||
void resize ( int x, int y, int w, int h );
|
||||
void copy ( void );
|
||||
void clear ( void );
|
||||
void flip ( void );
|
||||
void draw_row_name ( int y, const char *name, int color );
|
||||
void draw_shape ( int x, int y, int w, int color );
|
||||
static void draw_dash ( int x, int y, int l, int color, void *userdata );
|
||||
int draw_playhead ( void );
|
||||
// void draw_shape ( int x, int y, int w, int color );
|
||||
static void draw_dash ( tick_t x, int y, tick_t l, int color, int selected, void *userdata );
|
||||
void draw_dash ( tick_t x, int y, tick_t w, int color, int selected ) const;
|
||||
void damage_grid ( tick_t x, int y, tick_t w, int h );
|
||||
void draw_overlay ( void );
|
||||
void draw_playhead ( void );
|
||||
void draw ( void );
|
||||
/* void redraw ( void ); */
|
||||
bool grid_pos ( int *x, int *y ) const;
|
||||
int is_row_name ( int x, int y );
|
||||
int is_row_press ( void ) const;
|
||||
void unset ( int x, int y );
|
||||
void adj_color ( int x, int y, int n );
|
||||
void adj_length ( int x, int y, int n );
|
||||
void set_end ( int x, int y, int n );
|
||||
void select ( int x, int y );
|
||||
void select_range ( void );
|
||||
void invert_selection ( void );
|
||||
|
@ -149,6 +161,8 @@ public:
|
|||
|
||||
void move_selected ( int dir, int n );
|
||||
|
||||
virtual int handle ( int m );
|
||||
|
||||
};
|
||||
|
||||
inline int
|
||||
|
|
|
@ -27,7 +27,7 @@ const int MAX_PATTERN = 128;
|
|||
const unsigned int PPQN = 480;
|
||||
|
||||
/* interval between GUI updates for playhead movement, etc. */
|
||||
const double TRANSPORT_POLL_INTERVAL = 0.05;
|
||||
const double TRANSPORT_POLL_INTERVAL = 0.02;
|
||||
|
||||
const char APP_NAME[] = "Non-Sequencer";
|
||||
const char APP_TITLE[] = "The Non-Sequencer";
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
struct dash
|
||||
{
|
||||
tick_t timestamp;
|
||||
tick_t length;
|
||||
unsigned char color;
|
||||
};
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
|
||||
/*******************************************************************************/
|
||||
/* Copyright (C) 2007-2008 Jonathan Moore Liles */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it and/or modify it */
|
||||
/* under the terms of the GNU General Public License as published by the */
|
||||
/* Free Software Foundation; either version 2 of the License, or (at your */
|
||||
/* option) any later version. */
|
||||
/* */
|
||||
/* This program is distributed in the hope that it will be useful, but WITHOUT */
|
||||
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
|
||||
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
|
||||
/* more details. */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General Public License along */
|
||||
/* with This program; see the file COPYING. If not,write to the Free Software */
|
||||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
/*******************************************************************************/
|
||||
|
||||
/* Higher level event interface, supporting doublely-linked list,
|
||||
marking, selection, and linking of note pairs. */
|
||||
|
||||
#include "event.H"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
void
|
||||
event::_init ( void )
|
||||
{
|
||||
_link = _next = _prev = NULL;
|
||||
_selected = 0;
|
||||
}
|
||||
|
||||
event::event ( void )
|
||||
{
|
||||
_init();
|
||||
}
|
||||
|
||||
event::~event ( void )
|
||||
{
|
||||
_link = _next = _prev = NULL;
|
||||
}
|
||||
|
||||
/* copy constructor */
|
||||
event::event ( const event &e ) : midievent( e )
|
||||
{
|
||||
_link = _next = _prev = NULL;
|
||||
_selected = e._selected;
|
||||
}
|
||||
|
||||
event::event ( const midievent &e ) : midievent( e )
|
||||
{
|
||||
_init();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
event::link ( event *event )
|
||||
{
|
||||
if ( event == NULL )
|
||||
{
|
||||
if ( _link )
|
||||
{
|
||||
_link->_link = NULL;
|
||||
_link = NULL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
_link = event;
|
||||
_link->_link = this;
|
||||
}
|
||||
|
||||
event *
|
||||
event::link ( void ) const
|
||||
{
|
||||
return _link;
|
||||
}
|
||||
|
||||
bool
|
||||
event::linked ( void ) const
|
||||
{
|
||||
return _link != NULL;
|
||||
}
|
||||
|
||||
void
|
||||
event::select ( void )
|
||||
{
|
||||
_selected = 1;
|
||||
|
||||
if ( _link )
|
||||
_link->_selected = 1;
|
||||
}
|
||||
|
||||
void
|
||||
event::deselect ( void )
|
||||
{
|
||||
_selected = 0;
|
||||
|
||||
if ( _link )
|
||||
_link->_selected = 0;
|
||||
}
|
||||
|
||||
bool
|
||||
event::selected ( int n ) const
|
||||
{
|
||||
return _selected == n;
|
||||
}
|
||||
|
||||
bool
|
||||
event::selected ( void ) const
|
||||
{
|
||||
return _selected == 1;
|
||||
}
|
||||
|
||||
/* override this so we can update linked event */
|
||||
void
|
||||
event::note ( char note )
|
||||
{
|
||||
midievent::note( note );
|
||||
|
||||
if ( _link )
|
||||
_link->midievent::note( note );
|
||||
}
|
||||
|
||||
/* stupid C++ makes us override the all polymorphic functions... */
|
||||
unsigned char
|
||||
event::note ( void ) const
|
||||
{
|
||||
return midievent::note();
|
||||
}
|
||||
|
||||
tick_t
|
||||
event::note_duration ( void ) const
|
||||
{
|
||||
return _link ? _link->timestamp() - timestamp() : 0;
|
||||
}
|
||||
|
||||
void
|
||||
event::note_duration ( tick_t l )
|
||||
{
|
||||
if ( _link )
|
||||
_link->timestamp( timestamp() + l );
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
|
||||
/*******************************************************************************/
|
||||
/* Copyright (C) 2007-2008 Jonathan Moore Liles */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it and/or modify it */
|
||||
/* under the terms of the GNU General Public License as published by the */
|
||||
/* Free Software Foundation; either version 2 of the License, or (at your */
|
||||
/* option) any later version. */
|
||||
/* */
|
||||
/* This program is distributed in the hope that it will be useful, but WITHOUT */
|
||||
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
|
||||
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
|
||||
/* more details. */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General Public License along */
|
||||
/* with This program; see the file COPYING. If not,write to the Free Software */
|
||||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
/*******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "midievent.H"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
class event_list;
|
||||
|
||||
class event : public midievent
|
||||
{
|
||||
|
||||
protected:
|
||||
|
||||
/* these are only to be used by event_list class! */
|
||||
event *_next;
|
||||
event *_prev;
|
||||
|
||||
private:
|
||||
|
||||
event *_link; /* other event in pair */
|
||||
|
||||
byte_t _selected;
|
||||
|
||||
void _init ( void );
|
||||
|
||||
public:
|
||||
|
||||
event();
|
||||
~event();
|
||||
event ( const event &e );
|
||||
event ( const midievent &e );
|
||||
|
||||
event * next ( void ) const;
|
||||
event * prev ( void ) const;
|
||||
|
||||
void link ( event *event );
|
||||
event * link ( void ) const;
|
||||
bool linked ( void ) const;
|
||||
void select ( void );
|
||||
void deselect ( void );
|
||||
bool selected ( int n ) const;
|
||||
bool selected ( void ) const;
|
||||
void note ( char note );
|
||||
unsigned char note ( void ) const;
|
||||
tick_t note_duration ( void ) const;
|
||||
void note_duration ( tick_t l );
|
||||
|
||||
|
||||
friend class event_list;
|
||||
|
||||
};
|
||||
|
||||
inline event *
|
||||
event::next ( void ) const
|
||||
{
|
||||
return _next;
|
||||
}
|
||||
|
||||
inline event *
|
||||
event::prev ( void ) const
|
||||
{
|
||||
return _prev;
|
||||
}
|
|
@ -1,627 +0,0 @@
|
|||
|
||||
/*******************************************************************************/
|
||||
/* Copyright (C) 2008 Jonathan Moore Liles */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it and/or modify it */
|
||||
/* under the terms of the GNU General Public License as published by the */
|
||||
/* Free Software Foundation; either version 2 of the License, or (at your */
|
||||
/* option) any later version. */
|
||||
/* */
|
||||
/* This program is distributed in the hope that it will be useful, but WITHOUT */
|
||||
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
|
||||
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
|
||||
/* more details. */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General Public License along */
|
||||
/* with This program; see the file COPYING. If not,write to the Free Software */
|
||||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
/*******************************************************************************/
|
||||
|
||||
#include "event_list.H"
|
||||
|
||||
/* The operations we perform on event lists are clumsy with STL lists
|
||||
and iterators so we have a custom doubly-linked list implementation
|
||||
here for complete control */
|
||||
|
||||
#define RFOR_ALL( it ) for ( event *next, * it = _tail; it && ((next = it ->_prev), true) ; it = next )
|
||||
#define FOR_ALL( it ) for ( event *next, * it = _head; it && ((next = it ->_next), true) ; it = next )
|
||||
// #define FOR_ALL( e ) for ( event * e = _head; e; e = e ->_next )
|
||||
#define FOR_SELECTED( e ) FOR_ALL( e ) if ( e ->selected() )
|
||||
#define RFOR_SELECTED( e ) RFOR_ALL( e ) if ( e ->selected() )
|
||||
|
||||
|
||||
event_list::event_list ( void )
|
||||
{
|
||||
_head = NULL;
|
||||
_tail = NULL;
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
event_list::~event_list ( void )
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
/* copy constructor */
|
||||
event_list::event_list ( const event_list &el )
|
||||
{
|
||||
_copy( &el );
|
||||
}
|
||||
|
||||
event_list &
|
||||
event_list::operator= ( const event_list &rhs )
|
||||
{
|
||||
if ( this != &rhs )
|
||||
{
|
||||
clear();
|
||||
|
||||
_copy( &rhs );
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
event_list &
|
||||
event_list::operator= ( const list <midievent> &rhs )
|
||||
{
|
||||
clear();
|
||||
|
||||
for ( list <midievent>::const_iterator me = rhs.begin(); me != rhs.end(); me++ )
|
||||
{
|
||||
event *e = new event( *me );
|
||||
|
||||
_insert( NULL, e );
|
||||
}
|
||||
|
||||
relink();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** allow indexing */
|
||||
event *
|
||||
event_list::operator[] ( unsigned int index )
|
||||
{
|
||||
unsigned int i = 0;
|
||||
for ( event *e = _head; e; (e = e->_next), ++i )
|
||||
if ( i == index )
|
||||
return e;
|
||||
|
||||
// all else fails.
|
||||
return _tail;
|
||||
}
|
||||
|
||||
void
|
||||
event_list::_copy ( const event_list *el )
|
||||
{
|
||||
if ( ! el->_head )
|
||||
{
|
||||
_head = _tail = NULL;
|
||||
_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
_head = new event( *(el->_head) );
|
||||
_head->_prev = NULL;
|
||||
|
||||
event *p = _head;
|
||||
|
||||
for ( event *e = el->_head->_next; e; e = e->_next )
|
||||
{
|
||||
event *n = new event( *e );
|
||||
|
||||
n->_next = NULL;
|
||||
p->_next = n;
|
||||
n->_prev = p;
|
||||
|
||||
p = n;
|
||||
}
|
||||
|
||||
_tail = p;
|
||||
|
||||
_size = el->_size;
|
||||
|
||||
relink();
|
||||
}
|
||||
|
||||
/** insert event /n/ before event /o/ */
|
||||
void
|
||||
event_list::_insert ( event *o, event *n )
|
||||
{
|
||||
++_size;
|
||||
|
||||
if ( ! o )
|
||||
{
|
||||
n->_next = NULL;
|
||||
n->_prev = _tail;
|
||||
|
||||
if ( _tail )
|
||||
_tail->_next = n;
|
||||
|
||||
_tail = n;
|
||||
if ( ! _head )
|
||||
_head = n;
|
||||
return;
|
||||
}
|
||||
|
||||
event *t = o->_prev;
|
||||
|
||||
o->_prev = n;
|
||||
n->_next = o;
|
||||
n->_prev = t;
|
||||
|
||||
if ( ! t )
|
||||
_head = n;
|
||||
else
|
||||
t->_next = n;
|
||||
}
|
||||
|
||||
void
|
||||
event_list::unlink ( event *e )
|
||||
{
|
||||
if ( e->_next )
|
||||
e->_next->_prev = e->_prev;
|
||||
else
|
||||
_tail = e->_prev;
|
||||
|
||||
if ( e->_prev )
|
||||
e->_prev->_next = e->_next;
|
||||
else
|
||||
_head = e->_next;
|
||||
|
||||
--_size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
event_list::clear ( void )
|
||||
{
|
||||
for ( event *e = _head; e ; )
|
||||
{
|
||||
event *n = e->_next;
|
||||
delete e;
|
||||
e = n;
|
||||
}
|
||||
|
||||
_head = NULL;
|
||||
_tail = NULL;
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
void
|
||||
event_list::mix ( event *ne )
|
||||
{
|
||||
FOR_ALL( e )
|
||||
if ( *e == *ne )
|
||||
{
|
||||
/* already have an event like this, drop it */
|
||||
|
||||
if ( ne->linked() )
|
||||
delete ne->link();
|
||||
|
||||
delete ne;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
insert( ne );
|
||||
if ( ne->linked() )
|
||||
insert( ne->link() );
|
||||
|
||||
}
|
||||
|
||||
/** remove elements from list /el/ to this list */
|
||||
void
|
||||
event_list::merge ( event_list *el )
|
||||
{
|
||||
event *n;
|
||||
for ( event *e = el->_head; e; e = n )
|
||||
{
|
||||
n = e->_next;
|
||||
|
||||
el->unlink( e );
|
||||
|
||||
insert( e );
|
||||
}
|
||||
}
|
||||
|
||||
/** unlink event e */
|
||||
void
|
||||
event_list::remove ( event *e )
|
||||
{
|
||||
unlink( e );
|
||||
delete e;
|
||||
}
|
||||
|
||||
/** sorted insert /e/ */
|
||||
void
|
||||
event_list::insert ( event *e )
|
||||
{
|
||||
/* find the place to insert */
|
||||
RFOR_ALL( i )
|
||||
if ( *e >= *i )
|
||||
{
|
||||
_insert( i->_next, e );
|
||||
return;
|
||||
}
|
||||
|
||||
_insert( _head, e );
|
||||
}
|
||||
|
||||
/** just append event without sorting */
|
||||
void
|
||||
event_list::append ( event *e )
|
||||
{
|
||||
_insert( NULL, e );
|
||||
}
|
||||
|
||||
event *
|
||||
event_list::first ( void ) const
|
||||
{
|
||||
return _head;
|
||||
}
|
||||
|
||||
event *
|
||||
event_list::last ( void ) const
|
||||
{
|
||||
return _tail;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************/
|
||||
/* Selection */
|
||||
/*************/
|
||||
|
||||
/** select all events from /start/ to /end/ inclusive */
|
||||
void
|
||||
event_list::select ( tick_t start, tick_t end )
|
||||
{
|
||||
FOR_ALL( e )
|
||||
{
|
||||
tick_t ts = e->timestamp();
|
||||
|
||||
/* don't count note offs exactly on start */
|
||||
if ( ts == start && e->is_note_off() )
|
||||
continue;
|
||||
|
||||
if ( ts >= start && ts < end )
|
||||
e->select();
|
||||
}
|
||||
}
|
||||
|
||||
/** select note evenets from /start/ to /end/ within range /hi/ through /lo/ */
|
||||
void
|
||||
event_list::select ( tick_t start, tick_t end, int hi, int lo )
|
||||
{
|
||||
FOR_ALL( e )
|
||||
{
|
||||
tick_t ts = e->timestamp();
|
||||
|
||||
/* don't count note offs exactly on start */
|
||||
if ( ! e->is_note_on() )
|
||||
continue;
|
||||
|
||||
if ( ts >= start && ts < end &&
|
||||
e->note() <= hi && e->note() >= lo )
|
||||
e->select();
|
||||
}
|
||||
}
|
||||
|
||||
/** select ALL events */
|
||||
void
|
||||
event_list::select_all ( void )
|
||||
{
|
||||
FOR_ALL( e )
|
||||
e->select();
|
||||
}
|
||||
|
||||
void
|
||||
event_list::select_none ( void )
|
||||
{
|
||||
FOR_ALL( e )
|
||||
e->deselect();
|
||||
}
|
||||
|
||||
void
|
||||
event_list::invert_selection ( void )
|
||||
{
|
||||
FOR_ALL( e )
|
||||
if ( ! e->is_note_off() )
|
||||
{
|
||||
if ( e->selected() )
|
||||
e->deselect();
|
||||
else
|
||||
e->select();
|
||||
}
|
||||
}
|
||||
|
||||
/** remove all selected events */
|
||||
void
|
||||
event_list::remove_selected ( void )
|
||||
{
|
||||
FOR_SELECTED( e )
|
||||
{
|
||||
remove( e );
|
||||
}
|
||||
}
|
||||
|
||||
/** transpose selected notes (ignoring other event types) by /n/ tones
|
||||
* (may span octaves) */
|
||||
void
|
||||
event_list::transpose_selected ( int n )
|
||||
{
|
||||
FOR_SELECTED( e )
|
||||
{
|
||||
if ( e->is_note_on() )
|
||||
e->note( e->note() + n );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** change all notes of value /from/ to /to/ */
|
||||
void
|
||||
event_list::rewrite_selected ( int from, int to )
|
||||
{
|
||||
FOR_SELECTED( e )
|
||||
{
|
||||
if ( e->is_note_on() && e->note() == from )
|
||||
e->note( to );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** get timestamp of earliest selected event */
|
||||
tick_t
|
||||
event_list::selection_min ( void )
|
||||
{
|
||||
FOR_SELECTED( e )
|
||||
return e->timestamp();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
tick_t
|
||||
event_list::selection_max ( void )
|
||||
{
|
||||
RFOR_SELECTED( e )
|
||||
return e->timestamp();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** move selected events by offset /o/ */
|
||||
void
|
||||
event_list::move_selected ( long o )
|
||||
{
|
||||
if ( o < 0 )
|
||||
if ( selection_min() < (tick_t)( 0 - o ) )
|
||||
return;
|
||||
|
||||
if ( o < 0 )
|
||||
{
|
||||
FOR_SELECTED( e )
|
||||
move( e, o );
|
||||
}
|
||||
else
|
||||
{
|
||||
RFOR_SELECTED( e )
|
||||
move( e, o );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
event_list::push_selection ( void )
|
||||
{
|
||||
FOR_ALL( e )
|
||||
if ( e->_selected )
|
||||
++e->_selected;
|
||||
}
|
||||
|
||||
void
|
||||
event_list::pop_selection ( void )
|
||||
{
|
||||
FOR_ALL( e )
|
||||
if ( e->_selected )
|
||||
--e->_selected;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** verify that all note ons are linked to note offs */
|
||||
bool
|
||||
event_list::verify ( void ) const
|
||||
{
|
||||
FOR_ALL( e )
|
||||
if ( e->is_note_on() && ! e->linked() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** link /e/ (a note on) with the next corresponding note off */
|
||||
void
|
||||
event_list::link ( event *on )
|
||||
{
|
||||
if ( ! on->is_note_on() )
|
||||
return;
|
||||
|
||||
for ( event *off = on->_next; off; off = off->_next )
|
||||
{
|
||||
if ( off->linked() )
|
||||
continue;
|
||||
|
||||
if ( off->is_note_off() &&
|
||||
off->channel() == on->channel() &&
|
||||
off->note() == on->note() )
|
||||
{
|
||||
on->link( off );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
WARNING( "no corresponding note_off found for note on, repairing" );
|
||||
|
||||
event *off = new event( *on );
|
||||
|
||||
off->opcode( event::NOTE_OFF );
|
||||
|
||||
on->link( off );
|
||||
|
||||
insert( off );
|
||||
}
|
||||
|
||||
/** insert /l/ ticks of time at /start/ */
|
||||
void
|
||||
event_list::insert_time ( tick_t start, tick_t l )
|
||||
{
|
||||
FOR_ALL( e )
|
||||
{
|
||||
tick_t ts = e->timestamp();
|
||||
|
||||
if ( e->is_note_off() )
|
||||
continue;
|
||||
|
||||
if ( ts >= start )
|
||||
{
|
||||
if ( e->is_note_on() )
|
||||
{
|
||||
/* only notes ENTIRELY WITHIN the range will be moved */
|
||||
e->timestamp( ts + l );
|
||||
e->link()->timestamp( e->link()->timestamp() + l );
|
||||
}
|
||||
else
|
||||
e->timestamp( e->timestamp() + l );
|
||||
}
|
||||
}
|
||||
|
||||
sort();
|
||||
}
|
||||
|
||||
/** delete events in range and close the gap */
|
||||
void
|
||||
event_list::delete_time ( tick_t start, tick_t end )
|
||||
{
|
||||
tick_t l = end - start;
|
||||
|
||||
push_selection();
|
||||
|
||||
select( start, end );
|
||||
|
||||
remove_selected();
|
||||
|
||||
pop_selection();
|
||||
|
||||
/* cut out the slack */
|
||||
FOR_ALL( e )
|
||||
{
|
||||
tick_t ts = e->timestamp();
|
||||
|
||||
if ( ts >= end )
|
||||
e->timestamp( ts - l );
|
||||
}
|
||||
}
|
||||
|
||||
/** link all note ons to subsequent note offs */
|
||||
void
|
||||
event_list::relink ( void )
|
||||
{
|
||||
/* clear links */
|
||||
FOR_ALL( e )
|
||||
e->link( NULL );
|
||||
|
||||
/* link */
|
||||
FOR_ALL( on )
|
||||
link( on );
|
||||
|
||||
if ( ! verify() )
|
||||
ASSERTION( "event list failed verification" );
|
||||
}
|
||||
|
||||
/** resort event /e/ */
|
||||
void
|
||||
event_list::sort ( event *e )
|
||||
{
|
||||
unlink( e );
|
||||
|
||||
insert( e );
|
||||
}
|
||||
|
||||
/** resort entire list */
|
||||
void
|
||||
event_list::sort ( void )
|
||||
{
|
||||
event_list *temp = new event_list( );
|
||||
|
||||
_head = temp->_head;
|
||||
_tail = temp->_tail;
|
||||
|
||||
FOR_ALL( n )
|
||||
temp->insert( n );
|
||||
|
||||
temp->_head = NULL;
|
||||
|
||||
delete temp;
|
||||
|
||||
relink();
|
||||
}
|
||||
|
||||
/** move event /e/ by /o/ ticks */
|
||||
void
|
||||
event_list::move ( event *e, long o )
|
||||
{
|
||||
e->timestamp( e->timestamp() + o );
|
||||
|
||||
sort( e );
|
||||
}
|
||||
|
||||
bool
|
||||
event_list::empty ( void ) const
|
||||
{
|
||||
return _head == NULL;
|
||||
}
|
||||
|
||||
size_t
|
||||
event_list::size ( void ) const
|
||||
{
|
||||
return _size;
|
||||
}
|
||||
|
||||
void
|
||||
event_list::_hi_lo ( bool sel, int *hi, int *lo ) const
|
||||
{
|
||||
*hi = 0;
|
||||
*lo = 127;
|
||||
|
||||
FOR_ALL( e )
|
||||
{
|
||||
if ( sel && ! e->selected() )
|
||||
continue;
|
||||
|
||||
if ( ! e->is_note_on() )
|
||||
continue;
|
||||
|
||||
int n = e->note();
|
||||
|
||||
if ( n > *hi )
|
||||
*hi = n;
|
||||
|
||||
if ( n < *lo )
|
||||
*lo = n;
|
||||
}
|
||||
}
|
||||
|
||||
/** set /hi/ and /lo/ to the lowest and highest pitched note events in
|
||||
* this list, respectively */
|
||||
void
|
||||
event_list::hi_lo_note ( int *hi, int *lo ) const
|
||||
{
|
||||
_hi_lo( false, hi, lo );
|
||||
}
|
||||
|
||||
void
|
||||
event_list::selected_hi_lo_note ( int *hi, int *lo ) const
|
||||
{
|
||||
_hi_lo( true, hi, lo );
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
|
||||
/*******************************************************************************/
|
||||
/* Copyright (C) 2008 Jonathan Moore Liles */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it and/or modify it */
|
||||
/* under the terms of the GNU General Public License as published by the */
|
||||
/* Free Software Foundation; either version 2 of the License, or (at your */
|
||||
/* option) any later version. */
|
||||
/* */
|
||||
/* This program is distributed in the hope that it will be useful, but WITHOUT */
|
||||
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
|
||||
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
|
||||
/* more details. */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General Public License along */
|
||||
/* with This program; see the file COPYING. If not,write to the Free Software */
|
||||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
/*******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "event.H"
|
||||
|
||||
#include <list>
|
||||
using std::list;
|
||||
|
||||
class midievent;
|
||||
|
||||
class event_list {
|
||||
|
||||
event * _head;
|
||||
event * _tail;
|
||||
|
||||
size_t _size;
|
||||
|
||||
void _insert ( event *o, event *n );
|
||||
void _copy ( const event_list *el );
|
||||
void _hi_lo ( bool sel, int *hi, int *lo ) const;
|
||||
|
||||
public:
|
||||
|
||||
event_list ( void );
|
||||
~event_list ( void );
|
||||
event_list ( const event_list &el );
|
||||
|
||||
void clear ( void );
|
||||
void merge ( event_list *el );
|
||||
void unlink ( event *e );
|
||||
void remove ( event *e );
|
||||
void insert ( event *e );
|
||||
event * first ( void ) const;
|
||||
event * last ( void ) const;
|
||||
void select ( tick_t start, tick_t end );
|
||||
void select ( tick_t start, tick_t end, int hi, int lo );
|
||||
|
||||
void select_all ( void );
|
||||
void select_none ( void );
|
||||
void invert_selection ( void );
|
||||
|
||||
void remove_selected ( void );
|
||||
void transpose_selected ( int n );
|
||||
tick_t selection_min ( void );
|
||||
tick_t selection_max ( void );
|
||||
void move_selected ( long o );
|
||||
void push_selection ( void );
|
||||
void pop_selection ( void );
|
||||
bool verify ( void ) const;
|
||||
void link ( event *on );
|
||||
void insert_time ( tick_t start, tick_t l );
|
||||
void delete_time ( tick_t start, tick_t end );
|
||||
void relink ( void );
|
||||
void sort ( event *e );
|
||||
void sort ( void );
|
||||
void move ( event *e, long o );
|
||||
bool empty ( void ) const;
|
||||
size_t size ( void ) const;
|
||||
void append ( event *e );
|
||||
void mix ( event *ne );
|
||||
void hi_lo_note ( int *hi, int *lo ) const;
|
||||
void rewrite_selected ( int from, int to );
|
||||
void selected_hi_lo_note ( int *hi, int *lo ) const;
|
||||
|
||||
|
||||
event_list & operator= ( const event_list &rhs );
|
||||
event_list & operator= ( const list <midievent> &rhs );
|
||||
event *operator[] ( unsigned int index );
|
||||
|
||||
// friend class event;
|
||||
};
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
#include "smf.H"
|
||||
|
||||
using namespace MIDI;
|
||||
|
||||
Grid::Grid ( void )
|
||||
{
|
||||
_name = NULL;
|
||||
|
@ -44,7 +46,8 @@ Grid::Grid ( void )
|
|||
d->length = 0;
|
||||
|
||||
_bpb = 4;
|
||||
_ppqn = 1;
|
||||
/* how many grid positions there are per beat */
|
||||
_ppqn = 4;
|
||||
|
||||
viewport.h = 32;
|
||||
viewport.w = 32;
|
||||
|
@ -184,31 +187,6 @@ Grid::_delete ( int x, int y )
|
|||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Grid::_get ( struct dash *d, int x, int y ) const
|
||||
{
|
||||
event *e = _event ( x, y, false );
|
||||
|
||||
if ( e )
|
||||
{
|
||||
tick_t ts = e->timestamp();
|
||||
tick_t l = 0;
|
||||
|
||||
if ( e->linked() )
|
||||
l = e->link()->timestamp() - ts;
|
||||
else
|
||||
WARNING( "Found unlinked note on" );
|
||||
|
||||
d->timestamp = ts_to_x( ts );
|
||||
d->length = ts_to_x( l );
|
||||
d->color = e->note_velocity();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Grid::clear ( void )
|
||||
{
|
||||
|
@ -219,13 +197,6 @@ Grid::clear ( void )
|
|||
unlock();
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Grid::get ( struct dash *d, int x, int y ) const
|
||||
{
|
||||
return _get( d, x, y );
|
||||
}
|
||||
|
||||
void
|
||||
Grid::del ( int x, int y )
|
||||
{
|
||||
|
@ -318,8 +289,15 @@ Grid::expand ( void )
|
|||
unlock();
|
||||
}
|
||||
|
||||
/** returns true if there is a note event at x,y */
|
||||
bool
|
||||
Grid::is_set ( int x, int y ) const
|
||||
{
|
||||
return _event( x, y, false );
|
||||
}
|
||||
|
||||
void
|
||||
Grid::put ( int x, int y, tick_t l )
|
||||
Grid::put ( int x, int y, tick_t l, int velocity )
|
||||
{
|
||||
|
||||
int xl = ts_to_x( l );
|
||||
|
@ -328,10 +306,8 @@ Grid::put ( int x, int y, tick_t l )
|
|||
event *on = new event;
|
||||
event *off = new event;
|
||||
|
||||
struct dash d;
|
||||
|
||||
// Don't allow overlap (Why not?)
|
||||
if ( get( &d, x, y ) || get( &d, x + xl - 1, y ) )
|
||||
if ( _event( x, y, false ) || _event( x + xl - 1, y, false ) )
|
||||
return;
|
||||
|
||||
DMESSAGE( "put %d,%d", x, y );
|
||||
|
@ -343,18 +319,19 @@ Grid::put ( int x, int y, tick_t l )
|
|||
on->status( event::NOTE_ON );
|
||||
on->note( note );
|
||||
on->timestamp( ts );
|
||||
on->note_velocity( 64 );
|
||||
on->note_velocity( velocity );
|
||||
on->link( off );
|
||||
|
||||
off->status( event::NOTE_OFF );
|
||||
off->note( note );
|
||||
off->timestamp( ts + l );
|
||||
off->note_velocity( 64 );
|
||||
off->note_velocity( velocity );
|
||||
off->link( on );
|
||||
|
||||
_rw->events.insert( on );
|
||||
_rw->events.insert( off );
|
||||
|
||||
|
||||
expand();
|
||||
|
||||
unlock();
|
||||
|
@ -457,6 +434,95 @@ Grid::adj_duration ( int x, int y, int l )
|
|||
|
||||
}
|
||||
|
||||
void
|
||||
Grid::set_duration ( int x, int y, int ex )
|
||||
{
|
||||
if ( ex < 1 )
|
||||
return;
|
||||
|
||||
lock();
|
||||
|
||||
event *e = _event( x, y, true );
|
||||
|
||||
if ( e )
|
||||
{
|
||||
DMESSAGE( "adjusting duration" );
|
||||
|
||||
e->note_duration( x_to_ts( ex ) );
|
||||
|
||||
_rw->events.sort( e->link() );
|
||||
}
|
||||
|
||||
unlock();
|
||||
}
|
||||
|
||||
void
|
||||
Grid::get_note_properties ( int x, int y, note_properties *p ) const
|
||||
{
|
||||
const event *e = _event( x, y, false );
|
||||
|
||||
e->get_note_properties( p );
|
||||
|
||||
p->start = p->start;
|
||||
p->duration = p->duration;
|
||||
p->note = note_to_y( p->note );
|
||||
}
|
||||
|
||||
/* void */
|
||||
/* Grid::set_note_properties ( int x, int y, const note_properties *p ) */
|
||||
/* { */
|
||||
/* lock(); */
|
||||
|
||||
/* const event *e = _event( x, y, true ); */
|
||||
|
||||
/* e->set_note_properties( p ); */
|
||||
|
||||
/* unlock(); */
|
||||
/* } */
|
||||
|
||||
|
||||
|
||||
|
||||
/** if there's a note at grid coordinates x,y, then adjust them to the beginning of the note */
|
||||
int
|
||||
Grid::get_start ( int *x, int *y ) const
|
||||
{
|
||||
const event *e = _event( *x, *y, false );
|
||||
|
||||
if ( e )
|
||||
{
|
||||
*x = ts_to_x( e->timestamp() );
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
Grid::set_end ( int x, int y, int ex )
|
||||
{
|
||||
lock();
|
||||
|
||||
event *e = _event( x, y, true );
|
||||
|
||||
if ( e )
|
||||
{
|
||||
DMESSAGE( "adjusting duration" );
|
||||
|
||||
tick_t ts = x_to_ts( ex );
|
||||
|
||||
if ( ts > e->timestamp() &&
|
||||
ts - e->timestamp() > x_to_ts( 1 ) )
|
||||
{
|
||||
e->note_duration( ts - e->timestamp() );
|
||||
|
||||
_rw->events.sort( e->link() );
|
||||
}
|
||||
}
|
||||
|
||||
unlock();
|
||||
}
|
||||
|
||||
void
|
||||
Grid::toggle_select ( int x, int y )
|
||||
{
|
||||
|
@ -544,6 +610,16 @@ Grid::select_none ( void )
|
|||
unlock();
|
||||
}
|
||||
|
||||
void
|
||||
Grid::select_all ( void )
|
||||
{
|
||||
lock();
|
||||
|
||||
_rw->events.select_all();
|
||||
|
||||
unlock();
|
||||
}
|
||||
|
||||
void
|
||||
Grid::invert_selection ( void )
|
||||
{
|
||||
|
@ -656,13 +732,13 @@ Grid::print ( void ) const
|
|||
void
|
||||
Grid::draw_notes ( draw_note_func_t draw_note, void *userdata ) const
|
||||
{
|
||||
int bx = viewport.x;
|
||||
int by = viewport.y;
|
||||
int bw = viewport.w;
|
||||
int bh = viewport.h;
|
||||
/* int bx = viewport.x; */
|
||||
/* int by = viewport.y; */
|
||||
/* int bw = viewport.w + 100; /\* FIXME: hack *\/ */
|
||||
/* int bh = viewport.h; */
|
||||
|
||||
const tick_t start = x_to_ts( bx );
|
||||
const tick_t end = x_to_ts( bx + bw );
|
||||
/* const tick_t start = x_to_ts( bx ); */
|
||||
/* const tick_t end = x_to_ts( bx + bw ); */
|
||||
|
||||
data *d = const_cast< data *>( _rd );
|
||||
|
||||
|
@ -677,12 +753,14 @@ Grid::draw_notes ( draw_note_func_t draw_note, void *userdata ) const
|
|||
|
||||
const tick_t tse = e->link()->timestamp();
|
||||
|
||||
if ( tse >= start && ts <= end )
|
||||
draw_note( ts_to_x( ts ),
|
||||
note_to_y( e->note() ),
|
||||
ts_to_x( tse - ts ),
|
||||
e->note_velocity(),
|
||||
userdata );
|
||||
/* if ( tse >= start && ts <= end ) */
|
||||
draw_note( // ts_to_x( ts ),
|
||||
ts,
|
||||
note_to_y( e->note() ),
|
||||
tse - ts,
|
||||
e->note_velocity(),
|
||||
e->selected(),
|
||||
userdata );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -768,12 +846,17 @@ Grid::ppqn ( void ) const
|
|||
void
|
||||
Grid::resolution ( unsigned int n )
|
||||
{
|
||||
if ( n < 4 )
|
||||
ASSERTION( "bad resolution: %d", n );
|
||||
/* if ( n < 4 ) */
|
||||
/* ASSERTION( "bad resolution: %d", n ); */
|
||||
|
||||
_ppqn = n / 4;
|
||||
// _ppqn = n / 4;
|
||||
_ppqn = n;
|
||||
DMESSAGE( "%d setting resolution to %d", n, _ppqn );
|
||||
|
||||
/* ensure that the correct number of bars are in the viewport */
|
||||
|
||||
viewport.w = _ppqn * _bpb * 2;
|
||||
|
||||
signal_events_change();
|
||||
|
||||
signal_settings_change();
|
||||
|
|
|
@ -19,9 +19,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "event.H"
|
||||
#include "event_list.H"
|
||||
#include "dash.H"
|
||||
#include <MIDI/event.H>
|
||||
#include <MIDI/event_list.H>
|
||||
#include "const.h"
|
||||
#include "instrument.H"
|
||||
|
||||
|
@ -48,7 +47,7 @@ struct data {
|
|||
|
||||
tick_t length;
|
||||
int state;
|
||||
event_list events;
|
||||
MIDI::event_list events;
|
||||
|
||||
data( void )
|
||||
{
|
||||
|
@ -107,7 +106,7 @@ protected:
|
|||
char *_notes;
|
||||
char *_name;
|
||||
int _number;
|
||||
|
||||
|
||||
bool _suspend_update;
|
||||
|
||||
unsigned int _bpb; /* beats per bar */
|
||||
|
@ -131,9 +130,8 @@ protected:
|
|||
list <data *> _history;
|
||||
|
||||
void _remove_marked ( void );
|
||||
event * _event ( int x, int y, bool write ) const;
|
||||
MIDI::event * _event ( int x, int y, bool write ) const;
|
||||
bool _delete ( int x, int y );
|
||||
bool _get ( struct dash *d, int x, int y ) const;
|
||||
void _link ( void );
|
||||
void _relink ( void );
|
||||
void _fix_length ( void );
|
||||
|
@ -145,7 +143,7 @@ private:
|
|||
|
||||
public:
|
||||
|
||||
typedef void draw_note_func_t ( int x, int y, int l, int velocity, void *userdata );
|
||||
typedef void draw_note_func_t ( tick_t x, int y, tick_t l, int velocity, int selected, void *userdata );
|
||||
|
||||
void draw_notes ( draw_note_func_t draw_note, void *userdata ) const;
|
||||
|
||||
|
@ -158,10 +156,12 @@ public:
|
|||
virtual ~Grid ( void );
|
||||
Grid ( const Grid &rhs );
|
||||
|
||||
virtual bool velocity_sensitive ( void ) const { return true; }
|
||||
|
||||
int y_to_note ( int y ) const;
|
||||
int note_to_y ( int n ) const;
|
||||
tick_t x_to_ts ( uint x ) const;
|
||||
uint ts_to_x ( tick_t ts ) const;
|
||||
tick_t x_to_ts ( tick_t x ) const;
|
||||
tick_t ts_to_x ( tick_t ts ) const;
|
||||
|
||||
virtual Grid * create ( void ) = 0;
|
||||
virtual Grid * clone ( void ) = 0;
|
||||
|
@ -170,17 +170,20 @@ public:
|
|||
|
||||
virtual Grid * by_number ( int n ) const = 0;
|
||||
|
||||
virtual void put ( int x, int y, tick_t l );
|
||||
virtual void put ( int x, int y, tick_t l, int velocity = 64 );
|
||||
virtual bool is_set ( int x, int y ) const;
|
||||
|
||||
void lock ( void );
|
||||
void unlock ( void );
|
||||
void clear ( void );
|
||||
int get ( struct dash *d, int x, int y ) const;
|
||||
void del ( int x, int y );
|
||||
void adj_velocity ( int x, int y, int n );
|
||||
void adj_duration ( int x, int y, int l );
|
||||
void set_duration ( int x, int y, int l );
|
||||
void set_end ( int x, int y, int l );
|
||||
int get_start ( int *x, int *y ) const;
|
||||
void move ( int x, int y, int nx, int ny );
|
||||
void record_event ( event *e );
|
||||
void record_event ( MIDI::event *e );
|
||||
tick_t index ( void ) const;
|
||||
bool playing ( void ) const;
|
||||
|
||||
|
@ -219,6 +222,7 @@ public:
|
|||
void select ( int start, int end, int t, int b );
|
||||
void delete_time ( int start, int end );
|
||||
void select_none ( void );
|
||||
void select_all ( void );
|
||||
void invert_selection ( void );
|
||||
|
||||
void resolution ( unsigned int n );
|
||||
|
@ -228,11 +232,19 @@ public:
|
|||
void draw ( Canvas *c, int bx, int by, int bw, int bh );
|
||||
void print ( void ) const;
|
||||
|
||||
event_list * events ( void ) const;
|
||||
void events ( const event_list * el );
|
||||
MIDI::event_list * events ( void ) const;
|
||||
void events ( const MIDI::event_list * el );
|
||||
|
||||
void get_note_properties ( int x, int y, MIDI::note_properties *p ) const;
|
||||
|
||||
virtual tick_t default_length ( void ) const
|
||||
{
|
||||
return PPQN;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
inline int
|
||||
Grid::y_to_note ( int y ) const
|
||||
{
|
||||
|
@ -246,14 +258,14 @@ Grid::note_to_y ( int n ) const
|
|||
}
|
||||
|
||||
inline tick_t
|
||||
Grid::x_to_ts ( unsigned int x ) const
|
||||
Grid::x_to_ts ( tick_t x ) const
|
||||
{
|
||||
return (x * PPQN) / _ppqn;
|
||||
|
||||
// return x * (PPQN / _ppqn);
|
||||
}
|
||||
|
||||
inline unsigned int
|
||||
inline tick_t
|
||||
Grid::ts_to_x ( tick_t ts ) const
|
||||
{
|
||||
return (ts * _ppqn) / PPQN;
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
|
||||
|
||||
all:
|
||||
@ make -s -C ..
|
|
@ -1,105 +0,0 @@
|
|||
|
||||
/*******************************************************************************/
|
||||
/* Copyright (C) 2007-2008 Jonathan Moore Liles */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it and/or modify it */
|
||||
/* under the terms of the GNU General Public License as published by the */
|
||||
/* Free Software Foundation; either version 2 of the License, or (at your */
|
||||
/* option) any later version. */
|
||||
/* */
|
||||
/* This program is distributed in the hope that it will be useful, but WITHOUT */
|
||||
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
|
||||
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
|
||||
/* more details. */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General Public License along */
|
||||
/* with This program; see the file COPYING. If not,write to the Free Software */
|
||||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
/*******************************************************************************/
|
||||
|
||||
/* This file contains ALL platform specific drawing code required by the canvas */
|
||||
|
||||
#include "ui.H"
|
||||
#include "draw.H"
|
||||
|
||||
#include "../common.h"
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "../canvas.H"
|
||||
|
||||
struct color_table {
|
||||
int state;
|
||||
unsigned char r, g, b;
|
||||
};
|
||||
|
||||
struct color_table color_defs[] = {
|
||||
{ EMPTY, 18, 18, 18 },
|
||||
{ FULL, 255, 69, 0 },
|
||||
{ PARTIAL, 0, 0, 0 },
|
||||
{ CONTINUED, 80, 80, 80 },
|
||||
{ LINE, 10, 10, 10 },
|
||||
{ HIT, 255, 255, 255 },
|
||||
{ PLAYHEAD, 10, 69, 10 },
|
||||
{ SELECTED, 255, 10, 255 },
|
||||
};
|
||||
|
||||
Fl_Color *state_colors;
|
||||
|
||||
Fl_Color velocity_colors[128];
|
||||
Fl_Color velocity2_colors[128];
|
||||
|
||||
bool draw_borders = 1;
|
||||
|
||||
void
|
||||
init_colors ( void )
|
||||
{
|
||||
unsigned int i;
|
||||
/* velocity colors */
|
||||
|
||||
for ( i = 128; i--; )
|
||||
{
|
||||
// velocity_colors[i] = fl_color_average( FL_GRAY, fl_rgb_color( i * 2, 255 - i * 2, 32 ), 0.4 );
|
||||
// velocity_colors[i] = fl_rgb_color( i * 2, 0, 0 );
|
||||
velocity_colors[i] = fl_rgb_color( i, 0, 0 );
|
||||
velocity2_colors[i] = fl_color_average( FL_WHITE, velocity_colors[i], 0.5 );
|
||||
}
|
||||
|
||||
state_colors = (Fl_Color*)malloc(sizeof( Fl_Color ) * MAX_STATE );
|
||||
|
||||
for ( i = elementsof( color_defs ); i--; )
|
||||
{
|
||||
state_colors[ color_defs[i].state ] = fl_rgb_color( color_defs[i].r,
|
||||
color_defs[i].g,
|
||||
color_defs[i].b );
|
||||
}
|
||||
}
|
||||
|
||||
extern UI *ui;
|
||||
|
||||
static
|
||||
void
|
||||
clear_status ( void * )
|
||||
{
|
||||
ui->status->label( NULL );
|
||||
}
|
||||
|
||||
/** inform the user of something via a status bar */
|
||||
void
|
||||
gui_status ( const char *fmt, ... )
|
||||
{
|
||||
va_list args;
|
||||
|
||||
static char pat[256];
|
||||
|
||||
if ( fmt )
|
||||
{
|
||||
va_start( args, fmt );
|
||||
vsnprintf( pat, 256, fmt, args );
|
||||
va_end( args );
|
||||
}
|
||||
|
||||
ui->status->label( pat );
|
||||
|
||||
Fl::add_timeout( 5.0f, clear_status );
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
/* canvas node states */
|
||||
enum {
|
||||
/* real */
|
||||
EMPTY, /* nothing */
|
||||
FULL, /* dot or dash head */
|
||||
PARTIAL,
|
||||
CONTINUED, /* dash tail */
|
||||
SELECTED,
|
||||
/* virtual */
|
||||
HIT, /* playhead hit */
|
||||
LINE, /* beat line */
|
||||
PLAYHEAD,
|
||||
MAX_STATE,
|
||||
};
|
||||
|
||||
#define MAX_REAL_STATE HIT
|
||||
|
||||
#define STATE_MASK 0x0F
|
||||
#define STATE_FLAG_MASK (~ (STATE_MASK) )
|
||||
|
||||
/* flags */
|
||||
enum {
|
||||
F_PLAYHEAD = 1 << 0, /* playhead is on item */
|
||||
F_P1 = 1 << 1,
|
||||
F_P2 = 1 << 2,
|
||||
F_SELECTION = 1 << 3 /* item is part of the selection box */
|
||||
};
|
||||
|
||||
|
||||
void init_colors ( void );
|
||||
void gui_status ( const char *fmt, ... );
|
|
@ -28,6 +28,15 @@ decl {\#include "../grid.H"} {private local
|
|||
decl {\#include "../scale.H"} {private local
|
||||
}
|
||||
|
||||
decl {\#include <MIDI/event.H>} {public global
|
||||
}
|
||||
|
||||
decl {\#include <MIDI/event_list.H>} {selected public global
|
||||
}
|
||||
|
||||
decl {using namespace MIDI;} {private local
|
||||
}
|
||||
|
||||
decl {extern Fl_Color velocity_colors[];} {private local
|
||||
}
|
||||
|
||||
|
@ -40,9 +49,9 @@ class Event_Editor {open
|
|||
}
|
||||
decl {Grid *_grid;} {private local
|
||||
}
|
||||
decl {event_list *_old;} {private local
|
||||
decl {MIDI::event_list *_old;} {private local
|
||||
}
|
||||
decl {event_list *_el;} {private local
|
||||
decl {MIDI::event_list *_el;} {private local
|
||||
}
|
||||
decl {int _y;} {private local
|
||||
}
|
||||
|
@ -61,10 +70,9 @@ _el = _old = NULL;
|
|||
o->hide();
|
||||
|
||||
Fl::delete_widget( o );} open
|
||||
xywh {966 99 655 805} type Double resizable
|
||||
xywh {968 122 655 805} type Double resizable
|
||||
code0 {\#include "event_edit.H"}
|
||||
code1 {\#include "../grid.H"}
|
||||
code2 {\#include "../event_list.H"} modal size_range {0 0 659 803} visible
|
||||
code1 {\#include "../grid.H"} modal size_range {0 0 659 803} visible
|
||||
} {
|
||||
Fl_Scroll {} {
|
||||
label {Event List} open
|
||||
|
@ -192,7 +200,7 @@ update_widgets();} {}
|
|||
code {int i = 0;
|
||||
if ( ! _el->empty() )
|
||||
|
||||
for ( event* e = (*_el)[0]; e = e->next(); i++ )
|
||||
for ( event* e = (*_el)[0]; ( e = e->next() ); i++ )
|
||||
{
|
||||
Event_Widget *ew;
|
||||
|
||||
|
@ -253,9 +261,8 @@ while( w->shown() )
|
|||
}
|
||||
|
||||
widget_class Event_Widget {user_data_type {void *} open
|
||||
xywh {943 216 590 30} type Single
|
||||
code0 {\#include "../event.H"}
|
||||
code1 {_event = NULL;}
|
||||
xywh {945 239 590 30} type Single
|
||||
code0 {_event = NULL;}
|
||||
class Fl_Group size_range {400 24 0 24} visible
|
||||
} {
|
||||
decl {static const Fl_Color note_color = FL_BLACK;} {private local
|
||||
|
@ -270,11 +277,11 @@ widget_class Event_Widget {user_data_type {void *} open
|
|||
}
|
||||
decl {static const Fl_Color pitch_color = FL_GREEN} {private local
|
||||
}
|
||||
decl {event *_event;} {private local
|
||||
decl {MIDI::event *_event;} {private local
|
||||
}
|
||||
decl {Fl_Group *tab;} {private local
|
||||
}
|
||||
Function {ev( event * e )} {open return_type void
|
||||
Function {ev( MIDI::event * e )} {open return_type void
|
||||
} {
|
||||
code {if ( e && ( _event == NULL ) )
|
||||
activate();
|
||||
|
@ -374,7 +381,7 @@ name->redraw();
|
|||
|
||||
// redraw();} {}
|
||||
}
|
||||
Function {ev( void )} {open return_type {event *}
|
||||
Function {ev( void )} {open return_type {MIDI::event *}
|
||||
} {
|
||||
code {return _event;} {}
|
||||
}
|
||||
|
@ -491,7 +498,7 @@ do_callback();}
|
|||
Fl_Slider {} {
|
||||
label {Pressure:}
|
||||
user_data this
|
||||
callback cb_lsb selected
|
||||
callback cb_lsb
|
||||
xywh {359 0 230 24} type {Horz Fill} align 4 when 4 maximum 127 step 1
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,347 +0,0 @@
|
|||
|
||||
/*******************************************************************************/
|
||||
/* Copyright (C) 2007-2008 Jonathan Moore Liles */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it and/or modify it */
|
||||
/* under the terms of the GNU General Public License as published by the */
|
||||
/* Free Software Foundation; either version 2 of the License, or (at your */
|
||||
/* option) any later version. */
|
||||
/* */
|
||||
/* This program is distributed in the hope that it will be useful, but WITHOUT */
|
||||
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
|
||||
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
|
||||
/* more details. */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General Public License along */
|
||||
/* with This program; see the file COPYING. If not,write to the Free Software */
|
||||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
/*******************************************************************************/
|
||||
|
||||
#include <cstring>
|
||||
|
||||
/* system */
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../non.H"
|
||||
#include "draw.H"
|
||||
#include "../common.h"
|
||||
|
||||
#include "ui.H"
|
||||
#include "../transport.H"
|
||||
|
||||
extern UI *ui;
|
||||
|
||||
void
|
||||
async_exec ( const char *cmd )
|
||||
{
|
||||
if ( fork() )
|
||||
{
|
||||
printf( "Executed command \"%s\"\n", cmd );
|
||||
return;
|
||||
}
|
||||
|
||||
system( cmd );
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int
|
||||
canvas_input_callback ( O_Canvas *widget, Canvas *c, int m )
|
||||
{
|
||||
// MESSAGE( "Hello, my name is %s", widget->parent()->label() );
|
||||
|
||||
int ow, oh;
|
||||
|
||||
int x, y;
|
||||
int processed = 1;
|
||||
|
||||
x = Fl::event_x();
|
||||
y = Fl::event_y();
|
||||
|
||||
|
||||
ow = c->grid()->viewport.w;
|
||||
oh = c->grid()->viewport.h;
|
||||
|
||||
switch ( m )
|
||||
{
|
||||
case FL_KEYBOARD:
|
||||
{
|
||||
|
||||
/* if ( Fl::event_state() & FL_ALT || Fl::event_state() & FL_CTRL ) */
|
||||
/* // this is more than a simple keypress. */
|
||||
/* return 0; */
|
||||
|
||||
|
||||
if ( Fl::event_state() & FL_CTRL )
|
||||
{
|
||||
switch ( Fl::event_key() )
|
||||
{
|
||||
case FL_Delete:
|
||||
c->delete_time();
|
||||
break;
|
||||
case FL_Insert:
|
||||
c->insert_time();
|
||||
break;
|
||||
case FL_Right:
|
||||
c->pan( TO_NEXT_NOTE, 0 );
|
||||
break;
|
||||
case FL_Left:
|
||||
c->pan( TO_PREV_NOTE, 0 );
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
if ( Fl::event_state() & FL_ALT )
|
||||
return 0;
|
||||
|
||||
switch ( Fl::event_key() )
|
||||
{
|
||||
case FL_Left:
|
||||
c->pan( LEFT, 1 );
|
||||
break;
|
||||
case FL_Right:
|
||||
c->pan( RIGHT, 1 );
|
||||
break;
|
||||
case FL_Up:
|
||||
c->pan( UP, 1 );
|
||||
break;
|
||||
case FL_Down:
|
||||
c->pan( DOWN, 1 );
|
||||
break;
|
||||
case FL_Delete:
|
||||
if ( Fl::event_state() & FL_SHIFT )
|
||||
c->grid()->clear();
|
||||
else
|
||||
c->grid()->delete_selected();
|
||||
break;
|
||||
default:
|
||||
/* have to do this to get shifted keys */
|
||||
switch ( *Fl::event_text() )
|
||||
{
|
||||
case 'f':
|
||||
c->pan( TO_PLAYHEAD, 0 );
|
||||
break;
|
||||
case 'r':
|
||||
c->select_range();
|
||||
break;
|
||||
case 'q':
|
||||
c->grid()->select_none();
|
||||
break;
|
||||
case 'i':
|
||||
c->invert_selection();
|
||||
break;
|
||||
case '1':
|
||||
c->h_zoom( 2.0f );
|
||||
break;
|
||||
case '2':
|
||||
c->h_zoom( 0.5f );
|
||||
break;
|
||||
case '3':
|
||||
c->v_zoom( 2.0f );
|
||||
break;
|
||||
case '4':
|
||||
c->v_zoom( 0.5f );
|
||||
break;
|
||||
case ' ':
|
||||
transport.toggle();
|
||||
break;
|
||||
case '[':
|
||||
{
|
||||
Grid *g = NULL;
|
||||
|
||||
#define IS_PATTERN (widget->parent() == ui->pattern_tab)
|
||||
#define IS_PHRASE (widget->parent() == ui->phrase_tab)
|
||||
#define IS_SEQUENCE (widget->parent() == ui->sequence_tab)
|
||||
|
||||
/* is there no nicer way to do this shit in c++? */
|
||||
g = c->grid()->by_number( c->grid()->number() - 1 );
|
||||
|
||||
if ( g )
|
||||
{
|
||||
c->grid( g );
|
||||
processed = 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ']':
|
||||
{
|
||||
Grid *g = NULL;
|
||||
|
||||
/* is there no nicer way to do this shit in c++? */
|
||||
g = c->grid()->by_number( c->grid()->number() + 1 );
|
||||
|
||||
if ( g )
|
||||
{
|
||||
c->grid( g );
|
||||
processed = 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '<':
|
||||
c->move_selected( LEFT, 1 );
|
||||
break;
|
||||
case '>':
|
||||
c->move_selected( RIGHT, 1 );
|
||||
break;
|
||||
case ',':
|
||||
c->move_selected( UP, 1 );
|
||||
break;
|
||||
case '.':
|
||||
c->move_selected( DOWN, 1 );
|
||||
break;
|
||||
case 'C':
|
||||
c->crop();
|
||||
break;
|
||||
case 'c':
|
||||
{
|
||||
Grid *g = c->grid()->create();
|
||||
|
||||
if ( g )
|
||||
{
|
||||
c->grid( g );
|
||||
|
||||
ui->update_sequence_widgets();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 'd':
|
||||
{
|
||||
MESSAGE( "duplicating thing" );
|
||||
c->grid( c->grid()->clone() );
|
||||
|
||||
// number of phrases may have changed.
|
||||
ui->update_sequence_widgets();
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
case 'D':
|
||||
c->duplicate_range();
|
||||
break;
|
||||
case 't':
|
||||
c->grid()->trim();
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
c->grid()->mode( c->grid()->mode() == MUTE ? PLAY : MUTE );
|
||||
break;
|
||||
case 's':
|
||||
c->grid()->mode( c->grid()->mode() == SOLO ? PLAY : SOLO );
|
||||
break;
|
||||
default:
|
||||
processed = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FL_PUSH:
|
||||
{
|
||||
switch ( Fl::event_button() )
|
||||
{
|
||||
case 1:
|
||||
int note;
|
||||
if ( ( note = c->is_row_name( x, y ) ) >= 0 )
|
||||
{
|
||||
DMESSAGE( "click on row %d", note );
|
||||
Instrument *i = ((pattern *)c->grid())->mapping.instrument();
|
||||
|
||||
if ( i )
|
||||
{
|
||||
ui->edit_instrument_row( i, note );
|
||||
|
||||
c->changed_mapping();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( Fl::event_state() & FL_SHIFT )
|
||||
{
|
||||
c->start_cursor( x, y );
|
||||
break;
|
||||
}
|
||||
|
||||
if ( IS_PATTERN && Fl::event_state() & ( FL_ALT | FL_CTRL ) )
|
||||
c->randomize_row( y );
|
||||
else
|
||||
c->set( x, y );
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if ( Fl::event_state() & FL_SHIFT )
|
||||
{
|
||||
c->end_cursor( x, y );
|
||||
break;
|
||||
}
|
||||
|
||||
c->unset( x, y );
|
||||
break;
|
||||
case 2:
|
||||
c->select( x, y );
|
||||
break;
|
||||
default:
|
||||
processed = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FL_RELEASE:
|
||||
break;
|
||||
case FL_DRAG:
|
||||
break;
|
||||
/* case FL_DRAG: */
|
||||
/* { */
|
||||
/* if ( ! lmb_down ) */
|
||||
/* break; */
|
||||
|
||||
/* // c->grid()->move( x, y, nx ); */
|
||||
/* break; */
|
||||
/* } */
|
||||
case FL_MOUSEWHEEL:
|
||||
{
|
||||
if ( Fl::event_state() & FL_CTRL )
|
||||
c->adj_length( x, y, (0 - Fl::event_dy()) );
|
||||
else if ( Fl::event_state() & FL_ALT )
|
||||
c->adj_color( x, y, (0 - Fl::event_dy()) * 5 );
|
||||
else if ( Fl::event_state() & FL_SHIFT )
|
||||
{
|
||||
if ( Fl::event_dy() > 0 )
|
||||
{
|
||||
c->pan( RIGHT, Fl::event_dy() * 5 );
|
||||
}
|
||||
else
|
||||
{
|
||||
c->pan( LEFT, 0 - Fl::event_dy() * 5 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( Fl::event_dy() > 0 )
|
||||
{
|
||||
c->pan( DOWN, Fl::event_dy() * 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
c->pan( UP, (0 - Fl::event_dy()) * 1 );
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
processed = 0;
|
||||
}
|
||||
|
||||
int nw, nh;
|
||||
nw = c->grid()->viewport.w;
|
||||
nh = c->grid()->viewport.h;
|
||||
|
||||
// layout of canvas changed... requires clearing.
|
||||
if ( oh != nh || ow != nw )
|
||||
return 3;
|
||||
|
||||
return processed;
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "../canvas.H"
|
||||
#include "../common.h"
|
||||
|
||||
class O_Canvas;
|
||||
|
||||
void disp_message ( char *s );
|
||||
void async_exec ( const char *cmd );
|
||||
int canvas_input_callback ( O_Canvas *widget, Canvas *c, int m );
|
||||
int disp_init ( int argc, char **argv );
|
File diff suppressed because it is too large
Load Diff
|
@ -33,8 +33,12 @@
|
|||
|
||||
|
||||
#include <list>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <MIDI/event.H>
|
||||
using namespace MIDI;
|
||||
|
||||
using std::list;
|
||||
using std::string;
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include <list>
|
||||
using std::list;
|
||||
|
||||
#include "event.H"
|
||||
#include <MIDI/midievent.H>
|
||||
|
||||
struct i_map {
|
||||
char *name;
|
||||
|
@ -55,7 +55,7 @@ public:
|
|||
void note_name ( int n, char *s );
|
||||
|
||||
/* inspection */
|
||||
bool translate ( midievent *e ) const;
|
||||
bool translate ( MIDI::midievent *e ) const;
|
||||
const char * note_name ( int n ) const;
|
||||
int height ( void ) const;
|
||||
const char * name ( void ) const;
|
||||
|
|
|
@ -32,7 +32,10 @@
|
|||
#include "transport.H"
|
||||
#include "pattern.H"
|
||||
#include "phrase.H"
|
||||
#include "event_list.H"
|
||||
#include <MIDI/event_list.H>
|
||||
#include <MIDI/midievent.H>
|
||||
|
||||
using namespace MIDI;
|
||||
|
||||
#ifdef JACK_MIDI_PROTO_API
|
||||
/* correct for prototype version of API */
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
|
||||
#include <jack/jack.h>
|
||||
|
||||
#include <MIDI/midievent.H>
|
||||
#include "common.h"
|
||||
|
||||
enum { CONTROL, PERFORMANCE };
|
||||
|
||||
class midievent;
|
||||
|
||||
bool midi_input_event ( int port, midievent *e );
|
||||
bool midi_input_event ( int port, MIDI::midievent *e );
|
||||
bool midi_is_active ( void );
|
||||
midievent * midi_input_event ( int port );
|
||||
void midi_output_event ( int port, const midievent *e );
|
||||
void midi_output_event ( int port, const midievent *e, tick_t duration );
|
||||
MIDI::midievent * midi_input_event ( int port );
|
||||
void midi_output_event ( int port, const MIDI::midievent *e );
|
||||
void midi_output_event ( int port, const MIDI::midievent *e, tick_t duration );
|
||||
void midi_all_sound_off ( void );
|
||||
const char * midi_init ( const char *name );
|
||||
void midi_shutdown ( void );
|
||||
void midi_output_immediate_event ( int port, const midievent *e );
|
||||
void midi_output_immediate_event ( int port, const MIDI::midievent *e );
|
||||
|
|
|
@ -36,8 +36,6 @@
|
|||
|
||||
const double NSM_CHECK_INTERVAL = 0.25f;
|
||||
|
||||
Canvas *pattern_c, *phrase_c, *trigger_c;
|
||||
|
||||
sequence *playlist;
|
||||
|
||||
global_settings config;
|
||||
|
@ -59,10 +57,6 @@ quit ( void )
|
|||
|
||||
delete ui;
|
||||
|
||||
delete pattern_c;
|
||||
delete phrase_c;
|
||||
delete trigger_c;
|
||||
|
||||
midi_all_sound_off();
|
||||
|
||||
// wait for it...
|
||||
|
@ -81,13 +75,14 @@ clear_song ( void )
|
|||
{
|
||||
// song.filename = NULL;
|
||||
|
||||
pattern_c->grid( NULL );
|
||||
phrase_c->grid( NULL );
|
||||
ui->pattern_canvas_widget->grid( NULL );
|
||||
ui->phrase_canvas_widget->grid( NULL );
|
||||
|
||||
playlist->reset();
|
||||
playlist->insert( 0, 1 );
|
||||
pattern_c->grid( new pattern );
|
||||
phrase_c->grid( new phrase );
|
||||
|
||||
ui->pattern_canvas_widget->grid( new pattern );
|
||||
ui->phrase_canvas_widget->grid( new phrase );
|
||||
|
||||
song.dirty( false );
|
||||
}
|
||||
|
@ -125,11 +120,11 @@ load_song ( const char *name )
|
|||
|
||||
MESSAGE( "loading song \"%s\"", name );
|
||||
|
||||
Grid *pattern_grid = pattern_c->grid();
|
||||
Grid *phrase_grid = phrase_c->grid();
|
||||
Grid *pattern_grid = ui->pattern_canvas_widget->grid();
|
||||
Grid *phrase_grid = ui->phrase_canvas_widget->grid();
|
||||
|
||||
pattern_c->grid( NULL );
|
||||
phrase_c->grid( NULL );
|
||||
ui->pattern_canvas_widget->grid( NULL );
|
||||
ui->phrase_canvas_widget->grid( NULL );
|
||||
|
||||
if ( ! playlist->load( name ) )
|
||||
{
|
||||
|
@ -137,8 +132,8 @@ load_song ( const char *name )
|
|||
goto failed;
|
||||
}
|
||||
|
||||
pattern_c->grid( pattern::pattern_by_number( 1 ) );
|
||||
phrase_c->grid( phrase::phrase_by_number( 1 ) );
|
||||
ui->pattern_canvas_widget->grid( pattern::pattern_by_number( 1 ) );
|
||||
ui->phrase_canvas_widget->grid( phrase::phrase_by_number( 1 ) );
|
||||
|
||||
song.filename = strdup( name );
|
||||
|
||||
|
@ -148,8 +143,8 @@ load_song ( const char *name )
|
|||
|
||||
failed:
|
||||
|
||||
pattern_c->grid( pattern_grid );
|
||||
phrase_c->grid( phrase_grid );
|
||||
ui->pattern_canvas_widget->grid( pattern_grid );
|
||||
ui->phrase_canvas_widget->grid( phrase_grid );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -237,26 +232,23 @@ main ( int argc, char **argv )
|
|||
|
||||
playlist = new sequence;
|
||||
|
||||
pattern_c = new Canvas(0,0,1,1);
|
||||
phrase_c = new Canvas(0,0,1,1);
|
||||
trigger_c = new Canvas(0,0,1,1);
|
||||
|
||||
nsm = new NSM_Client;
|
||||
|
||||
song.filename = NULL;
|
||||
clear_song();
|
||||
|
||||
pattern::signal_create_destroy.connect( mem_fun( phrase_c, &Canvas::v_zoom_fit ) );
|
||||
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 );
|
||||
|
|
|
@ -20,7 +20,9 @@
|
|||
#include "mapping.H"
|
||||
#include "stdlib.h"
|
||||
#include "common.h"
|
||||
#include <MIDI/midievent.H>
|
||||
|
||||
using namespace MIDI;
|
||||
/* Is C++'s dispatching useless or what? */
|
||||
|
||||
#define IS_INSTRUMENT ( _type == INSTRUMENT )
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "scale.H"
|
||||
#include "instrument.H"
|
||||
#include <MIDI/midievent.H>
|
||||
|
||||
/* C++'s inheritance system falls down dead for this application, so we
|
||||
have to do it backwards, using the base class (Mapping) as an interface
|
||||
|
@ -64,7 +65,7 @@ public:
|
|||
void key ( int n );
|
||||
|
||||
/* inspection */
|
||||
bool translate ( midievent *e ) const;
|
||||
bool translate ( MIDI::midievent *e ) const;
|
||||
const char * note_name ( int n ) const;
|
||||
int velocity ( int n ) const;
|
||||
int key ( void ) const;
|
||||
|
|
|
@ -1,218 +0,0 @@
|
|||
|
||||
/*******************************************************************************/
|
||||
/* Copyright (C) 2008 Jonathan Moore Liles */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it and/or modify it */
|
||||
/* under the terms of the GNU General Public License as published by the */
|
||||
/* Free Software Foundation; either version 2 of the License, or (at your */
|
||||
/* option) any later version. */
|
||||
/* */
|
||||
/* This program is distributed in the hope that it will be useful, but WITHOUT */
|
||||
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
|
||||
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
|
||||
/* more details. */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General Public License along */
|
||||
/* with This program; see the file COPYING. If not,write to the Free Software */
|
||||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
/*******************************************************************************/
|
||||
|
||||
/* raw MIDI events + timestamps. Some support for SysEx */
|
||||
|
||||
#include "common.h"
|
||||
#include "midievent.H"
|
||||
|
||||
static const char *opcode_names[] =
|
||||
{
|
||||
"Note Off",
|
||||
"Note On",
|
||||
"Aftertouch",
|
||||
"Control Change",
|
||||
"Program Change",
|
||||
"Channel Pressure",
|
||||
"Pitch Wheel"
|
||||
};
|
||||
|
||||
midievent::midievent ( void )
|
||||
{
|
||||
_sysex = NULL;
|
||||
_timestamp = 0;
|
||||
_data.status = NOTE_OFF;
|
||||
_data.msb = _data.lsb = 0;
|
||||
}
|
||||
|
||||
midievent::~midievent ( void )
|
||||
{
|
||||
if ( _sysex )
|
||||
delete _sysex;
|
||||
|
||||
_sysex = NULL;
|
||||
}
|
||||
|
||||
int
|
||||
midievent::pitch ( void ) const
|
||||
{
|
||||
return ((_data.msb << 7) | _data.lsb) - 0x2000;
|
||||
}
|
||||
|
||||
void
|
||||
midievent::pitch ( int n )
|
||||
{
|
||||
n += 0x2000;
|
||||
|
||||
_data.lsb = n & 0x7F;
|
||||
_data.msb = (n >> 7) & 0x7F;
|
||||
}
|
||||
|
||||
void
|
||||
midievent::data ( byte_t D1, byte_t D2 )
|
||||
{
|
||||
_data.lsb = D1 & 0x7F;
|
||||
_data.msb = D2 & 0x7F;
|
||||
}
|
||||
|
||||
void
|
||||
midievent::data ( byte_t *D1, byte_t *D2 ) const
|
||||
{
|
||||
*D1 = _data.lsb;
|
||||
*D2 = _data.msb;
|
||||
}
|
||||
|
||||
void
|
||||
midievent::raw ( byte_t *p, int l) const
|
||||
{
|
||||
memcpy( p, &_data, l );
|
||||
}
|
||||
|
||||
int
|
||||
midievent::size ( void ) const
|
||||
{
|
||||
return midievent::event_size( opcode() );
|
||||
}
|
||||
|
||||
void
|
||||
midievent::note_velocity ( int vel )
|
||||
{
|
||||
_data.msb = vel & 0x7F;
|
||||
}
|
||||
|
||||
void
|
||||
midievent::note ( char note )
|
||||
{
|
||||
_data.lsb = note & 0x7F;
|
||||
}
|
||||
|
||||
|
||||
unsigned char
|
||||
midievent::note ( void ) const
|
||||
{
|
||||
return _data.lsb;
|
||||
}
|
||||
|
||||
unsigned char
|
||||
midievent::note_velocity ( void ) const
|
||||
{
|
||||
return _data.msb;
|
||||
}
|
||||
|
||||
bool
|
||||
midievent::is_same_note ( midievent * e ) const
|
||||
{
|
||||
return channel() == e->channel() && note() == e->note();
|
||||
}
|
||||
|
||||
/** get name from opcode */
|
||||
const char *
|
||||
midievent::name ( void ) const
|
||||
{
|
||||
return opcode_names[ (opcode() >> 4) - 8 ];
|
||||
}
|
||||
|
||||
/** get opcode from name */
|
||||
int
|
||||
midievent::name ( const char *name ) const
|
||||
{
|
||||
for ( unsigned int i = elementsof( opcode_names ); i--; )
|
||||
if ( ! strcmp( name, opcode_names[ i ] ) )
|
||||
return (i + 8) << 4;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** print event in hexadecimal */
|
||||
void
|
||||
midievent::print ( void ) const
|
||||
{
|
||||
printf( "[%06ld] %02X %02X %02X\n",
|
||||
_timestamp,
|
||||
_data.status,
|
||||
_data.lsb,
|
||||
_data.msb );
|
||||
}
|
||||
|
||||
/** print event in english/decimal */
|
||||
void
|
||||
midievent::pretty_print ( void ) const
|
||||
{
|
||||
printf(
|
||||
"[%06ld] %-15s c: %2d d1: %3d d2: %3d\n",
|
||||
_timestamp,
|
||||
name(),
|
||||
channel(),
|
||||
_data.lsb,
|
||||
_data.msb );
|
||||
}
|
||||
|
||||
|
||||
/*********/
|
||||
/* Sysex */
|
||||
/*********/
|
||||
|
||||
midievent::sysex::sysex ( void )
|
||||
{
|
||||
_data = NULL;
|
||||
_size = 0;
|
||||
_alloc = 0;
|
||||
}
|
||||
|
||||
midievent::sysex::~sysex ( void )
|
||||
{
|
||||
if ( _data )
|
||||
free( _data );
|
||||
|
||||
_data = NULL;
|
||||
}
|
||||
|
||||
/** add bytes to sysex message */
|
||||
void
|
||||
midievent::sysex::append ( byte_t *data, size_t size )
|
||||
{
|
||||
if ( _size + size > _alloc )
|
||||
_data = (byte_t *)realloc( _data, _alloc += 256 );
|
||||
|
||||
memcpy( data + _size, data, size );
|
||||
|
||||
_size += size;
|
||||
}
|
||||
|
||||
/** return SysEx data */
|
||||
const byte_t *
|
||||
midievent::sysex::data ( void ) const
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
long
|
||||
midievent::sysex::size ( void ) const
|
||||
{
|
||||
return _size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
midievent::operator== ( const midievent &rhs ) const
|
||||
{
|
||||
return _timestamp == rhs._timestamp &&
|
||||
! bcmp( (void*)&_data, (void*)&rhs._data, size() );
|
||||
}
|
|
@ -1,232 +0,0 @@
|
|||
|
||||
/*******************************************************************************/
|
||||
/* Copyright (C) 2008 Jonathan Moore Liles */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it and/or modify it */
|
||||
/* under the terms of the GNU General Public License as published by the */
|
||||
/* Free Software Foundation; either version 2 of the License, or (at your */
|
||||
/* option) any later version. */
|
||||
/* */
|
||||
/* This program is distributed in the hope that it will be useful, but WITHOUT */
|
||||
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
|
||||
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
|
||||
/* more details. */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General Public License along */
|
||||
/* with This program; see the file COPYING. If not,write to the Free Software */
|
||||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
/*******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
/* raw MIDI event + timestamp */
|
||||
class midievent
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
class sysex {
|
||||
size_t _size, _alloc;
|
||||
byte_t *_data;
|
||||
|
||||
public:
|
||||
|
||||
sysex ( void );
|
||||
~sysex ( void );
|
||||
|
||||
void append ( byte_t *data, size_t size );
|
||||
const byte_t * data ( void ) const;
|
||||
long size ( void ) const;
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
sysex *_sysex;
|
||||
|
||||
tick_t _timestamp; /* in ticks */
|
||||
struct {
|
||||
byte_t status, /* full status byte */
|
||||
lsb, /* data 1 */
|
||||
msb; /* data 2 */
|
||||
} _data;
|
||||
|
||||
public:
|
||||
|
||||
static inline int
|
||||
event_size ( byte_t op )
|
||||
{
|
||||
switch ( op )
|
||||
{
|
||||
case NOTE_ON: case NOTE_OFF: case AFTERTOUCH:
|
||||
case CONTROL_CHANGE: case PITCH_WHEEL:
|
||||
return 3;
|
||||
case PROGRAM_CHANGE: case CHANNEL_PRESSURE:
|
||||
return 2;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
/* define MIDI status bytes */
|
||||
enum {
|
||||
STATUS_BIT = 0x80,
|
||||
NOTE_OFF = 0x80,
|
||||
NOTE_ON = 0x90,
|
||||
AFTERTOUCH = 0xA0,
|
||||
CONTROL_CHANGE = 0xB0,
|
||||
PROGRAM_CHANGE = 0xC0,
|
||||
CHANNEL_PRESSURE = 0xD0,
|
||||
PITCH_WHEEL = 0xE0,
|
||||
CLEAR_CHAN_MASK = 0xF0,
|
||||
MIDI_CLOCK = 0xF8,
|
||||
SYSEX = 0xF0,
|
||||
SYSEX_END = 0xF7,
|
||||
META = 0xFF
|
||||
};
|
||||
|
||||
midievent ( void );
|
||||
virtual ~midievent ( void );
|
||||
|
||||
tick_t timestamp ( void ) const;
|
||||
void timestamp ( tick_t time );
|
||||
void status ( byte_t status );
|
||||
byte_t status ( void ) const;
|
||||
void channel ( byte_t channel );
|
||||
byte_t channel ( void ) const;
|
||||
byte_t opcode ( void ) const;
|
||||
void opcode ( byte_t o );
|
||||
void lsb ( byte_t n );
|
||||
void msb ( byte_t n );
|
||||
int lsb ( void ) const;
|
||||
int msb ( void ) const;
|
||||
int pitch ( void ) const;
|
||||
void pitch ( int n );
|
||||
void data ( byte_t D1, byte_t D2 );
|
||||
void data ( byte_t *D1, byte_t *D2 ) const;
|
||||
void raw ( byte_t *p, int l) const;
|
||||
int size ( void ) const;
|
||||
void note_velocity ( int vel );
|
||||
bool is_note_on ( void ) const;
|
||||
bool is_note_off ( void ) const;
|
||||
virtual unsigned char note ( void ) const;
|
||||
virtual void note ( char note );
|
||||
unsigned char note_velocity ( void ) const;
|
||||
bool is_same_note ( midievent * e ) const;
|
||||
const char * name ( void ) const;
|
||||
int name ( const char *name ) const;
|
||||
void print ( void ) const;
|
||||
void pretty_print ( void ) const;
|
||||
|
||||
bool operator< ( const midievent &rhs ) const;
|
||||
bool operator>= ( const midievent &rhs ) const;
|
||||
|
||||
bool operator== ( const midievent &rhs ) const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**********************/
|
||||
/* Inlined accessors */
|
||||
/**********************/
|
||||
|
||||
|
||||
inline tick_t
|
||||
midievent::timestamp ( void ) const
|
||||
{
|
||||
return _timestamp;
|
||||
}
|
||||
|
||||
inline void
|
||||
midievent::timestamp ( tick_t time )
|
||||
{
|
||||
_timestamp = time;
|
||||
}
|
||||
|
||||
inline void
|
||||
midievent::status ( byte_t status )
|
||||
{
|
||||
_data.status = status;
|
||||
}
|
||||
|
||||
inline byte_t
|
||||
midievent::status ( void ) const
|
||||
{
|
||||
return _data.status;
|
||||
}
|
||||
|
||||
inline void
|
||||
midievent::channel ( byte_t channel )
|
||||
{
|
||||
_data.status = (_data.status & 0xF0) | (channel & 0x0F);
|
||||
}
|
||||
|
||||
inline byte_t
|
||||
midievent::channel ( void ) const
|
||||
{
|
||||
return _data.status & 0x0F;
|
||||
}
|
||||
|
||||
inline byte_t
|
||||
midievent::opcode ( void ) const
|
||||
{
|
||||
return _data.status & 0xF0;
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
midievent::opcode ( byte_t opcode )
|
||||
{
|
||||
_data.status = (_data.status & 0x0F) | (opcode & 0xF0);
|
||||
}
|
||||
|
||||
inline void
|
||||
midievent::lsb ( byte_t n )
|
||||
{
|
||||
_data.lsb = n & 0x7F;
|
||||
}
|
||||
|
||||
inline void
|
||||
midievent::msb ( byte_t n )
|
||||
{
|
||||
_data.msb = n & 0x7F;
|
||||
}
|
||||
|
||||
inline int
|
||||
midievent::lsb ( void ) const
|
||||
{
|
||||
return _data.lsb;
|
||||
}
|
||||
|
||||
inline int
|
||||
midievent::msb ( void ) const
|
||||
{
|
||||
return _data.msb;
|
||||
}
|
||||
|
||||
inline bool
|
||||
midievent::is_note_on ( void ) const
|
||||
{
|
||||
return (opcode() == NOTE_ON);
|
||||
}
|
||||
|
||||
inline bool
|
||||
midievent::is_note_off ( void ) const
|
||||
{
|
||||
return (opcode() == NOTE_OFF);
|
||||
}
|
||||
|
||||
inline bool
|
||||
midievent::operator< ( const midievent &rhs ) const
|
||||
{
|
||||
return _timestamp < rhs._timestamp;
|
||||
}
|
||||
|
||||
inline bool
|
||||
midievent::operator>= ( const midievent &rhs ) const
|
||||
{
|
||||
return _timestamp >= rhs._timestamp;
|
||||
}
|
|
@ -26,6 +26,9 @@
|
|||
#include "transport.H"
|
||||
#include <math.h>
|
||||
|
||||
#include <MIDI/event_list.H>
|
||||
using namespace MIDI;
|
||||
|
||||
event_list pattern::_recorded_events;
|
||||
vector <pattern*> pattern::_patterns;
|
||||
int pattern::_solo;
|
||||
|
@ -276,10 +279,26 @@ pattern::by_number ( int n ) const
|
|||
return pattern::pattern_by_number( n );
|
||||
}
|
||||
|
||||
/** what to do when the row name is pressed */
|
||||
void
|
||||
pattern::row_name_press ( int y )
|
||||
{
|
||||
/* echo note */
|
||||
midievent e;
|
||||
|
||||
e.status( event::NOTE_ON );
|
||||
e.channel( _channel );
|
||||
e.timestamp( default_length() );
|
||||
e.note( y );
|
||||
e.note_velocity( 64 );
|
||||
|
||||
midi_output_immediate_event ( _port, &e );
|
||||
}
|
||||
|
||||
void
|
||||
pattern::put ( int x, int y, tick_t l )
|
||||
{
|
||||
l = l ? l : PPQN * 4 / _note;
|
||||
l = l ? l : default_length();
|
||||
|
||||
Grid::put( x, y, l );
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include "grid.H"
|
||||
#include "canvas.H"
|
||||
#include "mapping.H"
|
||||
// #include "event.H"
|
||||
#include "common.h"
|
||||
|
||||
#include <vector>
|
||||
|
@ -30,7 +29,7 @@ using std::vector;
|
|||
|
||||
class pattern : public Grid
|
||||
{
|
||||
static event_list _recorded_events;
|
||||
static MIDI::event_list _recorded_events;
|
||||
static vector <pattern *> _patterns;
|
||||
static int _solo;
|
||||
static int _pattern_recording;
|
||||
|
@ -68,7 +67,7 @@ public:
|
|||
static pattern * import ( smf *f, int track );
|
||||
|
||||
static pattern * recording ( void );
|
||||
static void record_event ( const midievent *e );
|
||||
static void record_event ( const MIDI::midievent *e );
|
||||
|
||||
pattern * create ( void );
|
||||
pattern * by_number ( int n ) const;
|
||||
|
@ -91,6 +90,7 @@ public:
|
|||
int queue ( void ) const;
|
||||
|
||||
void randomize_row ( int y, int feel, float probability );
|
||||
void row_name_press ( int y );
|
||||
|
||||
int port ( void ) const;
|
||||
void port ( int p );
|
||||
|
@ -112,4 +112,9 @@ public:
|
|||
int ppqn ( void ) const;
|
||||
void ppqn ( int n );
|
||||
|
||||
virtual tick_t default_length ( void ) const
|
||||
{
|
||||
return PPQN * 4 / _note;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -18,12 +18,13 @@
|
|||
/*******************************************************************************/
|
||||
|
||||
#include "phrase.H"
|
||||
#include "gui/draw.H"
|
||||
#include "pattern.H"
|
||||
#include "smf.H"
|
||||
#include "common.h"
|
||||
#include <math.h>
|
||||
|
||||
using namespace MIDI;
|
||||
|
||||
vector <phrase*> phrase::_phrases;
|
||||
signal <void> phrase::signal_create_destroy;
|
||||
|
||||
|
|
|
@ -46,6 +46,8 @@ public:
|
|||
static phrase * phrase_by_number ( int n );
|
||||
static void reset ( void );
|
||||
|
||||
virtual bool velocity_sensitive ( void ) const { return false; }
|
||||
|
||||
phrase *create ( void );
|
||||
phrase * by_number ( int n ) const;
|
||||
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
#include "common.h"
|
||||
|
||||
#include "stdlib.h"
|
||||
#include <MIDI/midievent.H>
|
||||
|
||||
using namespace MIDI;
|
||||
|
||||
/* Define some scales. These don't really need to be stored on
|
||||
disk. Scales don't change that often. */
|
||||
|
@ -189,13 +192,20 @@ const char *
|
|||
Scale::note_name ( int k, int n ) const
|
||||
{
|
||||
/* all the magic is here */
|
||||
static char s[5];
|
||||
|
||||
n %= 12;
|
||||
const int mod_n = n % 12;
|
||||
|
||||
// FIXME: searching is not efficient!
|
||||
for ( int i = _notes; i-- ; )
|
||||
if ( n == (_degrees[ i ] + k) % 12 )
|
||||
return chromatic_names[ n ];
|
||||
if ( mod_n == (_degrees[ i ] + k) % 12 )
|
||||
{
|
||||
snprintf( s, sizeof(s), "%s%i",
|
||||
chromatic_names[ mod_n ],
|
||||
n / 12 );
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
/*******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "event.H"
|
||||
#include <MIDI/midievent.H>
|
||||
|
||||
class Scale
|
||||
{
|
||||
|
@ -41,7 +40,7 @@ public:
|
|||
static const char * chromatic_name ( int n );
|
||||
static int octave ( int n );
|
||||
|
||||
bool translate ( int k, midievent *e ) const;
|
||||
bool translate ( int k, MIDI::midievent *e ) const;
|
||||
int note ( int k, int n ) const;
|
||||
const char * note_name ( int k, int n ) const;
|
||||
const char * name ( void ) const;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "phrase.H"
|
||||
#include "pattern.H"
|
||||
|
||||
using namespace MIDI;
|
||||
|
||||
smf::smf ( void )
|
||||
{
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "grid.H"
|
||||
#include "event.H"
|
||||
|
||||
class pattern;
|
||||
class phrase;
|
||||
|
@ -104,7 +103,7 @@ public:
|
|||
void write_meta_event ( byte_t type, int n );
|
||||
void write_meta_event ( byte_t type, const char *s );
|
||||
|
||||
void write_event ( const midievent *e );
|
||||
void write_event ( const MIDI::midievent *e );
|
||||
void write_header ( int tracks );
|
||||
|
||||
void open_chunk ( const char *id );
|
||||
|
@ -116,7 +115,7 @@ public:
|
|||
|
||||
void cue ( bool b );
|
||||
|
||||
list <midievent> * read_track_events ( tick_t *length );
|
||||
list <MIDI::midievent> * read_track_events ( tick_t *length );
|
||||
|
||||
void write_phrase_info ( const phrase *p );
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
using namespace sigc;
|
||||
|
||||
#include "event.H" // just for tick_t
|
||||
#include <MIDI/types.h> // just for tick_t
|
||||
|
||||
#include <jack/transport.h>
|
||||
|
||||
|
|
|
@ -46,18 +46,13 @@ src/NSM.C
|
|||
src/NSM/Client.C
|
||||
src/canvas.C
|
||||
src/debug.C
|
||||
src/event.C
|
||||
src/event_list.C
|
||||
src/grid.C
|
||||
src/gui/draw.C
|
||||
src/gui/event_edit.fl
|
||||
src/gui/input.C
|
||||
src/gui/ui.fl
|
||||
src/instrument.C
|
||||
src/jack.C
|
||||
src/main.C
|
||||
src/mapping.C
|
||||
src/midievent.C
|
||||
src/pattern.C
|
||||
src/phrase.C
|
||||
src/scale.C
|
||||
|
|
Loading…
Reference in New Issue