From b0d5b60a6fb2a18af5761c22a1a0cfa787b704ff Mon Sep 17 00:00:00 2001 From: Jonathan Moore Liles Date: Wed, 26 Mar 2008 03:33:14 -0500 Subject: [PATCH] Work on switching Timeline Editor over to use the Peak Server. --- Engine/Peak_Server.C | 71 ++++++++++++++++----- Engine/Peaks.C | 2 +- Timeline/Audio_Track.C | 21 +------ Timeline/Clip.H | 70 +++++++++++++++++++++ Timeline/Makefile | 4 +- Timeline/Peak_Client.C | 135 ++++++++++++++++++++++++++++++++++++++++ Timeline/Peak_Client.H | 40 ++++++++++++ Timeline/Region.C | 73 +++++++++++++--------- Timeline/Region.H | 12 ++-- Timeline/Timeline.H | 4 +- Timeline/Track_Widget.H | 1 - Timeline/Waveform.C | 32 +++------- Timeline/Waveform.H | 7 ++- Timeline/main.C | 11 ++++ 14 files changed, 377 insertions(+), 106 deletions(-) create mode 100644 Timeline/Clip.H create mode 100644 Timeline/Peak_Client.C create mode 100644 Timeline/Peak_Client.H diff --git a/Engine/Peak_Server.C b/Engine/Peak_Server.C index 92521b1..54dd480 100644 --- a/Engine/Peak_Server.C +++ b/Engine/Peak_Server.C @@ -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; diff --git a/Engine/Peaks.C b/Engine/Peaks.C index 1591d7b..183e5d4 100644 --- a/Engine/Peaks.C +++ b/Engine/Peaks.C @@ -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 */ diff --git a/Timeline/Audio_Track.C b/Timeline/Audio_Track.C index 322a54a..1dbe0d9 100644 --- a/Timeline/Audio_Track.C +++ b/Timeline/Audio_Track.C @@ -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 ::const_iterator r = _widgets.begin(); r != _widgets.end(); r++ ) - { - printf( "\t" ); - ((Region*)(*r))->dump(); - } - - printf( "}\n" ); -} diff --git a/Timeline/Clip.H b/Timeline/Clip.H new file mode 100644 index 0000000..8bbae2b --- /dev/null +++ b/Timeline/Clip.H @@ -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 ); + } +}; diff --git a/Timeline/Makefile b/Timeline/Makefile index 6fbaa92..46a2d74 100644 --- a/Timeline/Makefile +++ b/Timeline/Makefile @@ -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) diff --git a/Timeline/Peak_Client.C b/Timeline/Peak_Client.C new file mode 100644 index 0000000..5e45746 --- /dev/null +++ b/Timeline/Peak_Client.C @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#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; +} diff --git a/Timeline/Peak_Client.H b/Timeline/Peak_Client.H new file mode 100644 index 0000000..2f90b09 --- /dev/null +++ b/Timeline/Peak_Client.H @@ -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 ); + +}; diff --git a/Timeline/Region.C b/Timeline/Region.C index 805f024..c393a34 100644 --- a/Timeline/Region.C +++ b/Timeline/Region.C @@ -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() ); } diff --git a/Timeline/Region.H b/Timeline/Region.H index 58cb656..fb7dfe1 100644 --- a/Timeline/Region.H +++ b/Timeline/Region.H @@ -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 diff --git a/Timeline/Timeline.H b/Timeline/Timeline.H index bce0100..c51dc61 100644 --- a/Timeline/Timeline.H +++ b/Timeline/Timeline.H @@ -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 #include diff --git a/Timeline/Track_Widget.H b/Timeline/Track_Widget.H index 7302653..cbf32ce 100644 --- a/Timeline/Track_Widget.H +++ b/Timeline/Track_Widget.H @@ -21,7 +21,6 @@ #include "Track.H" #include "Loggable.H" -#include "Audio_File.H" #include "Timeline.H" #include #include diff --git a/Timeline/Waveform.C b/Timeline/Waveform.C index db7674f..f98d7e5 100644 --- a/Timeline/Waveform.C +++ b/Timeline/Waveform.C @@ -24,7 +24,6 @@ #include #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 )); } diff --git a/Timeline/Waveform.H b/Timeline/Waveform.H index 08cfd65..52e762f 100644 --- a/Timeline/Waveform.H +++ b/Timeline/Waveform.H @@ -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 ); }; diff --git a/Timeline/main.C b/Timeline/main.C index cbb9f55..740ce26 100644 --- a/Timeline/main.C +++ b/Timeline/main.C @@ -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 );