687 lines
14 KiB
C
687 lines
14 KiB
C
|
||
/*******************************************************************************/
|
||
/* 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 "pattern.H"
|
||
#include "non.H"
|
||
#include "common.h"
|
||
#include "smf.H"
|
||
|
||
#include "jack.H"
|
||
#include "transport.H"
|
||
|
||
event_list pattern::_recorded_events;
|
||
vector <pattern*> pattern::_patterns;
|
||
int pattern::_solo;
|
||
int pattern::_pattern_recording;
|
||
|
||
signal <void> pattern::signal_create_destroy;
|
||
|
||
pattern::pattern ( void )
|
||
{
|
||
|
||
viewport.h = 32;
|
||
viewport.w = 32;
|
||
|
||
_draw_shape = CIRCLE;
|
||
_channel = _port = 0;
|
||
|
||
_ppqn = 4;
|
||
_bpb = 4;
|
||
_note = 8;
|
||
int _bars = 2;
|
||
|
||
_triggered = false;
|
||
|
||
// we need to reinitalize this.
|
||
data *d = const_cast< data * >( _rd );
|
||
|
||
d->length = x_to_ts( _bpb * _ppqn * _bars );
|
||
|
||
// mapping.open( Mapping::INSTRUMENT, "Default" );
|
||
mapping.open( Mapping::SCALE, "Major" );
|
||
|
||
_add();
|
||
|
||
char *s;
|
||
asprintf( &s, "Pattern %d", number() );
|
||
|
||
name( s );
|
||
}
|
||
|
||
void
|
||
pattern::_add ( void )
|
||
{
|
||
// keep track of all the patterns
|
||
pattern::_patterns.push_back( this );
|
||
_number = patterns();
|
||
|
||
signal_create_destroy();
|
||
}
|
||
|
||
pattern::~pattern ( void )
|
||
{
|
||
DEBUG( "deleting pattern %d", number() );
|
||
signal_create_destroy();
|
||
}
|
||
|
||
/* copy constructor */
|
||
pattern::pattern ( const pattern &rhs ) : Grid( rhs )
|
||
{
|
||
_note = rhs._note;
|
||
_port = rhs._port;
|
||
_channel = rhs._channel;
|
||
|
||
mapping = rhs.mapping;
|
||
|
||
_add();
|
||
}
|
||
|
||
pattern *
|
||
pattern::clone ( void )
|
||
{
|
||
return new pattern( *this );
|
||
}
|
||
|
||
/******************/
|
||
/* Static methods */
|
||
/******************/
|
||
|
||
int
|
||
pattern::solo ( void )
|
||
{
|
||
return pattern::_solo;
|
||
}
|
||
|
||
int
|
||
pattern::patterns ( void )
|
||
{
|
||
return pattern::_patterns.size();
|
||
}
|
||
|
||
// this is the static one
|
||
pattern *
|
||
pattern::pattern_by_number ( int n )
|
||
{
|
||
if ( n <= patterns() && n > 0 )
|
||
{
|
||
return pattern::_patterns[ n - 1 ];
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
/** delete all patterns in preparation for a reload */
|
||
void
|
||
pattern::reset ( void )
|
||
{
|
||
for ( int n = pattern::patterns(); n-- ; )
|
||
{
|
||
delete pattern::_patterns.back();
|
||
pattern::_patterns.pop_back();
|
||
}
|
||
}
|
||
|
||
void
|
||
pattern::record_event ( const midievent *me )
|
||
{
|
||
/* set the events aside in a dedicated list--the recording pattern
|
||
* will decide what to do with them the next time around the
|
||
* loop */
|
||
|
||
/* FIXME: how does the pattern decide when to loop? It seems
|
||
reasonable that /merge/ and /replace/ modes should be bound to
|
||
the previous pattern length, but what about "NEW" mode? Should it
|
||
just use this entire list as a new pattern (of whatever length)
|
||
when recording is halted? */
|
||
|
||
event *e = new event;
|
||
|
||
*e = *me;
|
||
|
||
pattern::_recorded_events.append( e );
|
||
|
||
record_mode_e mode = config.record_mode;
|
||
|
||
if ( mode == OVERWRITE || mode == LAYER )
|
||
{
|
||
pattern *p = pattern::recording();
|
||
|
||
if ( ! p->_cleared )
|
||
{
|
||
|
||
if ( mode == LAYER )
|
||
{
|
||
p->record_stop();
|
||
|
||
p = p->clone();
|
||
|
||
p->record( 0 );
|
||
}
|
||
|
||
p->clear();
|
||
|
||
p->_cleared = true;
|
||
}
|
||
|
||
mode = MERGE;
|
||
}
|
||
|
||
/* let's fill in the pattern 'live' in merge mode. looks a little
|
||
complicated because we have to wait for a note-off before it's
|
||
safe to insert */
|
||
if ( mode == MERGE || mode == NEW )
|
||
{
|
||
|
||
pattern *p = pattern::recording();
|
||
|
||
p->lock();
|
||
|
||
event_list *el = &pattern::_recorded_events;
|
||
|
||
if ( e->is_note_off() )
|
||
{
|
||
event *off = e;
|
||
|
||
for ( event *on = el->last(); on; on = on->prev() )
|
||
{
|
||
if ( on->is_note_on() &&
|
||
on->is_same_note( off ) )
|
||
// &&
|
||
// *on < *e )
|
||
{
|
||
el->unlink( on );
|
||
el->unlink( off );
|
||
|
||
tick_t duration = off->timestamp() - on->timestamp();
|
||
|
||
/* place within loop */
|
||
on->timestamp( ( on->timestamp() - p->_start ) % p->_rw->length );
|
||
|
||
on->link( off );
|
||
on->note_duration( duration );
|
||
|
||
p->_rw->events.mix( on );
|
||
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
if ( ! e->is_note_on() )
|
||
{
|
||
|
||
// if ( ! filter )
|
||
|
||
e->timestamp( e->timestamp() % p->_rw->length );
|
||
|
||
el->unlink( e );
|
||
p->_rw->events.insert( e );
|
||
}
|
||
|
||
p->unlock();
|
||
}
|
||
}
|
||
|
||
pattern *
|
||
pattern::recording ( void )
|
||
{
|
||
return pattern::pattern_by_number( pattern::_pattern_recording );
|
||
}
|
||
|
||
|
||
|
||
/*******************/
|
||
/* Virtual Methods */
|
||
/*******************/
|
||
|
||
/* allows us to create a new pattern/phrase from a base class pointer */
|
||
pattern *
|
||
pattern::create ( void )
|
||
{
|
||
return new pattern;
|
||
}
|
||
|
||
pattern *
|
||
pattern::by_number ( int n ) const
|
||
{
|
||
return pattern::pattern_by_number( n );
|
||
}
|
||
|
||
void
|
||
pattern::put ( int x, int y, tick_t l )
|
||
{
|
||
l = l ? l : PPQN * 4 / _note;
|
||
|
||
Grid::put( x, y, l );
|
||
|
||
if ( ! transport.rolling )
|
||
{
|
||
/* echo note */
|
||
midievent e;
|
||
|
||
e.status( event::NOTE_ON );
|
||
e.channel( _channel );
|
||
e.timestamp( l );
|
||
e.note( y_to_note( y ) );
|
||
e.note_velocity( 64 );
|
||
|
||
midi_output_immediate_event ( _port, &e );
|
||
}
|
||
}
|
||
|
||
const char *
|
||
pattern::row_name ( int r ) const
|
||
{
|
||
return mapping.note_name( y_to_note( r ) );
|
||
}
|
||
|
||
void
|
||
pattern::draw_row_names ( Canvas *c ) const
|
||
{
|
||
for ( int y = 128; y-- ; )
|
||
c->draw_row_name( y, mapping.note_name( y_to_note( y ) ), mapping.velocity( y_to_note( y ) ) );
|
||
}
|
||
|
||
void
|
||
pattern::trigger ( tick_t start, tick_t end )
|
||
{
|
||
if ( start > end )
|
||
ASSERTION( "programming error: invalid loop trigger! (%lu-%lu)", start, end );
|
||
|
||
_start = start;
|
||
_end = end;
|
||
_index = 0;
|
||
}
|
||
|
||
|
||
void
|
||
pattern::stop ( void ) const
|
||
{
|
||
_playing = false;
|
||
|
||
_start = 0;
|
||
_end = 0;
|
||
_index = 0;
|
||
}
|
||
|
||
|
||
void
|
||
pattern::mode ( int n )
|
||
{
|
||
if ( song.play_mode == TRIGGER )
|
||
{
|
||
switch ( n )
|
||
{
|
||
case PLAY:
|
||
_triggered = true;
|
||
break;
|
||
case MUTE:
|
||
_triggered = false;
|
||
break;
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
if ( n == SOLO )
|
||
{
|
||
if ( pattern::_solo )
|
||
((Grid*)pattern::pattern_by_number( pattern::_solo ))->mode( PLAY );
|
||
pattern::_solo = _number;
|
||
Grid::mode( SOLO );
|
||
}
|
||
else
|
||
{
|
||
if ( pattern::_solo == _number )
|
||
pattern::_solo = 0;
|
||
|
||
Grid::mode( n );
|
||
}
|
||
}
|
||
|
||
int
|
||
pattern::mode ( void ) const
|
||
{
|
||
|
||
if ( song.play_mode == TRIGGER )
|
||
{
|
||
if ( ! _triggered )
|
||
return MUTE;
|
||
else
|
||
return PLAY;
|
||
}
|
||
|
||
if ( pattern::_solo )
|
||
{
|
||
if ( pattern::_solo == _number )
|
||
return SOLO;
|
||
else
|
||
return MUTE;
|
||
}
|
||
else
|
||
return Grid::mode();
|
||
}
|
||
|
||
/* WARNING: runs in the RT thread! */
|
||
// output notes from /start/ to /end/ (absolute)
|
||
void
|
||
pattern::play ( tick_t start, tick_t end ) const
|
||
{
|
||
/* get our own copy of this pointer so UI thread can change it. */
|
||
const data *d = const_cast< const data * >(_rd);
|
||
|
||
if ( start > _end )
|
||
{
|
||
stop();
|
||
WARNING( "attempt to play a loop (pattern %d) that has ended (%lu, %lu)", number(), start, _end );
|
||
return;
|
||
}
|
||
else
|
||
if ( end < _start )
|
||
// not ready yet
|
||
return;
|
||
|
||
if ( start < _start )
|
||
start = _start;
|
||
|
||
if ( end > _end )
|
||
end = _end;
|
||
|
||
_playing = true;
|
||
|
||
// where we are in the absolute time
|
||
tick_t tick = start - _start;
|
||
int num_played = tick / d->length;
|
||
tick_t offset = _start + (d->length * num_played);
|
||
|
||
const event *e;
|
||
|
||
_index = tick % d->length;
|
||
|
||
if ( _index < end - start )
|
||
{
|
||
DEBUG( "Triggered pattern %d at tick %lu (ls: %lu, le: %lu, o: %lu)", number(), start, _start, _end, offset );
|
||
|
||
_cleared = false;
|
||
}
|
||
|
||
if ( mode() == MUTE )
|
||
return;
|
||
|
||
try_again:
|
||
|
||
// pattern is empty
|
||
if ( d->events.empty() )
|
||
goto done;
|
||
|
||
for ( e = d->events.first(); e; e = e->next() )
|
||
{
|
||
// MESSAGE( "s[%ld] -> t[%ld] : %ld, len %ld", start, end, e->timestamp(), _length ); // (*e).print();
|
||
|
||
tick_t ts = e->timestamp() + offset;
|
||
|
||
if ( ts >= end )
|
||
goto done;
|
||
|
||
if ( ts >= start )
|
||
{
|
||
midievent me = *e;
|
||
|
||
|
||
// MESSAGE( "timestamp %d, tick %d, ts - start == %lu", e->timestamp(), start,
|
||
// e->timestamp() - start);
|
||
|
||
/* set the channel */
|
||
me.channel( _channel );
|
||
|
||
/* set the in-cycle timestamp */
|
||
me.timestamp ( ts - start );
|
||
|
||
if ( me.is_note_on() )
|
||
{
|
||
if ( mapping.translate( &me ) )
|
||
midi_output_event( _port, &me, 1 + e->note_duration() );
|
||
}
|
||
else
|
||
if ( me.is_note_off() )
|
||
if ( mapping.translate( &me ) )
|
||
midi_output_event( _port, &me, 0 );
|
||
else
|
||
/* any other event type */
|
||
midi_output_event( _port, &me );
|
||
}
|
||
}
|
||
|
||
// ran out of events, but there's still some loop left to play.
|
||
offset += d->length;
|
||
goto try_again;
|
||
|
||
DEBUG( "out of events, resetting to satisfy loop" );
|
||
|
||
done: ;
|
||
|
||
}
|
||
|
||
/* Import /track/ of /f/ as new pattern */
|
||
pattern *
|
||
pattern::import ( smf *f, int track )
|
||
{
|
||
if ( ! f->seek_track( track ) )
|
||
return NULL;
|
||
|
||
pattern *p = new pattern;
|
||
|
||
p->lock();
|
||
|
||
p->load( f );
|
||
|
||
/* file could have any notes in it... Use Chromatic scale to
|
||
ensure all are visible */
|
||
p->mapping.open( Mapping::SCALE, "Chromatic" );
|
||
|
||
p->unlock();
|
||
|
||
p->fit();
|
||
|
||
return p;
|
||
}
|
||
|
||
/** fill pattern from current track of /f/ */
|
||
void
|
||
pattern::load ( smf *f )
|
||
{
|
||
lock();
|
||
|
||
f->read_pattern_info( this );
|
||
|
||
tick_t len;
|
||
|
||
list <midievent> *e = f->read_track_events( &len );
|
||
|
||
/* set channel to channel of first event... */
|
||
if ( e->size() )
|
||
_channel = e->front().channel();
|
||
|
||
/* copy events into pattern */
|
||
_rw->events = *e;
|
||
delete e;
|
||
|
||
if ( len )
|
||
_rw->length = len;
|
||
|
||
unlock();
|
||
|
||
// print();
|
||
}
|
||
|
||
/** save (export) pattern to file /name/ */
|
||
void
|
||
pattern::save ( const char *name ) const
|
||
{
|
||
smf f;
|
||
|
||
/* open for writing */
|
||
f.open( name, smf::WRITE );
|
||
|
||
/* writing SMF 0 track */
|
||
f.write_header( 0 );
|
||
|
||
f.open_track( _name, _number );
|
||
|
||
Grid::dump( &f, _channel, true );
|
||
|
||
f.close_track( length() );
|
||
}
|
||
|
||
/** dump pattern as a track in an already open MIDI file */
|
||
void
|
||
pattern::dump ( smf *f ) const
|
||
{
|
||
f->open_track( _name, _number );
|
||
|
||
f->write_pattern_info( this );
|
||
|
||
Grid::dump( f, _channel, false );
|
||
|
||
f->close_track( length() );
|
||
}
|
||
|
||
|
||
void
|
||
pattern::randomize_row ( int y, int feel, float probability )
|
||
{
|
||
lock();
|
||
|
||
int l = PPQN * 4 / _note;
|
||
|
||
int bx = ts_to_x( _rw->length - l );
|
||
|
||
float *p = (float *)alloca( feel * sizeof( float ) );
|
||
|
||
float prob = probability;
|
||
for ( int i = 0; i < feel; i++ )
|
||
{
|
||
p[i] = prob;
|
||
// reduce probability as we move away from center
|
||
prob *= 0.5;
|
||
}
|
||
|
||
for ( int x = 0; x < bx; x++ )
|
||
{
|
||
float r = ((float)rand()) / RAND_MAX;
|
||
|
||
if ( p[ x % feel ] + r >= 1 )
|
||
put( x, y, l );
|
||
}
|
||
|
||
unlock();
|
||
}
|
||
|
||
/*************/
|
||
/* Recording */
|
||
/*************/
|
||
|
||
void
|
||
pattern::record ( int mode )
|
||
{
|
||
_recording = true;
|
||
pattern::_pattern_recording = _number;
|
||
}
|
||
|
||
void
|
||
pattern::record_stop ( void )
|
||
{
|
||
if ( ! _recording )
|
||
return;
|
||
|
||
_recording = false;
|
||
|
||
if ( config.record_mode == NEW )
|
||
trim();
|
||
|
||
pattern::_recorded_events.clear();
|
||
}
|
||
|
||
|
||
|
||
/*******************************/
|
||
/* Pattern specific accessors. */
|
||
/*******************************/
|
||
|
||
|
||
int
|
||
pattern::port ( void ) const
|
||
{
|
||
return _port;
|
||
}
|
||
|
||
void
|
||
pattern::port ( int p )
|
||
{
|
||
_port = p;
|
||
}
|
||
|
||
int
|
||
pattern::channel ( void ) const
|
||
{
|
||
return _channel;
|
||
}
|
||
|
||
void
|
||
pattern::channel ( int c )
|
||
{
|
||
_channel = c;
|
||
}
|
||
|
||
int
|
||
pattern::note ( void ) const
|
||
{
|
||
return _note;
|
||
}
|
||
|
||
void
|
||
pattern::note ( int n )
|
||
{
|
||
_note = n;
|
||
}
|
||
|
||
|
||
int
|
||
pattern::ppqn ( void ) const
|
||
{
|
||
return _ppqn;
|
||
}
|
||
|
||
void
|
||
pattern::ppqn ( int n )
|
||
{
|
||
_ppqn = n;
|
||
}
|
||
|
||
int
|
||
pattern::key ( void ) const
|
||
{
|
||
return mapping.key();
|
||
}
|
||
|
||
void
|
||
pattern::key ( int k )
|
||
{
|
||
mapping.key( k );
|
||
}
|