Browse Source

Split Disk_Stream into a base class and Playback_DS and Record_DS.

tags/non-daw-v1.1.0
Jonathan Moore Liles 17 years ago
parent
commit
fbb4b17dca
17 changed files with 616 additions and 253 deletions
  1. +4
    -2
      Timeline/Audio_File.H
  2. +45
    -4
      Timeline/Audio_File_SF.C
  3. +2
    -0
      Timeline/Audio_File_SF.H
  4. +5
    -204
      Timeline/Disk_Stream.C
  5. +19
    -17
      Timeline/Disk_Stream.H
  6. +7
    -2
      Timeline/Makefile
  7. +227
    -0
      Timeline/Playback_DS.C
  8. +40
    -0
      Timeline/Playback_DS.H
  9. +11
    -2
      Timeline/Port.C
  10. +6
    -3
      Timeline/Port.H
  11. +155
    -0
      Timeline/Record_DS.C
  12. +55
    -0
      Timeline/Record_DS.H
  13. +2
    -1
      Timeline/Region.C
  14. +4
    -4
      Timeline/Timeline.C
  15. +23
    -11
      Timeline/Track_Header.C
  16. +11
    -3
      Timeline/Track_Header.H
  17. +0
    -0
      Timeline/dsp.C

+ 4
- 2
Timeline/Audio_File.H 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 );



+ 45
- 4
Timeline/Audio_File_SF.C 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 );
}

+ 2
- 0
Timeline/Audio_File_SF.H 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 );

};

+ 5
- 204
Timeline/Disk_Stream.C 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;
}

+ 19
- 17
Timeline/Disk_Stream.H 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 );

};

+ 7
- 2
Timeline/Makefile 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
- 0
Timeline/Playback_DS.C 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
- 0
Timeline/Playback_DS.H 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 );

};

+ 11
- 2
Timeline/Port.C 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 )
{


+ 6
- 3
Timeline/Port.H 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
- 0
Timeline/Record_DS.C 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
- 0
Timeline/Record_DS.H 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 );

};

+ 2
- 1
Timeline/Region.C 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;



+ 4
- 4
Timeline/Timeline.C 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;
}
}

+ 23
- 11
Timeline/Track_Header.C 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 );
}

+ 11
- 3
Timeline/Track_Header.H 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"; }



Timeline/dsp.c → Timeline/dsp.C View File


Loading…
Cancel
Save