| @@ -1,31 +0,0 @@ | |||||
| SRCS= \ | |||||
| Server.C \ | |||||
| Peak_Server.C \ | |||||
| Timeline_Server.C \ | |||||
| main.C \ | |||||
| Audio_File.C \ | |||||
| Audio_File_SF.C \ | |||||
| Peaks.C \ | |||||
| Loggable.C \ | |||||
| OBJS=$(SRCS:.C=.o) | |||||
| .PHONEY: all clean install dist valgrind | |||||
| all: engine | |||||
| $(OBJS): Makefile | |||||
| include ../make.inc | |||||
| engine: $(OBJS) | |||||
| $(CXX) $(CXXFLAGS) $(INCLUDES) $(LIBS) $(OBJS) -o $@ | |||||
| clean: | |||||
| rm -f $(OBJS) engine makedepend | |||||
| valgrind: | |||||
| valgrind ./test | |||||
| include makedepend | |||||
| @@ -1,150 +0,0 @@ | |||||
| /*******************************************************************************/ | |||||
| /* 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 "Peak_Server.H" | |||||
| #include <stdio.h> | |||||
| #include <string.h> | |||||
| #include <sys/socket.h> | |||||
| /* Peak Server | |||||
| The Peak Server streams peak data to any Timeline Editors or other | |||||
| clients that ask for it. | |||||
| Peak request looks like (in ASCII) | |||||
| > read_peaks "foo.wav" fpp start end | |||||
| Where "foo.wav" is the base name. (actual filenames may differ if | |||||
| the channels of the source are 'broken out') | |||||
| Response looks like (in binary) | |||||
| > (int)channels (int)length (float)min max min max min max | |||||
| > min max min max | |||||
| 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" | |||||
| #include "Peaks.H" | |||||
| typedef unsigned long tick_t; | |||||
| #define PEAK_PORT 6100 | |||||
| void | |||||
| Peak_Server::handle_new ( int s ) | |||||
| { | |||||
| printf( "new connection\n" ); | |||||
| } | |||||
| void | |||||
| Peak_Server::handle_hang_up ( int s ) | |||||
| { | |||||
| printf( "hangup\n" ); | |||||
| } | |||||
| void | |||||
| Peak_Server::handle_request ( int s, const char *buf, int l ) | |||||
| { | |||||
| printf( "request: %s", buf ); | |||||
| char source[512]; | |||||
| float fpp; | |||||
| tick_t start, end; | |||||
| enum { GET_INFO, READ_PEAKS } request; | |||||
| if ( 1 == sscanf( buf, "get_info \"%[^\"]\"", source ) ) | |||||
| { | |||||
| 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 ); | |||||
| if ( ! af ) | |||||
| { | |||||
| const char *err = "error: could not open source\n"; | |||||
| send( s, err, strlen( err ), 0 ); | |||||
| return; | |||||
| } | |||||
| switch ( request ) | |||||
| { | |||||
| case GET_INFO: | |||||
| { | |||||
| char buf[128]; | |||||
| snprintf( buf, sizeof( buf ), "length=%lu channels=%d\n", af->length(), af->channels() ); | |||||
| send( s, buf, strlen( buf ), 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 ); | |||||
| const Peaks *pk = af->peaks(); | |||||
| int npeaks = pk->fill_buffer( fpp, start, end ); | |||||
| int channels = af->channels(); | |||||
| Peak *pbuf = new Peak[ npeaks * channels ]; | |||||
| /* deinterlace */ | |||||
| int k = 0; | |||||
| for ( int i = 0; i < channels; i++ ) | |||||
| for ( int j = i; j < npeaks * channels; j += channels ) | |||||
| pbuf[ k++ ] = pk->peakbuf()[ j ]; | |||||
| /* transmit */ | |||||
| send( s, pbuf, sizeof( Peak ) * npeaks * channels, 0 ); | |||||
| delete pbuf; | |||||
| break; | |||||
| } | |||||
| } | |||||
| // delete af; | |||||
| } | |||||
| @@ -1,40 +0,0 @@ | |||||
| /*******************************************************************************/ | |||||
| /* 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 "Server.H" | |||||
| class Peak_Server : public Server | |||||
| { | |||||
| protected: | |||||
| void handle_new ( int s ); | |||||
| void handle_hang_up ( int s ); | |||||
| void handle_request ( int s, const char *s, int l ); | |||||
| public: | |||||
| Peak_Server ( int port ) : Server ( port ) | |||||
| { | |||||
| fork( true ); | |||||
| echo( false ); | |||||
| } | |||||
| }; | |||||
| @@ -1,185 +0,0 @@ | |||||
| /*******************************************************************************/ | |||||
| /* 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 "Server.H" | |||||
| #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> | |||||
| /* Generic TCP server class */ | |||||
| /* */ | |||||
| #define MAX_HOST_NAME 512 | |||||
| /** open a socket listening on TCP port /port/. Returns -1 in case of error. */ | |||||
| int | |||||
| Server::listen_on_port ( int port ) | |||||
| { | |||||
| int s; | |||||
| char name[ MAX_HOST_NAME + 1 ]; | |||||
| struct sockaddr_in sa; | |||||
| struct hostent *hp; | |||||
| memset( &sa, 0, sizeof( sa ) ); | |||||
| gethostname( name, MAX_HOST_NAME ); | |||||
| hp = gethostbyname( name ); | |||||
| 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 ) | |||||
| { | |||||
| printf( "Could not create command socket!" ); | |||||
| return -1; | |||||
| } | |||||
| int yes = 1; | |||||
| if ( setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (char * )&yes, sizeof( int ) ) < 0 ) | |||||
| { | |||||
| close( s ); | |||||
| return -1; | |||||
| } | |||||
| if ( bind( s, (struct sockaddr *)&sa, sizeof( sa ) ) < 0 ) | |||||
| { | |||||
| printf( "bind: %s", strerror( errno ) ); | |||||
| close( s ); | |||||
| return -1; | |||||
| } | |||||
| listen( s, 1 ); | |||||
| return s; | |||||
| } | |||||
| Server::Server ( int port ) | |||||
| { | |||||
| _port = port; | |||||
| _echo = false; | |||||
| _fork = false; | |||||
| } | |||||
| void | |||||
| Server::run ( void ) | |||||
| { | |||||
| int server; /* server socket */ | |||||
| if ( ( server = listen_on_port( _port ) ) < 0 ) | |||||
| /* error */; | |||||
| fd_set master; | |||||
| fd_set read_fds; | |||||
| int maxfd; | |||||
| FD_ZERO( &master ); | |||||
| FD_ZERO( &read_fds ); | |||||
| FD_SET( server, &master ); | |||||
| maxfd = server; | |||||
| for ( ;; ) | |||||
| { | |||||
| read_fds = master; | |||||
| if ( select( maxfd + 1, &read_fds, NULL, NULL, NULL ) == -1 ) | |||||
| { | |||||
| perror( "select()" ); | |||||
| /* error */ | |||||
| } | |||||
| /* service connections */ | |||||
| /* FIXME: there's a better way to do this than cover *all* fds. */ | |||||
| for ( int i = 2; i < maxfd + 1; ++i ) | |||||
| { | |||||
| if ( FD_ISSET( i, &read_fds ) ) | |||||
| { | |||||
| if ( i == server ) | |||||
| { | |||||
| struct sockaddr_in ca; | |||||
| socklen_t al = sizeof( ca ); | |||||
| int c; | |||||
| if ( ( c = accept( server, (struct sockaddr *)&ca, &al ) ) < 0 ) | |||||
| perror( "accept()" ); | |||||
| FD_SET( c, &master ); | |||||
| if ( c > maxfd ) | |||||
| maxfd = c; | |||||
| handle_new( c ); | |||||
| // printf( "New connection from %s on socket %d\n", inet_ntoa( ca.sin_addr ), c ); | |||||
| } | |||||
| else | |||||
| { | |||||
| char buf[ BUFSIZ ]; | |||||
| int l; | |||||
| if ( ( l = recv( i, buf, sizeof( buf ), 0 ) ) <= 0 ) | |||||
| { | |||||
| if ( l == 0 ) | |||||
| { | |||||
| handle_hang_up( i ); | |||||
| } | |||||
| else | |||||
| perror( "recv()" ); | |||||
| close( i ); | |||||
| FD_CLR( i, &master ); | |||||
| } | |||||
| else | |||||
| { | |||||
| if ( echo() ) | |||||
| /* echo to others */ | |||||
| for ( int j = maxfd; j-- ; ) | |||||
| { | |||||
| if ( ! FD_ISSET( j, &master ) ) | |||||
| continue; | |||||
| if ( j != server && j != i ) | |||||
| { | |||||
| if ( send( j, buf, l, 0 ) < 0 ) | |||||
| perror( "send()" ); | |||||
| } | |||||
| } | |||||
| buf[ l ] = '\0'; | |||||
| handle_request( i, buf, l ); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,47 +0,0 @@ | |||||
| /*******************************************************************************/ | |||||
| /* 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 | |||||
| class Server | |||||
| { | |||||
| int _port; | |||||
| bool _echo; | |||||
| bool _fork; | |||||
| static int listen_on_port ( int port ); | |||||
| public: | |||||
| Server ( int port ); | |||||
| void run ( void ); | |||||
| bool echo ( void ) { return _echo; } | |||||
| bool fork ( void ) { return _fork; } | |||||
| void echo ( bool b ) { _echo = b; } | |||||
| void fork ( bool b) { _fork = b; } | |||||
| protected: | |||||
| virtual void handle_hang_up ( int s ) = 0; | |||||
| virtual void handle_new ( int s ) = 0; | |||||
| virtual void handle_request ( int s, const char *s, int l ) = 0; | |||||
| }; | |||||
| @@ -1,76 +0,0 @@ | |||||
| /*******************************************************************************/ | |||||
| /* 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 "objects.H" | |||||
| /* #include <sys/socket.h> */ | |||||
| /* #include <sys/types.h> */ | |||||
| /* #include <sys/select.h> */ | |||||
| #include "Timeline_Server.H" | |||||
| #include <stdio.h> | |||||
| #include <string.h> | |||||
| #include <sys/socket.h> | |||||
| /* Timeline Server. | |||||
| The timeline server runs in its own thread and manages communication | |||||
| between the engine and any connected timeline editors. | |||||
| Its duties are as follows: | |||||
| * Listen for connections from Timeline Editors on a TCP port. | |||||
| * Accept 'do' messages from each connection, echoing the change to | |||||
| all others. | |||||
| * Keep global engine state in sync with recieved messages (in a | |||||
| lock-free manner) | |||||
| * Write do+undo messages to journal. | |||||
| * Translate "undo" command into the appropriate 'do' messages. | |||||
| */ | |||||
| #define TIMELINE_PORT 6100 | |||||
| void | |||||
| Timeline_Server::handle_new ( int s ) | |||||
| { | |||||
| printf( "new connection\n" ); | |||||
| } | |||||
| void | |||||
| Timeline_Server::handle_hang_up ( int s ) | |||||
| { | |||||
| printf( "hangup\n" ); | |||||
| } | |||||
| void | |||||
| Timeline_Server::handle_request ( int s, const char *buf, int l ) | |||||
| { | |||||
| printf( "request: %s", buf ); | |||||
| // Loggable::do( buf ); | |||||
| send( s, "fuckoff\n", strlen( "fuckoff\n" ), 0 ); | |||||
| } | |||||
| @@ -1,40 +0,0 @@ | |||||
| /*******************************************************************************/ | |||||
| /* 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 "Server.H" | |||||
| class Timeline_Server : public Server | |||||
| { | |||||
| protected: | |||||
| void handle_new ( int s ); | |||||
| void handle_hang_up ( int s ); | |||||
| void handle_request ( int s, const char *s, int l ); | |||||
| public: | |||||
| Timeline_Server ( int port ) : Server ( port ) | |||||
| { | |||||
| fork( false ); | |||||
| echo( true ); | |||||
| } | |||||
| }; | |||||
| @@ -1,27 +0,0 @@ | |||||
| /*******************************************************************************/ | |||||
| /* 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. */ | |||||
| /*******************************************************************************/ | |||||
| /* default peak file resolution, therefore normally any zoom level less than this will | |||||
| require reading from the audio files directly */ | |||||
| const int FRAMES_PER_PEAK = 256; | |||||
| @@ -1,77 +0,0 @@ | |||||
| /*******************************************************************************/ | |||||
| /* 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 "const.h" | |||||
| #include "Audio_File.H" | |||||
| #include "Peaks.H" | |||||
| #include "Loggable.H" | |||||
| #include "Timeline_Server.H" | |||||
| #include "Peak_Server.H" | |||||
| /* TODO: | |||||
| Run server process here. | |||||
| * Manage session file. | |||||
| * Keep state for all relevant objects (must mirror that in Timeline) | |||||
| * Listen for incoming connections. | |||||
| * Send and recieve 'do' messages to client(s), recording do and undo portions to journal. Serve peaks (maybe in a separate process?) | |||||
| Peak request looks like: | |||||
| > read_peaks "foo.wav" fpp start end | |||||
| Response looks like (in binary floats): | |||||
| > length min max min max min max | |||||
| State must be communicated to realtime thread locklessly so that: | |||||
| Realtime: | |||||
| * Manage JACK transport. | |||||
| * Manage JACK outputs. | |||||
| * Stream regions from disk. | |||||
| * Manage JACK inputs. | |||||
| * Stream tracks to disk when recording. | |||||
| * Stream control points as OSC messages. (RT safe?) | |||||
| */ | |||||
| int | |||||
| main ( int argc, char **argv ) | |||||
| { | |||||
| if ( ! fork() ) | |||||
| { | |||||
| Peak_Server pks( 6111 ); | |||||
| pks.run(); | |||||
| exit( 0 ); | |||||
| } | |||||
| Timeline_Server tls( 6110 ); | |||||
| tls.run(); | |||||
| } | |||||
| @@ -1,183 +0,0 @@ | |||||
| /*******************************************************************************/ | |||||
| /* 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. */ | |||||
| /*******************************************************************************/ | |||||
| /* these are all the objects whose state must be recorded, this | |||||
| includes tracks, regions, etc. Relevant interfaces must be fully compatible | |||||
| with those in the Timeline program. */ | |||||
| #include "Audio_File.H" | |||||
| #include "Loggable.H" | |||||
| typedef unsigned long nframes_t; | |||||
| class Track_Widget | |||||
| { | |||||
| protected: | |||||
| nframes_t _offset; | |||||
| nframes_t _start; | |||||
| nframes_t _end; | |||||
| bool _selected; | |||||
| }; | |||||
| /* macros to simplify serialization code */ | |||||
| #define START( n ) char **sa = (char **)malloc( sizeof( char * ) * (1 + (n) ) ); int i = 0 | |||||
| #define PUT( fmt, arg ) asprintf( &sa[ i++ ], (fmt), (arg) ) | |||||
| #define END() sa[ i ] = NULL; return sa; | |||||
| #define SWITCH do | |||||
| #define CASE( arg ) if ( ! strcmp( s, ( arg ) ) ) | |||||
| #define GET( arg, act ) CASE( arg ) { act ; break; } | |||||
| class Track : public Loggable | |||||
| { | |||||
| }; | |||||
| class Region : public Loggable, public Track_Widget | |||||
| { | |||||
| Track *_track; | |||||
| Audio_File *_clip; /* clip this region represents */ | |||||
| float _scale; /* amplitude adjustment */ | |||||
| protected: | |||||
| const char *class_name ( void ) { return "Region"; } | |||||
| char ** get ( void ) | |||||
| { | |||||
| START( 7 ); | |||||
| PUT( ":source \"%s\"", _clip ? _clip->name() : "" ); | |||||
| PUT( ":track 0x%X", _track ? _track->id() : 0 ); | |||||
| PUT( ":x %lu", _offset ); | |||||
| PUT( ":l %lu", _start ); | |||||
| PUT( ":r %lu", _end ); | |||||
| PUT( ":selected %d", _selected ); | |||||
| PUT( ":gain %f", _scale ); | |||||
| END(); | |||||
| } | |||||
| void | |||||
| set ( char **sa ) | |||||
| { | |||||
| for ( int i = 0; sa[i]; ++i ) | |||||
| { | |||||
| char *s = sa[i]; | |||||
| char *v = s + strlen( s ) + 1; | |||||
| SWITCH | |||||
| { | |||||
| GET( ":x", _offset = atol( v ) ); | |||||
| GET( ":l" , _start = atol( v ) ); | |||||
| GET( ":r", _end = atol( v ) ); | |||||
| CASE( ":selected" ) | |||||
| { | |||||
| if ( atoi( v ) ) | |||||
| select(); | |||||
| else | |||||
| deselect(); | |||||
| break; | |||||
| } | |||||
| GET( ":gain", _scale = atof( v ) ); | |||||
| CASE( ":source" ) | |||||
| { | |||||
| if ( ! ( _clip = Audio_File::from_file( v ) ) ) | |||||
| printf( "Grave error: could not open source \"%s\"\n", v ); | |||||
| break; | |||||
| } | |||||
| CASE( ":track" ) | |||||
| { | |||||
| int i; | |||||
| sscanf( v, "%X", &i ); | |||||
| Track *t = (Track*)Loggable::find( i ); | |||||
| assert( t ); | |||||
| t->add( this ); | |||||
| break; | |||||
| } | |||||
| } | |||||
| free( s ); | |||||
| } | |||||
| free( sa ); | |||||
| } | |||||
| }; | |||||
| class Time_Point : public Track_Widget | |||||
| { | |||||
| protected: | |||||
| char ** get ( void ) | |||||
| { | |||||
| START( 4 ); | |||||
| PUT( ":track 0x%X", _track ? _track->id() : 0 ); | |||||
| PUT( ":x %lu", _offset ); | |||||
| PUT( ":beats_per_bar %d", _time.beats_per_bar ); | |||||
| PUT( ":beat_type %d", _time.beat_type ); | |||||
| END(); | |||||
| } | |||||
| void | |||||
| set ( char **sa ) | |||||
| { | |||||
| for ( int i = 0; sa[i]; ++i ) | |||||
| { | |||||
| char *s = sa[i]; | |||||
| char *v = s + strlen( s ) + 1; | |||||
| SWITCH | |||||
| { | |||||
| GET( ":x", _offset = atol( v ) ); | |||||
| GET( ":beats_per_bar", _time.beats_per_bar = atoi( v ) ); | |||||
| GET( ":beat_type", _time.beat_type = atoi( v ) ); | |||||
| CASE( ":track" ) | |||||
| { | |||||
| int i; | |||||
| sscanf( v, "%X", &i ); | |||||
| Track *t = (Track*)Loggable::find( i ); | |||||
| assert( t ); | |||||
| t->add( this ); | |||||
| break; | |||||
| } | |||||
| free( s ); | |||||
| } | |||||
| free( sa ); | |||||
| } | |||||
| } | |||||
| }; | |||||
| @@ -5,7 +5,6 @@ LIBS := -lsndfile `fltk-config --ldflags` | |||||
| all: all | all: all | ||||
| %: | %: | ||||
| @ $(MAKE) -s -C Engine CXXFLAGS="$(CXXFLAGS)" LIBS="$(LIBS)" $@ | |||||
| @ $(MAKE) -s -C FL CXXFLAGS="$(CXXFLAGS)" LIBS="$(LIBS)" $@ | @ $(MAKE) -s -C FL CXXFLAGS="$(CXXFLAGS)" LIBS="$(LIBS)" $@ | ||||
| @ $(MAKE) -s -C Timeline CXXFLAGS="$(CXXFLAGS)" LIBS="$(LIBS)" $@ | @ $(MAKE) -s -C Timeline CXXFLAGS="$(CXXFLAGS)" LIBS="$(LIBS)" $@ | ||||
| @ $(MAKE) -s -C Mixer CXXFLAGS="$(CXXFLAGS)" LIBS="$(LIBS)" $@ | @ $(MAKE) -s -C Mixer CXXFLAGS="$(CXXFLAGS)" LIBS="$(LIBS)" $@ | ||||
| @@ -50,3 +50,29 @@ done: | |||||
| return a; | return a; | ||||
| } | } | ||||
| bool | |||||
| Audio_File::read_peaks( float fpp, nframes_t start, nframes_t end, int *peaks, Peak **pbuf, int *channels ) | |||||
| { | |||||
| Peaks pk; | |||||
| pk.clip( this ); | |||||
| if ( ! pk.open() ) | |||||
| return false; | |||||
| *peaks = pk.fill_buffer( fpp, start, end ); | |||||
| *channels = this->channels(); | |||||
| *pbuf = new Peak[ *peaks * *channels ]; | |||||
| /* deinterlace */ | |||||
| int k = 0; | |||||
| for ( int i = 0; i < *channels; i++ ) | |||||
| for ( int j = i; j < *peaks * *channels; j += *channels ) | |||||
| (*pbuf)[ k++ ] = pk.peakbuf()[ j ]; | |||||
| return true; | |||||
| } | |||||
| @@ -67,4 +67,7 @@ public: | |||||
| virtual nframes_t read ( sample_t *buf, int channel, nframes_t len ) = 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 read ( sample_t *buf, int channel, nframes_t start, nframes_t end ) = 0; | ||||
| bool read_peaks( float fpp, nframes_t start, nframes_t end, int *peaks, Peak **pbuf, int *channels ); | |||||
| }; | }; | ||||
| @@ -88,7 +88,7 @@ Audio_Track::handle ( int m ) | |||||
| fl_cursor( FL_CURSOR_WAIT ); | fl_cursor( FL_CURSOR_WAIT ); | ||||
| Fl::check(); | Fl::check(); | ||||
| Clip *c = Clip::from_file( file ); | |||||
| Audio_File *c = Audio_File::from_file( file ); | |||||
| fl_cursor( FL_CURSOR_DEFAULT ); | fl_cursor( FL_CURSOR_DEFAULT ); | ||||
| @@ -1,70 +0,0 @@ | |||||
| /*******************************************************************************/ | |||||
| /* 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 ); | |||||
| } | |||||
| }; | |||||
| @@ -8,8 +8,10 @@ SRCS= \ | |||||
| Timeline.C \ | Timeline.C \ | ||||
| Track_Header.C \ | Track_Header.C \ | ||||
| Track_Widget.C \ | Track_Widget.C \ | ||||
| Peak_Client.C \ | |||||
| ../Engine/Loggable.C \ | |||||
| Peaks.C \ | |||||
| Audio_File.C \ | |||||
| Audio_File_SF.C \ | |||||
| Loggable.C \ | |||||
| OBJS=$(SRCS:.C=.o) | OBJS=$(SRCS:.C=.o) | ||||
| @@ -1,135 +0,0 @@ | |||||
| /*******************************************************************************/ | |||||
| /* 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; | |||||
| } | |||||
| @@ -1,40 +0,0 @@ | |||||
| /*******************************************************************************/ | |||||
| /* 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 ); | |||||
| }; | |||||
| @@ -35,8 +35,6 @@ | |||||
| using namespace std; | using namespace std; | ||||
| #include "Peak_Client.H" | |||||
| extern Timeline *timeline; | extern Timeline *timeline; | ||||
| Fl_Boxtype Region::_box = FL_UP_BOX; | Fl_Boxtype Region::_box = FL_UP_BOX; | ||||
| @@ -110,7 +108,7 @@ Region::Region ( const Region & rhs ) | |||||
| } | } | ||||
| /* */ | /* */ | ||||
| Region::Region ( Clip *c ) | |||||
| Region::Region ( Audio_File *c ) | |||||
| { | { | ||||
| init(); | init(); | ||||
| _clip = c; | _clip = c; | ||||
| @@ -121,7 +119,7 @@ Region::Region ( Clip *c ) | |||||
| /* used when DND importing */ | /* used when DND importing */ | ||||
| Region::Region ( Clip *c, Track *t, nframes_t o ) | |||||
| Region::Region ( Audio_File *c, Track *t, nframes_t o ) | |||||
| { | { | ||||
| init(); | init(); | ||||
| _clip = c; | _clip = c; | ||||
| @@ -18,7 +18,7 @@ | |||||
| /*******************************************************************************/ | /*******************************************************************************/ | ||||
| #pragma once | #pragma once | ||||
| #include "Clip.H" | |||||
| #include "Audio_File.H" | |||||
| #include "Track.H" | #include "Track.H" | ||||
| #include "Timeline.H" | #include "Timeline.H" | ||||
| @@ -38,7 +38,7 @@ class Region_Base : public Track_Widget | |||||
| private: | private: | ||||
| Clip *_clip; /* clip this region represents */ | |||||
| Audio_File *_clip; /* clip this region represents */ | |||||
| float _scale; /* amplitude adjustment */ | float _scale; /* amplitude adjustment */ | ||||
| @@ -100,7 +100,7 @@ protected: | |||||
| _scale = atof( v ); | _scale = atof( v ); | ||||
| else if ( ! strcmp( s, ":source" ) ) | else if ( ! strcmp( s, ":source" ) ) | ||||
| { | { | ||||
| if ( ! ( _clip = Clip::from_file( v ) ) ) | |||||
| if ( ! ( _clip = Audio_File::from_file( v ) ) ) | |||||
| { | { | ||||
| printf( "Grave error: could not open source \"%s\"\n", 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); } | 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 ( const Region & rhs ); | ||||
| Region ( Clip *c ); | |||||
| Region ( Clip *c, Track *t, nframes_t o ); | |||||
| Region ( Audio_File *c ); | |||||
| Region ( Audio_File *c, Track *t, nframes_t o ); | |||||
| int handle ( int m ); | int handle ( int m ); | ||||
| void draw_box( int X, int Y, int W, int H ); | void draw_box( int X, int Y, int W, int H ); | ||||
| @@ -24,7 +24,7 @@ | |||||
| #include "Timeline.H" | #include "Timeline.H" | ||||
| #include "Peak_Client.H" | |||||
| #include "Peaks.H" | |||||
| class Waveform { | class Waveform { | ||||
| @@ -53,10 +53,6 @@ | |||||
| Timeline *timeline; | Timeline *timeline; | ||||
| #include "Peak_Client.H" | |||||
| Peak_Client peak_client; | |||||
| void cb_undo ( Fl_Widget *w, void *v ) | void cb_undo ( Fl_Widget *w, void *v ) | ||||
| { | { | ||||
| Loggable::undo(); | Loggable::undo(); | ||||
| @@ -74,12 +70,6 @@ main ( int argc, char **argv ) | |||||
| // Fl::scheme( "gtk+" ); | // Fl::scheme( "gtk+" ); | ||||
| if ( ! peak_client.connect( "localhost" ) ) | |||||
| { | |||||
| fprintf( stderr, "Could not connect to peak server!\n" ); | |||||
| return 1; | |||||
| } | |||||
| Loggable::open( "history" ); | Loggable::open( "history" ); | ||||
| /* welcome to C++ */ | /* welcome to C++ */ | ||||
| Loggable::register_create( "Region", &Region::create ); | Loggable::register_create( "Region", &Region::create ); | ||||