Split Disk_Stream into a base class and Playback_DS and Record_DS.

pull/3/head
Jonathan Moore Liles 2008-04-16 03:44:31 -05:00
parent fc2ed291aa
commit fbb4b17dca
17 changed files with 616 additions and 253 deletions

View File

@ -39,7 +39,8 @@ protected:
const char *_filename;
nframes_t _length; /* length of file in samples */
nframes_t _length; /* length of file in samples */
nframes_t _samplerate; /* sample rate */
int _channels;
Peaks *_peaks;
@ -58,7 +59,7 @@ public:
const char *name ( void ) const { return _filename; }
nframes_t length ( void ) const { return _length; }
int channels ( void ) const { return _channels; }
nframes_t samplerate ( void ) const { return _samplerate; }
// Peaks const * peaks ( void ) { return &_peaks; }
virtual bool open ( void ) = 0;
@ -66,6 +67,7 @@ public:
virtual void seek ( nframes_t offset ) = 0;
virtual nframes_t read ( sample_t *buf, int channel, nframes_t len ) = 0;
virtual nframes_t read ( sample_t *buf, int channel, nframes_t start, nframes_t end ) = 0;
virtual nframes_t write ( sample_t *buf, nframes_t len ) = 0;
bool read_peaks( float fpp, nframes_t start, nframes_t end, int *peaks, Peak **pbuf, int *channels );

View File

@ -33,7 +33,6 @@ Audio_File_SF::from_file ( const char *filename )
SNDFILE *in;
SF_INFO si;
Audio_File_SF *c = NULL;
memset( &si, 0, sizeof( si ) );
@ -53,9 +52,10 @@ Audio_File_SF::from_file ( const char *filename )
c = new Audio_File_SF;
c->_current_read = 0;
c->_filename = strdup( filename );
c->_length = si.frames;
c->_channels = si.channels;
c->_filename = strdup( filename );
c->_length = si.frames;
c->_samplerate = si.samplerate;
c->_channels = si.channels;
c->_in = in;
// sf_close( in );
@ -68,6 +68,38 @@ invalid:
return NULL;
}
Audio_File_SF *
Audio_File_SF::create ( const char *filename, nframes_t samplerate, int channels, const char *format )
{
SF_INFO si;
SNDFILE *out;
memset( &si, 0, sizeof( si ) );
si.samplerate = samplerate;
si.channels = channels;
/* FIXME: bogus */
si.format = SF_FORMAT_WAV | SF_FORMAT_PCM_24 | SF_ENDIAN_CPU;
if ( ! ( out = sf_open( filename, SFM_WRITE, &si ) ) )
{
printf( "couldn't create soundfile.\n" );
return NULL;
}
Audio_File_SF *c = new Audio_File_SF;
c->_filename = strdup( filename );
c->_length = 0;
c->_samplerate = samplerate;
c->_channels = channels;
c->_in = out;
return c;
}
bool
Audio_File_SF::open ( void )
{
@ -146,3 +178,12 @@ Audio_File_SF::read ( sample_t *buf, int channel, nframes_t start, nframes_t end
return len;
}
/** write /nframes/ from /buf/ to soundfile. Should be interleaved for
* the appropriate number of channels */
nframes_t
Audio_File_SF::write ( sample_t *buf, nframes_t nframes )
{
return sf_writef_float( _in, buf, nframes );
}

View File

@ -34,11 +34,13 @@ class Audio_File_SF : public Audio_File
public:
static Audio_File_SF *from_file ( const char *filename );
static Audio_File_SF *create ( const char *filename, nframes_t samplerate, int channels, const char *format );
bool open ( void );
void close ( void );
void seek ( nframes_t offset );
nframes_t read ( sample_t *buf, int channel, nframes_t len );
nframes_t read ( sample_t *buf, int channel, nframes_t start, nframes_t end );
nframes_t write ( sample_t *buf, nframes_t nframes );
};

View File

@ -68,15 +68,12 @@ Disk_Stream::Disk_Stream ( Track_Header *th, float frame_rate, nframes_t nframes
size_t bufsize = _total_blocks * nframes * sizeof( sample_t );
/* const int blocks = 64; */
/* const size_t bufsize = (blocks * (nframes * sizeof( sample_t ))) + sizeof( sample_t ); */
for ( int i = channels; i--; )
_rb.push_back( jack_ringbuffer_create( bufsize ) );
sem_init( &_blocks, 0, _total_blocks );
run();
// run();
}
Disk_Stream::~Disk_Stream ( )
@ -109,7 +106,7 @@ Disk_Stream::track ( void )
void
Disk_Stream::run ( void )
{
if ( pthread_create( &_thread, NULL, &Disk_Stream::io_thread, this ) != 0 )
if ( pthread_create( &_thread, NULL, &Disk_Stream::disk_thread, this ) != 0 )
/* error */;
}
@ -121,47 +118,6 @@ Disk_Stream::resize ( nframes_t nframes )
/* FIXME: to something here! */;
}
bool
Disk_Stream::seek_pending ( void )
{
return _pending_seek != (nframes_t)-1;
}
/* THREAD: RT */
/** request that the IO thread perform a seek and rebuffer. This is
called for each Disk_Stream whenever the RT thread determines that
the transport has jumped to a new position. This is called *before*
process. */
void
Disk_Stream::seek ( nframes_t frame )
{
printf( "requesting seek\n" );
if ( seek_pending() )
printf( "seek error, attempt to seek while seek is pending\n" );
_pending_seek = frame;
/* flush buffers */
for ( int i = channels(); i--; )
jack_ringbuffer_read_advance( _rb[ i ], jack_ringbuffer_read_space( _rb[ i ] ) );
/* dirty hack... reset the semaphore. Should we just call sem_init
* again instead? */
/* sem_init( &_blocks, 0, _total_blocks ); */
int n;
sem_getvalue( &_blocks, &n );
n = _total_blocks - n;
while ( n-- )
sem_post( &_blocks );
}
/* void */
/* DIsk_Stream::shutdown ( void ) */
@ -171,45 +127,15 @@ Disk_Stream::seek ( nframes_t frame )
/* static wrapper */
void *
Disk_Stream::io_thread ( void *arg )
Disk_Stream::disk_thread ( void *arg )
{
((Disk_Stream*)arg)->io_thread();
((Disk_Stream*)arg)->disk_thread();
return NULL;
}
/* THREAD: IO */
/** read /nframes/ from the attached track into /buf/ */
void
Disk_Stream::read_block ( sample_t *buf, nframes_t nframes )
{
memset( buf, 0, nframes * sizeof( sample_t ) * channels() );
/* stupid chicken/egg */
if ( ! timeline )
return;
// printf( "IO: attempting to read block @ %lu\n", _frame );
if ( ! track() )
{
// _frame += _nframes;
return;
}
timeline->rdlock();
if ( track()->play( buf, _frame, nframes, channels() ) )
_frame += nframes;
else
/* error */;
timeline->unlock();
}
int
Disk_Stream::output_buffer_percent ( void )
Disk_Stream::buffer_percent ( void )
{
int n;
@ -217,128 +143,3 @@ Disk_Stream::output_buffer_percent ( void )
return 100 - (n * 100 / _total_blocks);
}
/* THREAD: IO */
void
Disk_Stream::io_thread ( void )
{
printf( "IO thread running...\n" );
/* buffer to hold the interleaved data returned by the track reader */
sample_t *buf = new sample_t[ _nframes * channels() ];
const size_t block_size = _nframes * sizeof( sample_t );
while ( wait_for_block() )
{
// printf( "IO: RT thread is ready for more data...\n" );
// printf( "IO: disk buffer is %3d%% full\r", output_buffer_percent() );
// lock(); // for seeking
if ( seek_pending() )
{
printf( "performing seek\n" );
_frame = _pending_seek;
_pending_seek = -1;
/* finish flushing the buffer */
/* for ( int i = channels(); i-- ) */
/* jack_ringbuffer_write_advance( _rb[ i ], jack_ringbuffer_write_space( _rb[ i ] ) ); */
}
/* FIXME: should we not read from disk in larger-than-JACK-buffer blocks? */
read_block( buf, _nframes );
// unlock(); // for seeking
/* deinterleave the buffer and stuff it into the per-channel ringbuffers */
for ( int i = channels(); i--; )
{
while ( jack_ringbuffer_write_space( _rb[ i ] ) < block_size )
{
printf( "IO: disk buffer overrun!\n" );
/* FIXME: is this *really* the right thing to do? */
usleep( 2000 );
}
/* deinterleave direcectly into the ringbuffer to avoid
* unnecessary copying */
jack_ringbuffer_data_t rbd[2];
jack_ringbuffer_get_write_vector( _rb[ i ], rbd );
if ( rbd[ 0 ].len >= _nframes )
/* it'll all fit in one go */
buffer_deinterleave_one_channel( (sample_t*)rbd[ 0 ].buf, buf, i, channels(), _nframes );
else if ( rbd[ 1 ].len )
{
/* there's enough space in the ringbuffer, but it's not contiguous */
/* do the first half */
const nframes_t f = rbd[ 1 ].len / sizeof( sample_t );
buffer_deinterleave_one_channel( (sample_t*)rbd[ 0 ].buf, buf, i, channels(), f );
assert( rbd[ 1 ].len >= (_nframes - f) * sizeof( sample_t ) );
/* do the second half */
buffer_deinterleave_one_channel( (sample_t*)rbd[ 1 ].buf, buf + f, i, channels(), _nframes - f );
}
else
printf( "programming error: expected more space in ringbuffer\n" );
/* buffer_deinterleave_one_channel( (sample_t*)rbd.buf, buf, i, channels(), _nframes ); */
/* jack_ringbuffer_write( _rb[ i ], (char*)cbuf, block_size ); */
jack_ringbuffer_write_advance( _rb[ i ], _nframes * sizeof( sample_t ) );
}
}
printf( "IO thread terminating.\n" );
delete[] buf;
}
/* THREAD: RT */
/** take a single block from the ringbuffers and send it out the
* attached track's ports */
nframes_t
Disk_Stream::process ( nframes_t nframes )
{
const size_t block_size = nframes * sizeof( sample_t );
// printf( "process: %lu %lu %lu\n", _frame, _frame + nframes, nframes );
for ( int i = channels(); i--; )
{
void *buf = _th->output[ i ].buffer( nframes );
if ( jack_ringbuffer_read( _rb[ i ], (char*)buf, block_size ) < block_size )
{
printf( "RT: buffer underrun (disk can't keep up).\n" );
memset( buf, 0, block_size );
/* FIXME: we need to resync somehow */
}
/* /\* testing. *\/ */
/* FILE *fp = fopen( "testing.au", "a" ); */
/* fwrite( buf, block_size, 1, fp ); */
/* fclose( fp ); */
}
block_processed();
/* FIXME: bogus */
return nframes;
}

View File

@ -19,7 +19,7 @@
#pragma once
#include "Port.H" // for nframes_t
#include "types.h"
#include <jack/ringbuffer.h>
#include <semaphore.h>
@ -38,30 +38,30 @@ class Audio_Track;
class Disk_Stream : public Mutex
{
pthread_t _thread;
protected:
Track_Header *_th; /* Track_Header we whould be playing */
pthread_t _thread; /* io thread */
nframes_t _nframes;
nframes_t _frame;
Track_Header *_th; /* Track_Header we belong to */
vector <jack_ringbuffer_t *> _rb;
nframes_t _nframes; /* buffer size */
// jack_ringbuffer_t *_rb; /* One interleaved ringbuffer for all channels */
nframes_t _frame; /* location of disk read */
sem_t _blocks; /* semaphore to wake the IO thread with */
vector < jack_ringbuffer_t * >_rb; /* one ringbuffer for each channel */
int _total_blocks;
sem_t _blocks; /* semaphore to wake the IO thread with */
volatile nframes_t _pending_seek; /* absolute transport position to seek to */
int _total_blocks; /* total number of blocks that we can buffer */
volatile nframes_t _pending_seek; /* absolute transport position to seek to */
volatile int _terminate;
int channels ( void ) const { return _rb.size(); }
Audio_Track * track ( void );
static void *io_thread ( void *arg );
static void *disk_thread ( void *arg );
protected:
@ -77,8 +77,7 @@ protected:
}
}
void read_block ( sample_t *buf, nframes_t nframes );
void io_thread ( void );
virtual void disk_thread ( void ) = 0;
public:
@ -90,11 +89,14 @@ public:
virtual ~Disk_Stream ( );
void resize ( nframes_t nframes );
void seek ( nframes_t frame );
bool seek_pending ( void );
/* void seek ( nframes_t frame ); */
/* bool seek_pending ( void ); */
void run ( void );
nframes_t process ( nframes_t nframes );
int output_buffer_percent ( void );
virtual nframes_t process ( nframes_t nframes ) = 0;
int buffer_percent ( void );
};

View File

@ -13,12 +13,15 @@ SRCS= \
Audio_File_SF.C \
Port.C \
Disk_Stream.C \
dsp.c \
Playback_DS.C \
Record_DS.C \
dsp.C \
Engine.C \
Transport.C \
Loggable.C \
OBJS=$(SRCS:.C=.o)
OBJS:=$(SRCS:.C=.o)
# OBJS:=$(OBJS:.c=.o)
INCLUDES=-I../Engine -I../FL
@ -33,6 +36,8 @@ include ../make.inc
#LIBS:=$(LIBS) -ljack -lpthread
timeline: $(OBJS)
echo $(SRCS) >/dev/stderr
echo $(OBJS) >/dev/stderr
$(CXX) $(CXXFLAGS) $(INCLUDES) $(LIBS) -ljack -lpthread $(OBJS) -o $@
clean:

227
Timeline/Playback_DS.C Normal file
View File

@ -0,0 +1,227 @@
/*******************************************************************************/
/* 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. */
/*******************************************************************************/
/* Handles streaming regions from disk to track outputs. */
/* FIXME: we shouldn't depend on these */
#include "Timeline.H"
#include "Engine.H"
#include "Audio_Track.H"
#include "Track_Header.H"
#include "Port.H"
#include "Playback_DS.H"
#include "dsp.h"
bool
Playback_DS::seek_pending ( void )
{
return _pending_seek != (nframes_t)-1;
}
/* THREAD: RT */
/** request that the IO thread perform a seek and rebuffer. This is
called for each Disk_Stream whenever the RT thread determines that
the transport has jumped to a new position. This is called *before*
process. */
void
Playback_DS::seek ( nframes_t frame )
{
printf( "requesting seek\n" );
if ( seek_pending() )
printf( "seek error, attempt to seek while seek is pending\n" );
_pending_seek = frame;
/* flush buffers */
for ( int i = channels(); i--; )
jack_ringbuffer_read_advance( _rb[ i ], jack_ringbuffer_read_space( _rb[ i ] ) );
/* dirty hack... reset the semaphore. Should we just call sem_init
* again instead? */
/* sem_init( &_blocks, 0, _total_blocks ); */
int n;
sem_getvalue( &_blocks, &n );
n = _total_blocks - n;
while ( n-- )
sem_post( &_blocks );
}
/* THREAD: IO */
/** read /nframes/ from the attached track into /buf/ */
void
Playback_DS::read_block ( sample_t *buf, nframes_t nframes )
{
memset( buf, 0, nframes * sizeof( sample_t ) * channels() );
/* stupid chicken/egg */
if ( ! timeline )
return;
// printf( "IO: attempting to read block @ %lu\n", _frame );
if ( ! track() )
{
// _frame += _nframes;
return;
}
timeline->rdlock();
if ( track()->play( buf, _frame, nframes, channels() ) )
_frame += nframes;
else
/* error */;
timeline->unlock();
}
/* THREAD: IO */
void
Playback_DS::disk_thread ( void )
{
printf( "IO thread running...\n" );
/* buffer to hold the interleaved data returned by the track reader */
sample_t *buf = new sample_t[ _nframes * channels() ];
const size_t block_size = _nframes * sizeof( sample_t );
while ( wait_for_block() )
{
// printf( "IO: RT thread is ready for more data...\n" );
// printf( "IO: disk buffer is %3d%% full\r", output_buffer_percent() );
// lock(); // for seeking
if ( seek_pending() )
{
printf( "performing seek\n" );
_frame = _pending_seek;
_pending_seek = -1;
/* finish flushing the buffer */
/* for ( int i = channels(); i-- ) */
/* jack_ringbuffer_write_advance( _rb[ i ], jack_ringbuffer_write_space( _rb[ i ] ) ); */
}
/* FIXME: should we not read from disk in larger-than-JACK-buffer blocks? */
read_block( buf, _nframes );
// unlock(); // for seeking
/* deinterleave the buffer and stuff it into the per-channel ringbuffers */
for ( int i = channels(); i--; )
{
while ( jack_ringbuffer_write_space( _rb[ i ] ) < block_size )
{
printf( "IO: disk buffer overrun!\n" );
/* FIXME: is this *really* the right thing to do? */
usleep( 2000 );
}
/* deinterleave direcectly into the ringbuffer to avoid
* unnecessary copying */
jack_ringbuffer_data_t rbd[2];
jack_ringbuffer_get_write_vector( _rb[ i ], rbd );
if ( rbd[ 0 ].len >= _nframes )
/* it'll all fit in one go */
buffer_deinterleave_one_channel( (sample_t*)rbd[ 0 ].buf, buf, i, channels(), _nframes );
else if ( rbd[ 1 ].len )
{
/* there's enough space in the ringbuffer, but it's not contiguous */
/* do the first half */
const nframes_t f = rbd[ 1 ].len / sizeof( sample_t );
buffer_deinterleave_one_channel( (sample_t*)rbd[ 0 ].buf, buf, i, channels(), f );
assert( rbd[ 1 ].len >= (_nframes - f) * sizeof( sample_t ) );
/* do the second half */
buffer_deinterleave_one_channel( (sample_t*)rbd[ 1 ].buf, buf + f, i, channels(), _nframes - f );
}
else
printf( "programming error: expected more space in ringbuffer\n" );
/* buffer_deinterleave_one_channel( (sample_t*)rbd.buf, buf, i, channels(), _nframes ); */
/* jack_ringbuffer_write( _rb[ i ], (char*)cbuf, block_size ); */
jack_ringbuffer_write_advance( _rb[ i ], _nframes * sizeof( sample_t ) );
}
}
printf( "IO thread terminating.\n" );
delete[] buf;
}
/* THREAD: RT */
/** take a single block from the ringbuffers and send it out the
* attached track's ports */
nframes_t
Playback_DS::process ( nframes_t nframes )
{
const size_t block_size = nframes * sizeof( sample_t );
// printf( "process: %lu %lu %lu\n", _frame, _frame + nframes, nframes );
for ( int i = channels(); i--; )
{
void *buf = _th->output[ i ].buffer( nframes );
if ( jack_ringbuffer_read( _rb[ i ], (char*)buf, block_size ) < block_size )
{
printf( "RT: buffer underrun (disk can't keep up).\n" );
memset( buf, 0, block_size );
/* FIXME: we need to resync somehow */
}
/* /\* testing. *\/ */
/* FILE *fp = fopen( "testing.au", "a" ); */
/* fwrite( buf, block_size, 1, fp ); */
/* fclose( fp ); */
}
block_processed();
/* FIXME: bogus */
return nframes;
}

40
Timeline/Playback_DS.H Normal file
View File

@ -0,0 +1,40 @@
/*******************************************************************************/
/* 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 "Disk_Stream.H"
class Playback_DS : public Disk_Stream
{
void read_block ( sample_t *buf, nframes_t nframes );
void disk_thread ( void );
public:
Playback_DS ( Track_Header *th, float frame_rate, nframes_t nframes, int channels ) :
Disk_Stream( th, frame_rate, nframes, channels )
{
run();
}
bool seek_pending ( void );
void seek ( nframes_t frame );
nframes_t process ( nframes_t nframes );
};

View File

@ -30,11 +30,14 @@ Port::Port ( jack_port_t *port )
_name = jack_port_name( _port );
}
Port::Port ( const char *name )
Port::Port ( const char *name, direction_e dir )
{
_name = name;
_port = jack_port_register( engine->client(), _name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 );
_port = jack_port_register( engine->client(), _name,
JACK_DEFAULT_AUDIO_TYPE,
dir == Output ? JackPortIsOutput : JackPortIsInput,
0 );
}
Port::~Port ( )
@ -49,6 +52,12 @@ Port::write ( sample_t *buf, nframes_t nframes )
memcpy( buffer( nframes ), buf, nframes * sizeof( sample_t ) );
}
void
Port::read ( sample_t *buf, nframes_t nframes )
{
memcpy( buf, buffer( nframes ), nframes * sizeof( sample_t ) );
}
void *
Port::buffer ( nframes_t nframes )
{

View File

@ -21,24 +21,27 @@
#include <jack/jack.h>
typedef float sample_t;
//typedef jack_nframes_t nframes_t;
#include "types.h"
class Port
{
jack_port_t *_port;
const char *_name;
public:
enum direction_e { Output, Input };
Port ( jack_port_t *port );
Port ( const char *name );
Port ( const char *name, direction_e dir );
~Port ( );
bool connected ( void ) const { return jack_port_connected( _port ); }
const char * name ( void ) const { return _name; }
void write ( sample_t *buf, nframes_t nframes );
void read ( sample_t *buf, nframes_t nframes );
void *buffer ( nframes_t nframes );
};

155
Timeline/Record_DS.C Normal file
View File

@ -0,0 +1,155 @@
/*******************************************************************************/
/* 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. */
/*******************************************************************************/
/* Handles streaming from track inputs to disk */
/* FIXME: we shouldn't depend on these */
#include "Timeline.H"
#include "Engine.H"
#include "Audio_Track.H"
#include "Track_Header.H"
#include "Port.H"
#include "Record_DS.H"
#include "dsp.h"
/* THREAD: IO */
/** write /nframes/ from buf to the capture file of the attached track */
void
Record_DS::write_block ( sample_t *buf, nframes_t nframes )
{
/* stupid chicken/egg */
if ( ! ( timeline && track() ) )
return;
// timeline->wrlock();
_af->write( buf, nframes );
// track()->record( buf, _frame, nframes, channels() );
// timeline->unlock();
}
/* THREAD: IO */
void
Record_DS::disk_thread ( void )
{
printf( "IO thread running...\n" );
/* buffer to hold the interleaved data returned by the track reader */
sample_t *buf = new sample_t[ _nframes * channels() ];
sample_t *cbuf = new sample_t[ _nframes ];
const size_t block_size = _nframes * sizeof( sample_t );
while ( wait_for_block() )
{
/* pull data from the per-channel ringbuffers and interlace it */
for ( int i = channels(); i--; )
{
while ( jack_ringbuffer_read_space( _rb[ i ] ) < block_size )
{
printf( "IO: disk buffer underrun!\n" );
/* FIXME: is this *really* the right thing to do? */
usleep( 2000 );
}
/* FIXME: avoid this copy */
jack_ringbuffer_read( _rb[ i ], (char*)cbuf, block_size );
buffer_interleave_one_channel( buf, cbuf, i, channels(), _nframes );
/* /\* deinterleave direcectly into the ringbuffer to avoid */
/* * unnecessary copying *\/ */
/* jack_ringbuffer_data_t rbd[2]; */
/* jack_ringbuffer_get_write_vector( _rb[ i ], rbd ); */
/* if ( rbd[ 0 ].len >= _nframes ) */
/* /\* it'll all fit in one go *\/ */
/* buffer_deinterleave_one_channel( (sample_t*)rbd[ 0 ].buf, buf, i, channels(), _nframes ); */
/* else if ( rbd[ 1 ].len ) */
/* { */
/* /\* there's enough space in the ringbuffer, but it's not contiguous *\/ */
/* /\* do the first half *\/ */
/* const nframes_t f = rbd[ 1 ].len / sizeof( sample_t ); */
/* buffer_deinterleave_one_channel( (sample_t*)rbd[ 0 ].buf, buf, i, channels(), f ); */
/* assert( rbd[ 1 ].len >= (_nframes - f) * sizeof( sample_t ) ); */
/* /\* do the second half *\/ */
/* buffer_deinterleave_one_channel( (sample_t*)rbd[ 1 ].buf, buf + f, i, channels(), _nframes - f ); */
/* } */
/* else */
/* printf( "programming error: expected more space in ringbuffer\n" ); */
/* /\* buffer_deinterleave_one_channel( (sample_t*)rbd.buf, buf, i, channels(), _nframes ); *\/ */
/* /\* jack_ringbuffer_write( _rb[ i ], (char*)cbuf, block_size ); *\/ */
/* jack_ringbuffer_write_advance( _rb[ i ], _nframes * sizeof( sample_t ) ); */
}
write_block( buf, _nframes );
}
printf( "IO thread terminating.\n" );
delete[] buf;
}
/* THREAD: RT */
/** take a single block from the ringbuffers and send it out the
* attached track's ports */
nframes_t
Record_DS::process ( nframes_t nframes )
{
const size_t block_size = nframes * sizeof( sample_t );
// printf( "process: %lu %lu %lu\n", _frame, _frame + nframes, nframes );
for ( int i = channels(); i--; )
{
void *buf = _th->input[ i ].buffer( nframes );
if ( jack_ringbuffer_write( _rb[ i ], (char*)buf, block_size ) < block_size )
{
printf( "RT: buffer overrun (disk can't keep up).\n" );
memset( buf, 0, block_size );
/* FIXME: we need to resync somehow */
}
}
block_processed();
/* FIXME: bogus */
return nframes;
}

55
Timeline/Record_DS.H Normal file
View File

@ -0,0 +1,55 @@
/*******************************************************************************/
/* 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 "Disk_Stream.H"
#include "Audio_File_SF.H"
class Audio_File;
class Record_DS : public Disk_Stream
{
Audio_File_SF *_af; /* capture file */
void write_block ( sample_t *buf, nframes_t nframes );
void disk_thread ( void );
public:
Record_DS ( Track_Header *th, float frame_rate, nframes_t nframes, int channels ) :
Disk_Stream( th, frame_rate, nframes, channels )
{
/* FIXME: we need our semaphore set to 0, no? */
_af = Audio_File_SF::create( "testing.wav", 48000, 1, "Wav/24" );
sem_destroy( &_blocks );
sem_init( &_blocks, 0, 0 );
run();
}
/* bool seek_pending ( void ); */
/* void seek ( nframes_t frame ); */
nframes_t process ( nframes_t nframes );
};

View File

@ -709,7 +709,8 @@ Region::Fade::apply ( sample_t *buf, Region::Fade::fade_dir_e dir, long start, n
const float inc = increment();
float fi = ( i - start ) / (float)length;
buf += i;
// buf += i;
buf = &buf[ i ];
nframes_t n = e - i;

View File

@ -32,7 +32,7 @@
const float UPDATE_FREQ = 0.02f;
#include "Disk_Stream.H"
#include "Playback_DS.H"
#include "Transport.H"
@ -160,7 +160,7 @@ Timeline::Timeline ( int X, int Y, int W, int H, const char* L ) : Fl_Overlay_Wi
o->type( Fl_Pack::VERTICAL );
o->spacing( 0 );
for ( int i = 2; i--; )
for ( int i = 1; i--; )
{
// Track_Header *t = new Track_Header( 0, 0, W, 75 );
Track_Header *t = new Track_Header( 0, 0, W, 30 );
@ -699,7 +699,7 @@ Timeline::seek_pending ( void )
{
Track_Header *t = (Track_Header*)tracks->child( i );
if ( t->diskstream )
r += t->diskstream->output_buffer_percent() < 50;
if ( t->playback_ds )
r += t->playback_ds->buffer_percent() < 50;
}
}

View File

@ -19,9 +19,13 @@
#include "Track_Header.H"
#include "Disk_Stream.H"
#include "Playback_DS.H"
#include "Record_DS.H"
#include "Engine.H"
#include "Port.H"
void
Track_Header::cb_input_field ( Fl_Widget *w, void *v )
{
@ -88,8 +92,6 @@ Track_Header::cb_button ( Fl_Widget *w )
}
}
#include "Port.H"
Track_Header::Track_Header ( int X, int Y, int W, int H, const char *L ) :
Fl_Group ( X, Y, W, H, L )
{
@ -102,13 +104,20 @@ Track_Header::Track_Header ( int X, int Y, int W, int H, const char *L ) :
{
char pname[40];
static int n = 0;
snprintf( pname, sizeof( pname ), "out-%d", n++ );
static int no = 0, ni = 0;
snprintf( pname, sizeof( pname ), "out-%d", no++ );
output.push_back( Port( strdup( pname ), Port::Output ) );
snprintf( pname, sizeof( pname ), "in-%d", ni++ );
input.push_back( Port( strdup( pname ), Port::Input ) );
output.push_back( Port( strdup( pname ) ) );
}
diskstream = new Disk_Stream( this, engine->frame_rate(), engine->nframes(), 1 );
playback_ds = new Playback_DS( this, engine->frame_rate(), engine->nframes(), 1 );
record_ds = new Record_DS( this, engine->frame_rate(), engine->nframes(), 1 );
Fl_Group::size( w(), height() );
@ -300,8 +309,11 @@ Track_Header::add_control( Track *t )
nframes_t
Track_Header::process ( nframes_t nframes )
{
if ( diskstream )
return diskstream->process( nframes );
if ( playback_ds )
{
record_ds->process( nframes );
return playback_ds->process( nframes );
}
else
return 0;
}
@ -310,6 +322,6 @@ Track_Header::process ( nframes_t nframes )
void
Track_Header::seek ( nframes_t frame )
{
if ( diskstream )
return diskstream->seek( frame );
if ( playback_ds )
return playback_ds->seek( frame );
}

View File

@ -30,11 +30,16 @@
#include "Loggable.H"
#include "Port.H"
// #include "Port.H"
#include <vector>
using std::vector;
class Disk_Stream;
class Playback_DS;
class Record_DS;
class Port;
class Track_Header : public Fl_Group, public Loggable
{
@ -73,8 +78,11 @@ public:
Fl_Pack *control;
Fl_Pack *takes;
vector <Port> input;
vector <Port> output; /* output ports... */
Disk_Stream *diskstream;
Playback_DS *playback_ds;
Record_DS *record_ds;
const char *class_name ( void ) { return "Track_Header"; }