Work on switching Timeline Editor over to use the Peak Server.

pull/3/head
Jonathan Moore Liles 2008-03-26 03:33:14 -05:00
parent 0b67f85b60
commit b0d5b60a6f
14 changed files with 377 additions and 106 deletions

View File

@ -38,10 +38,11 @@
Response looks like (in binary)
> (int)channels (int)length (float)min max min max min max
> length ...
> min max min max
Were length specifies the number of Peaks (min/max pairs). The
first channel is transmitted first, and any others follow.
Were length specifies the number of Peaks (min/max pairs) (for each
channel) The first channel is transmitted first, and any others
follow.
*/
#include "Audio_File.H"
@ -72,12 +73,22 @@ Peak_Server::handle_request ( int s, const char *buf, int l )
float fpp;
tick_t start, end;
if ( 4 != sscanf( buf, "read_peaks \"%[^\"]\" %f %lu %lu", source, &fpp, &start, &end ) )
enum { GET_INFO, READ_PEAKS } request;
if ( 1 == sscanf( buf, "get_info \"%[^\"]\"", source ) )
{
const char *err = "error: malformed request\n";
fprintf( stderr, err );
send( s, err, strlen( err ), 0 );
return;
request = GET_INFO;
}
else if ( 4 == sscanf( buf, "read_peaks \"%[^\"]\" %f %lu %lu", source, &fpp, &start, &end ) )
{
request = READ_PEAKS;
}
else
{
const char *err = "error: malformed request\n";
fprintf( stderr, err );
send( s, err, strlen( err ), 0 );
return;
}
Audio_File *af = Audio_File::from_file( source );
@ -89,19 +100,45 @@ Peak_Server::handle_request ( int s, const char *buf, int l )
return;
}
int channels = af->channels();
send( s, &channels, sizeof( int ), 0 );
for ( int i = 0; i < af->channels(); ++i )
switch ( request )
{
const Peaks *pk = af->peaks( i );
case GET_INFO:
{
char buf[128];
int peaks = pk->fill_buffer( fpp, start, end );
snprintf( buf, sizeof( buf ), "length=%lu channels=%d\n", af->length(), af->channels() );
send( s, &peaks, sizeof( int ), 0 );
send( s, buf, strlen( buf ), 0 );
send( s, pk->peakbuf(), peaks * sizeof( Peak ), 0 );
break;
}
case READ_PEAKS:
{
int data[2];
int peaks;
data[0] = af->channels();
data[1] = peaks = (end - start) / fpp;
send( s, &data, sizeof( data ), 0 );
for ( int i = 0; i < af->channels(); ++i )
{
const Peaks *pk = af->peaks( i );
int npeaks = pk->fill_buffer( fpp, start, end );
if ( ! ( peaks == npeaks ) )
printf( "wtf?! %d %d\n", peaks, npeaks );
// send( s, &peaks, sizeof( int ), 0 );
send( s, pk->peakbuf(), npeaks * sizeof( Peak ), 0 );
}
break;
}
}
// delete af;

View File

@ -56,7 +56,7 @@ Peaks::fill_buffer ( float fpp, int s, int e ) const
read_peaks( s, e, (e - s) / fpp, fpp );
/* FIXME: are we *SURE* we got them all? */
return e - s;
return (e - s) / fpp;
}
/* else */

View File

@ -88,12 +88,13 @@ Audio_Track::handle ( int m )
fl_cursor( FL_CURSOR_WAIT );
Fl::check();
Audio_File *c = Audio_File::from_file( file );
Clip *c = Clip::from_file( file );
fl_cursor( FL_CURSOR_DEFAULT );
if ( ! c )
{
printf( "could not open file\n" );
free( file );
return 0;
}
@ -107,21 +108,3 @@ Audio_Track::handle ( int m )
return Track::handle( m );
}
}
void
Audio_Track::dump ( void )
{
printf( "1 \"%s\" {\n", /* name() */ "Track" );
sort();
for ( list <Track_Widget *>::const_iterator r = _widgets.begin(); r != _widgets.end(); r++ )
{
printf( "\t" );
((Region*)(*r))->dump();
}
printf( "}\n" );
}

70
Timeline/Clip.H Normal file
View File

@ -0,0 +1,70 @@
/*******************************************************************************/
/* 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
typedef unsigned long nframes_t;
/* a clip is just a stupid wrapper object for communicating with the peak server */
#include "Peak_Client.H"
extern Peak_Client peak_client;
class Clip
{
const char *_filename;
nframes_t _length; /* length of file in samples */
int _channels;
public:
Clip ( )
{
_filename = NULL;
_length = _channels = 0;
}
const char *name ( void ) const { return _filename; }
nframes_t length ( void ) const { return _length; }
int channels ( void ) const { return _channels; }
static Clip *
from_file ( const char * filename )
{
Clip *c = new Clip;
c->_filename = filename;
if ( ! peak_client.get_info( filename, &c->_length, &c->_channels ) )
{
delete c;
return false;
}
return c;
}
bool
read_peaks ( float fpp, nframes_t start, nframes_t end,
int *peaks, Peak **pbuf, int *channels )
{
return peak_client.read_peaks( _filename, fpp, start, end, peaks, pbuf, channels );
}
};

View File

@ -8,9 +8,7 @@ SRCS= \
Timeline.C \
Track_Header.C \
Track_Widget.C \
../Engine/Audio_File.C \
../Engine/Audio_File_SF.C \
../Engine/Peaks.C \
Peak_Client.C \
../Engine/Loggable.C \
OBJS=$(SRCS:.C=.o)

135
Timeline/Peak_Client.C Normal file
View File

@ -0,0 +1,135 @@
/*******************************************************************************/
/* 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 <netdb.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include "Peak_Client.H"
/* An interface to the peak server */
#define PEAK_PORT 6111
int
connect_to_host ( const char *host, int port )
{
int s;
struct sockaddr_in sa;
struct hostent *hp;
memset( &sa, 0, sizeof( sa ) );
hp = gethostbyname( host );
sa.sin_family = hp->h_addrtype;
sa.sin_port = htons( port );
sa.sin_addr.s_addr = INADDR_ANY;
if ( ( s = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
{
perror( "socket()" );
return -1;
}
if ( connect( s, (struct sockaddr *)&sa, sizeof( sa ) ) < 0 )
{
perror( "connect()" );
close( s );
return -1;
}
return s;
}
bool
Peak_Client::connect ( const char *host )
{
if ( ( _socket = connect_to_host( host, PEAK_PORT ) ) < 0 )
return false;
return true;
}
bool
Peak_Client::get_info ( const char *source, nframes_t *len, int *channels )
{
/* FIXME: needs to handle errors/reconnect */
char buf[512];
snprintf( buf, sizeof( buf ), "get_info \"%s\"\n", source );
send( _socket, buf, strlen( buf ), 0 );
recv( _socket, buf, sizeof( buf ), 0 );
if ( sscanf( buf, "length=%lu channels=%d", len, channels ) != 2 )
return false;
return true;
}
bool
Peak_Client::read_peaks ( const char *source, float fpp, nframes_t start, nframes_t end,
int *peaks, Peak **pbuf, int *channels )
{
/* FIXME: needs to handle errors/reconnect */
char buf[512];
snprintf( buf, sizeof( buf ), "read_peaks \"%s\" %f %lu %lu\n", source, fpp, start, end );
send( _socket, buf, strlen( buf ), 0 );
if ( recv( _socket, buf, sizeof( int ) * 2, 0 ) != sizeof( int ) * 2 )
{
printf( "error!\n" );
return false;
}
if ( ! strncmp( buf, "error", 5 ) )
return false;
*channels = ((int*)buf)[0];
*peaks = ((int*)buf)[1];
if ( ! ( *peaks && *channels ) )
/* unknown error */;
printf( "reading %d peaks for %d channels\n", *peaks, *channels );
*pbuf = new Peak[ *peaks * *channels ];
for ( int i = 0; i < *channels; ++i )
recv( _socket, *pbuf + (i * *peaks), *peaks * sizeof( Peak ), MSG_WAITALL );
printf( "done.\n" );
return true;
}

40
Timeline/Peak_Client.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. */
/*******************************************************************************/
#pragma once
int connect_to_host ( const char *host, int port );
typedef unsigned long nframes_t;
struct Peak {
float min, max;
};
class Peak_Client
{
int _socket;
public:
bool connect ( const char *host );
bool get_info ( const char *source, nframes_t *len, int *channels );
bool read_peaks ( const char *source, float fpp, nframes_t start, nframes_t end, int *peaks, Peak **pbuf, int *channels );
};

View File

@ -34,6 +34,9 @@
//using std::algorithm;
using namespace std;
#include "Peak_Client.H"
extern Timeline *timeline;
Fl_Boxtype Region::_box = FL_UP_BOX;
@ -107,7 +110,7 @@ Region::Region ( const Region & rhs )
}
/* */
Region::Region ( Audio_File *c )
Region::Region ( Clip *c )
{
init();
_clip = c;
@ -118,7 +121,7 @@ Region::Region ( Audio_File *c )
/* used when DND importing */
Region::Region ( Audio_File *c, Track *t, nframes_t o )
Region::Region ( Clip *c, Track *t, nframes_t o )
{
init();
_clip = c;
@ -451,17 +454,42 @@ Region::draw ( int X, int Y, int W, int H )
fl_push_clip( rx, Y, rw, H );
/* dirty hack to keep the box from flipping to vertical at small sizes */
// fl_draw_box( box(), rx - 10, Y, rw + 50, H, _box_color );
/* get actual peak data */
int channels;
int peaks;
Peak *pbuf;
// fl_push_clip( x() + Fl::box_dx( box() ), y(), w() - Fl::box_dw( box() ), h() );
int ch = (h() - Fl::box_dh( box() )) / _clip->channels();
for ( int i = _clip->channels(); i--; )
Waveform::draw( rx, X, (y() + Fl::box_dy( box() )) + (i * ch), W, ch, _clip, i, timeline->fpp(),
_clip->read_peaks( timeline->fpp(),
_start + offset, min( (_end - _start) - offset, _end),
_scale, selected() ? fl_invert_color( _color ) : _color );
&peaks, &pbuf, &channels );
assert( pbuf );
int ch = (h() - Fl::box_dh( box() )) / channels;
for ( int i = 0; i < channels; ++i )
{
Peak *pb = pbuf + (peaks * i);
/* scale it */
for ( int j = peaks; j--; )
{
pb[ j ].min *= _scale;
pb[ j ].max *= _scale;
}
Waveform::draw( rx, X, (y() + Fl::box_dy( box() )) + (i * ch), W, ch,
pb, peaks,
selected() ? fl_invert_color( _color ) : _color );
}
delete pbuf;
/* for ( int i = _clip->channels(); i--; ) */
/* Waveform::draw( rx, X, (y() + Fl::box_dy( box() )) + (i * ch), W, */
/* ch, _clip, i, timeline->fpp(), */
/* _start + offset, min( (_end - _start) - offset, _end), */
/* _scale, selected() ? fl_invert_color( _color ) : _color ); */
timeline->draw_measure_lines( rx, Y, rw, H, _box_color );
@ -474,6 +502,8 @@ Region::draw ( int X, int Y, int W, int H )
if ( current() )
{
/* draw length bubble */
char pat[40];
snprintf( pat, sizeof( pat ), "%dm:%.1fs", (int)(length() / timeline->sample_rate()) / 60, (double)length() / timeline->sample_rate() );
@ -481,15 +511,6 @@ Region::draw ( int X, int Y, int W, int H )
draw_label( pat, (Fl_Align)(FL_ALIGN_INSIDE | FL_ALIGN_CENTER), FL_GREEN );
}
/* if ( _selected ) */
/* { */
/* fl_color( selection_color() ); */
/* fl_line_style( FL_SOLID, 4 ); */
/* fl_rect( x(), y(), w(), h() ); */
/* fl_line_style( FL_SOLID, 0 ); */
/* } */
fl_pop_clip();
}
@ -500,15 +521,7 @@ Region::normalize ( void )
{
printf( "normalize: start=%lu end=%lu\n", _start, _end );
/* FIXME: punt */
_scale = _clip->peaks( 0 )->normalization_factor( timeline->fpp(), _start, _end );
}
/* FIXME: figure out a way to do this via the peak server */
/* _scale = _clip->peaks( 0 )->normalization_factor( timeline->fpp(), _start, _end ); */
void
Region::dump ( void )
{
// printf( "Region %p %lu { \"%s\" %lu %lu }\n", this, _offset, _clip->name(), _start, _end );
/* how about in STD? */
printf( "Region\n\t%p\n\toffset\n\t\t%lu\n\tranage\n\t\t%lu\n\t\t%lu\n\tsource\n\t\t\"%s\"\n\n", this, _offset, _start, _end, _clip->name() );
}

View File

@ -18,7 +18,7 @@
/*******************************************************************************/
#pragma once
#include "Audio_File.H"
#include "Clip.H"
#include "Track.H"
#include "Timeline.H"
@ -38,7 +38,7 @@ class Region_Base : public Track_Widget
private:
Audio_File *_clip; /* clip this region represents */
Clip *_clip; /* clip this region represents */
float _scale; /* amplitude adjustment */
@ -100,7 +100,7 @@ protected:
_scale = atof( v );
else if ( ! strcmp( s, ":source" ) )
{
if ( ! ( _clip = Audio_File::from_file( v ) ) )
if ( ! ( _clip = Clip::from_file( v ) ) )
{
printf( "Grave error: could not open source \"%s\"\n", v );
}
@ -194,8 +194,8 @@ public:
Fl_Align align ( void ) const { return (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_BOTTOM /*| FL_ALIGN_CLIP*/ | FL_ALIGN_INSIDE); }
Region ( const Region & rhs );
Region ( Audio_File *c );
Region ( Audio_File *c, Track *t, nframes_t o );
Region ( Clip *c );
Region ( Clip *c, Track *t, nframes_t o );
int handle ( int m );
void draw_box( int X, int Y, int W, int H );
@ -204,7 +204,5 @@ public:
void normalize ( void );
void dump ( void );
};
#endif

View File

@ -27,7 +27,9 @@
#include "Scalebar.H"
#include "Audio_File.H" // just for nframes_t
/* #include "Audio_File.H" // just for nframes_t */
typedef unsigned long nframes_t;
#include <math.h>
#include <assert.h>

View File

@ -21,7 +21,6 @@
#include "Track.H"
#include "Loggable.H"
#include "Audio_File.H"
#include "Timeline.H"
#include <list>
#include <algorithm>

View File

@ -24,7 +24,6 @@
#include <FL/fl_draw.H>
#include "Timeline.H"
#include "Audio_File.H"
#include "Waveform.H"
@ -43,20 +42,17 @@ bool Waveform::logarithmic = true;
/** draw a portion of /clip/'s waveform. coordinates are the portion to draw */
void
Waveform::draw ( int ox, int X, int Y, int W, int H, Audio_File *_clip, int channel, float fpp, nframes_t _start, nframes_t _end, float _scale, Fl_Color color )
Waveform::draw ( int ox, int X, int Y, int W, int H,
Peak *pbuf, int peaks,
Fl_Color color )
{
fl_push_clip( X, Y, W, H );
int j;
// int start = timeline->ts_to_x( _start );
int start = timeline->ts_to_x( _start ) + (X - ox);
// int start = timeline->ts_to_x( _start ) + (X - ox);
const Peaks *pk = _clip->peaks( channel );
_start = timeline->x_to_ts( start );
pk->fill_buffer( fpp, _start, _start + timeline->x_to_ts( W ) );
int start = 0;
const int halfheight = H / 2;
const int mid = Y + halfheight;
@ -66,12 +62,7 @@ Waveform::draw ( int ox, int X, int Y, int W, int H, Audio_File *_clip, int chan
j = start;
for ( int x = X; x <= X + W; ++x, ++j )
{
// Peak p = (*pk)[ j ];
Peak p = pk->peak( timeline->x_to_ts( j ), timeline->x_to_ts( j + 1 ) );
p.max *= _scale;
p.min *= _scale;
const Peak p = pbuf[ j ];
const float diff = fabs( p.max - p.min );
@ -103,7 +94,6 @@ Waveform::draw ( int ox, int X, int Y, int W, int H, Audio_File *_clip, int chan
}
}
if ( Waveform::outline )
{
@ -116,10 +106,7 @@ Waveform::draw ( int ox, int X, int Y, int W, int H, Audio_File *_clip, int chan
j = start;
for ( int x = X; x <= X + W; ++x, ++j )
{
// Peak p = (*pk)[ j ];
Peak p = pk->peak( timeline->x_to_ts( j ), timeline->x_to_ts( j + 1 ) );
p.min *= _scale;
const Peak p = pbuf[ j ];
fl_vertex( x, Y + (H / 2) + ((float)H / 2 * p.min ));
}
@ -131,10 +118,7 @@ Waveform::draw ( int ox, int X, int Y, int W, int H, Audio_File *_clip, int chan
j = start;
for ( int x = X; x <= X + W; ++x, ++j )
{
// Peak p = (*pk)[ j ];
Peak p = pk->peak( timeline->x_to_ts( j ), timeline->x_to_ts( j + 1 ) );
p.max *= _scale;
const Peak p = pbuf[ j ];
fl_vertex( x, Y + (H / 2) + ((float)H / 2 * p.max ));
}

View File

@ -24,8 +24,7 @@
#include "Timeline.H"
#include "Audio_File.H"
#include "Peak_Client.H"
class Waveform {
@ -36,6 +35,8 @@ public:
static bool vary_color;
static bool logarithmic;
static void draw ( int rx, int X, int Y, int W, int H, Audio_File *_clip, int channel, float fpp, nframes_t _start, nframes_t _end, float _scale, Fl_Color color );
static void draw ( int ox, int X, int Y, int W, int H,
Peak *pbuf, int peaks,
Fl_Color color );
};

View File

@ -53,6 +53,10 @@
Timeline *timeline;
#include "Peak_Client.H"
Peak_Client peak_client;
void cb_undo ( Fl_Widget *w, void *v )
{
Loggable::undo();
@ -69,6 +73,13 @@ main ( int argc, char **argv )
Fl::scheme( "plastic" );
// Fl::scheme( "gtk+" );
if ( ! peak_client.connect( "localhost" ) )
{
fprintf( stderr, "Could not connect to peak server!\n" );
return 1;
}
Loggable::open( "history" );
/* welcome to C++ */
Loggable::register_create( "Region", &Region::create );