]> git.sesse.net Git - mlt/blob - src/humperdink/client.c
afd2bbda7205dc6f0aead2921ce59551dab72b29
[mlt] / src / humperdink / client.c
1 /*
2  * client.c -- Valerie client demo
3  * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
4  * Author: Charles Yates <charles.yates@pandora.be>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20
21 /* System header files */
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 /* Application header files */
27 #include "client.h"
28 #include "io.h"
29
30 /** Clip navigation enumeration.
31 */
32
33 typedef enum
34 {
35         absolute,
36         relative
37 }
38 dv_demo_whence;
39
40 /** Function prototype for menu handling. 
41 */
42
43 typedef valerie_error_code (*demo_function)( dv_demo );
44
45 /** The menu structure. 
46 */
47
48 typedef struct
49 {
50         const char *description;
51         struct menu_item
52         {
53                 const char *option;
54                 demo_function function;
55         }
56         array[ 50 ];
57 }
58 *dv_demo_menu, dv_demo_menu_t;
59
60 /** Forward reference to menu runner.
61 */
62
63 extern valerie_error_code dv_demo_run_menu( dv_demo, dv_demo_menu );
64
65 /** Foward references. 
66 */
67
68 extern valerie_error_code dv_demo_list_nodes( dv_demo );
69 extern valerie_error_code dv_demo_add_unit( dv_demo );
70 extern valerie_error_code dv_demo_select_unit( dv_demo );
71 extern valerie_error_code dv_demo_execute( dv_demo );
72 extern valerie_error_code dv_demo_load( dv_demo );
73 extern valerie_error_code dv_demo_transport( dv_demo );
74 static void *dv_demo_status_thread( void * );
75
76 /** Connected menu definition. 
77 */
78
79 dv_demo_menu_t connected_menu =
80 {
81         "Connected Menu",
82         {
83                 { "Add Unit", dv_demo_add_unit },
84                 { "Select Unit", dv_demo_select_unit },
85                 { "Command Shell", dv_demo_execute },
86                 { NULL, NULL }
87         }
88 };
89
90 /** Initialise the demo structure.
91 */
92
93 dv_demo dv_demo_init( valerie_parser parser )
94 {
95         dv_demo this = malloc( sizeof( dv_demo_t ) );
96         if ( this != NULL )
97         {
98                 int index = 0;
99                 memset( this, 0, sizeof( dv_demo_t ) );
100                 strcpy( this->last_directory, "/" );
101                 for ( index = 0; index < 4; index ++ )
102                 {
103                         this->queues[ index ].unit = index;
104                         this->queues[ index ].position = -1;
105                 }
106                 this->parser = parser;
107         }
108         return this;
109 }
110
111 /** Display a status record.
112 */
113
114 void dv_demo_show_status( dv_demo demo, valerie_status status )
115 {
116         if ( status->unit == demo->selected_unit && demo->showing )
117         {
118                 char temp[ 1024 ] = "";
119
120                 sprintf( temp, "U%d ", demo->selected_unit );
121
122                 switch( status->status )
123                 {
124                         case unit_offline:
125                                 strcat( temp, "offline   " );
126                                 break;
127                         case unit_undefined:
128                                 strcat( temp, "undefined " );
129                                 break;
130                         case unit_not_loaded:
131                                 strcat( temp, "unloaded  " );
132                                 break;
133                         case unit_stopped:
134                                 strcat( temp, "stopped   " );
135                                 break;
136                         case unit_playing:
137                                 strcat( temp, "playing   " );
138                                 break;
139                         case unit_paused:
140                                 strcat( temp, "paused    " );
141                                 break;
142                         case unit_disconnected:
143                                 strcat( temp, "disconnect" );
144                                 break;
145                         default:
146                                 strcat( temp, "unknown   " );
147                                 break;
148                 }
149
150                 sprintf( temp + strlen( temp ), " %9d %9d %9d ", status->in, status->position, status->out );
151                 strcat( temp, status->clip );
152
153                 printf( "%-80.80s\r", temp );
154                 fflush( stdout );
155         }
156 }
157
158 /** Determine action to carry out as dictated by the client unit queue.
159 */
160
161 void dv_demo_queue_action( dv_demo demo, valerie_status status )
162 {
163         dv_demo_queue queue = &demo->queues[ status->unit ];
164
165         /* SPECIAL CASE STATUS NOTIFICATIONS TO IGNORE */
166
167         /* When we've issued a LOAD on the previous notification, then ignore this one. */
168         if ( queue->ignore )
169         {
170                 queue->ignore --;
171                 return;
172         }
173
174         if ( queue->mode && status->status != unit_offline && queue->head != queue->tail )
175         {
176                 if ( ( status->position >= status->out && status->speed > 0 ) || status->status == unit_not_loaded )
177                 {
178                         queue->position = ( queue->position + 1 ) % 50;
179                         if ( queue->position == queue->tail )
180                                 queue->position = queue->head;
181                         valerie_unit_load( demo->dv_status, status->unit, queue->list[ queue->position ] );
182                         if ( status->status == unit_not_loaded )
183                                 valerie_unit_play( demo->dv, queue->unit );
184                         queue->ignore = 1;
185                 }
186                 else if ( ( status->position <= status->in && status->speed < 0 ) || status->status == unit_not_loaded )
187                 {
188                         if ( queue->position == -1 )
189                                 queue->position = queue->head;
190                         valerie_unit_load( demo->dv_status, status->unit, queue->list[ queue->position ] );
191                         if ( status->status == unit_not_loaded )
192                                 valerie_unit_play( demo->dv, queue->unit );
193                         queue->position = ( queue->position - 1 ) % 50;
194                         queue->ignore = 1;
195                 }
196         }
197 }
198
199 /** Status thread.
200 */
201
202 static void *dv_demo_status_thread( void *arg )
203 {
204         dv_demo demo = arg;
205         valerie_status_t status;
206         valerie_notifier notifier = valerie_get_notifier( demo->dv_status );
207
208         while ( !demo->terminated )
209         {
210                 if ( valerie_notifier_wait( notifier, &status ) != -1 )
211                 {
212                         dv_demo_queue_action( demo, &status );
213                         dv_demo_show_status( demo, &status );
214                         if ( status.status == unit_disconnected )
215                                 demo->disconnected = 1;
216                 }
217         }
218
219         return NULL;
220 }
221
222 /** Turn on/off status display.
223 */
224
225 void dv_demo_change_status( dv_demo demo, int flag )
226 {
227         if ( demo->disconnected && flag )
228         {
229                 valerie_error_code error = valerie_connect( demo->dv );
230                 if ( error == valerie_ok )
231                         demo->disconnected = 0;
232                 else
233                         beep();
234         }
235
236         if ( flag )
237         {
238                 valerie_status_t status;
239                 valerie_notifier notifier = valerie_get_notifier( demo->dv );
240                 valerie_notifier_get( notifier, &status, demo->selected_unit );
241                 demo->showing = 1;
242                 dv_demo_show_status( demo, &status );
243         }
244         else
245         {
246                 demo->showing = 0;
247                 printf( "%-80.80s\r", " " );
248                 fflush( stdout );
249         }
250 }
251
252 /** Add a unit.
253 */
254
255 valerie_error_code dv_demo_add_unit( dv_demo demo )
256 {
257         valerie_error_code error = valerie_ok;
258         valerie_nodes nodes = valerie_nodes_init( demo->dv );
259         valerie_units units = valerie_units_init( demo->dv );
260
261         if ( valerie_nodes_count( nodes ) != -1 && valerie_units_count( units ) != -1 )
262         {
263                 char pressed;
264                 valerie_node_entry_t node;
265                 valerie_unit_entry_t unit;
266                 int node_index = 0;
267                 int unit_index = 0;
268
269                 printf( "Select a Node\n\n" );
270
271                 for ( node_index = 0; node_index < valerie_nodes_count( nodes ); node_index ++ )
272                 {
273                         valerie_nodes_get( nodes, node_index, &node );
274                         printf( "%d: %s - %s ", node_index + 1, node.guid, node.name );
275                         for ( unit_index = 0; unit_index < valerie_units_count( units ); unit_index ++ )
276                         {
277                                 valerie_units_get( units, unit_index, &unit );
278                                 if ( !strcmp( unit.guid, node.guid ) )
279                                         printf( "[U%d] ", unit.unit );
280                         }
281                         printf( "\n" );
282                 }
283
284                 printf( "0. Exit\n\n" );
285
286                 printf( "Node: " );
287
288                 while ( ( pressed = get_keypress( ) ) != '0' )
289                 {
290                         node_index = pressed - '1';
291                         if ( node_index >= 0 && node_index < valerie_nodes_count( nodes ) )
292                         {
293                                 int unit;
294                                 printf( "%c\n\n", pressed );
295                                 valerie_nodes_get( nodes, node_index, &node );
296                                 if ( valerie_unit_add( demo->dv, node.guid, &unit ) == valerie_ok )
297                                 {
298                                         printf( "Unit added as U%d\n", unit );
299                                         demo->selected_unit = unit;
300                                 }
301                                 else
302                                 {
303                                         int index = 0;
304                                         valerie_response response = valerie_get_last_response( demo->dv );
305                                         printf( "Failed to add unit:\n\n" );
306                                         for( index = 1; index < valerie_response_count( response ) - 1; index ++ )
307                                                 printf( "%s\n", valerie_response_get_line( response, index ) );
308                                 }
309                                 printf( "\n" );
310                                 wait_for_any_key( NULL );
311                                 break;
312                         }
313                         else
314                         {
315                                 beep( );
316                         }
317                 }
318         }
319         else
320         {
321                 printf( "Invalid response from the server.\n\n" );
322                 wait_for_any_key( NULL );
323         }
324
325         valerie_nodes_close( nodes );
326         valerie_units_close( units );
327
328         return error;
329 }
330
331 /** Select a unit.
332 */
333
334 valerie_error_code dv_demo_select_unit( dv_demo demo )
335 {
336         int terminated = 0;
337         int refresh = 1;
338
339         while ( !terminated )
340         {
341                 valerie_units units = valerie_units_init( demo->dv );
342
343                 if ( valerie_units_count( units ) > 0 )
344                 {
345                         valerie_unit_entry_t unit;
346                         int index = 0;
347                         char key = '\0';
348
349                         if ( refresh )
350                         {
351                                 printf( "Select a Unit\n\n" );
352
353                                 for ( index = 0; index < valerie_units_count( units ); index ++ )
354                                 {
355                                         valerie_units_get( units, index, &unit );
356                                         printf( "%d: U%d - %s [%s]\n", index + 1, 
357                                                                                                    unit.unit, 
358                                                                                                    unit.guid, 
359                                                                                                    unit.online ? "online" : "offline" );
360                                 }
361                                 printf( "0: Exit\n\n" );
362
363                                 printf( "Unit [%d]: ", demo->selected_unit + 1 );
364                                 refresh = 0;
365                         }
366
367                         key = get_keypress( );
368
369                         if ( key == '\r' )
370                                 key = demo->selected_unit + '1';
371
372                         if ( key != '0' )
373                         {
374                                 if ( key >= '1' && key < '1' + valerie_units_count( units ) )
375                                 {
376                                         demo->selected_unit = key - '1';
377                                         printf( "%c\n\n", key );
378                                         dv_demo_load( demo );
379                                         refresh = 1;
380                                 }
381                                 else
382                                 {
383                                         beep( );
384                                 }                                       
385                         }
386                         else
387                         {
388                                 printf( "0\n\n" );
389                                 terminated = 1;
390                         }
391                 }
392                 else if ( valerie_units_count( units ) == 0 )
393                 {
394                         printf( "No units added - add a unit first\n\n" );
395                         dv_demo_add_unit( demo );
396                 }
397                 else
398                 {
399                         printf( "Unable to obtain Unit List.\n" );
400                         terminated = 1;
401                 }
402
403                 valerie_units_close( units );
404         }
405
406         return valerie_ok;
407 }
408
409 /** Execute an arbitrary command.
410 */
411
412 valerie_error_code dv_demo_execute( dv_demo demo )
413 {
414         valerie_error_code error = valerie_ok;
415         char command[ 10240 ];
416         int terminated = 0;
417
418         printf( "Miracle Shell\n" );
419         printf( "Enter an empty command to exit.\n\n" );
420
421         while ( !terminated )
422         {
423                 terminated = 1;
424                 printf( "Command> " );
425
426                 if ( chomp( io_get_string( command, 10240, "" ) ) != NULL )
427                 {
428                         if ( strcmp( command, "" ) )
429                         {
430                                 int index = 0;
431                                 valerie_response response = NULL;
432                                 error = valerie_execute( demo->dv, 10240, command );
433                                 printf( "\n" );
434                                 response = valerie_get_last_response( demo->dv );
435                                 for ( index = 0; index < valerie_response_count( response ); index ++ )
436                                 {
437                                         char *line = valerie_response_get_line( response, index );
438                                         printf( "%4d: %s\n", index, line );
439                                 }
440                                 printf( "\n" );
441                                 terminated = 0;
442                         }
443                 }
444         }
445
446         printf( "\n" );
447
448         return error;
449 }
450
451 /** Add a file to the queue.
452 */
453
454 valerie_error_code dv_demo_queue_add( dv_demo demo, dv_demo_queue queue, char *file )
455 {
456         valerie_status_t status;
457         valerie_notifier notifier = valerie_get_notifier( demo->dv );
458
459         if ( ( queue->tail + 1 ) % 50 == queue->head )
460                 queue->head = ( queue->head + 1 ) % 50;
461         strcpy( queue->list[ queue->tail ], file );
462         queue->tail = ( queue->tail + 1 ) % 50;
463
464         valerie_notifier_get( notifier, &status, queue->unit );
465         valerie_notifier_put( notifier, &status );
466
467         return valerie_ok;
468 }
469
470 /** Basic queue maintenance and status reports.
471 */
472
473 valerie_error_code dv_demo_queue_maintenance( dv_demo demo, dv_demo_queue queue )
474 {
475         printf( "Queue Maintenance for Unit %d\n\n", queue->unit );
476
477         if ( !queue->mode )
478         {
479                 char ch;
480                 printf( "Activate queueing? [Y] " );
481                 ch = get_keypress( );
482                 if ( ch == 'y' || ch == 'Y' || ch == '\r' )
483                         queue->mode = 1;
484                 printf( "\n\n" );
485         }
486
487         if ( queue->mode )
488         {
489                 int terminated = 0;
490                 int last_position = -2;
491
492                 term_init( );
493
494                 while ( !terminated )
495                 {
496                         int first = ( queue->position + 1 ) % 50;
497                         int index = first;
498
499                         if ( first == queue->tail )
500                                 index = first = queue->head;
501
502                         if ( queue->head == queue->tail )
503                         {
504                                 if ( last_position == -2 )
505                                 {
506                                         printf( "Queue is empty\n" );
507                                         printf( "\n" );
508                                         printf( "0 = exit, t = turn off queueing\n\n" );
509                                         last_position = -1;
510                                 }
511                         }
512                         else if ( last_position != queue->position )
513                         {
514                                 printf( "Order of play\n\n" );
515
516                                 do 
517                                 {
518                                         printf( "%c%02d: %s\n", index == first ? '*' : ' ', index, queue->list[ index ] + 1 );
519                                         index = ( index + 1 ) % 50;
520                                         if ( index == queue->tail )
521                                                 index = queue->head;
522                                 }
523                                 while( index != first );
524         
525                                 printf( "\n" );
526                                 printf( "0 = exit, t = turn off queueing, c = clear queue\n\n" );
527                                 last_position = queue->position;
528                         }
529
530                         dv_demo_change_status( demo, 1 );
531                         
532                         switch( term_read( ) )
533                         {
534                                 case -1:
535                                         break;
536                                 case '0':
537                                         terminated = 1;
538                                         break;
539                                 case 't':
540                                         terminated = 1;
541                                         queue->mode = 0;
542                                         break;
543                                 case 'c':
544                                         queue->head = queue->tail = 0;
545                                         queue->position = -1;
546                                         last_position = -2;
547                                         break;
548                         }
549
550                         dv_demo_change_status( demo, 0 );
551                 }
552
553                 term_exit( );
554         }
555
556         return valerie_ok;
557 }
558
559 /** Load a file to the selected unit. Horrible function - sorry :-/. Not a good
560         demo....
561 */
562
563 valerie_error_code dv_demo_load( dv_demo demo )
564 {
565         valerie_error_code error = valerie_ok;
566         int terminated = 0;
567         int refresh = 1;
568         int start = 0;
569
570         strcpy( demo->current_directory, demo->last_directory );
571
572         term_init( );
573
574         while ( !terminated )
575         {
576                 valerie_dir dir = valerie_dir_init( demo->dv, demo->current_directory );
577
578                 if ( valerie_dir_count( dir ) == -1 )
579                 {
580                         printf( "Invalid directory - retrying %s\n", demo->last_directory );
581                         valerie_dir_close( dir );
582                         dir = valerie_dir_init( demo->dv, demo->last_directory );
583                         if ( valerie_dir_count( dir ) == -1 )
584                         {
585                                 printf( "Invalid directory - going back to /\n" );
586                                 valerie_dir_close( dir );
587                                 dir = valerie_dir_init( demo->dv, "/" );
588                                 strcpy( demo->current_directory, "/" );
589                         }
590                         else
591                         {
592                                 strcpy( demo->current_directory, demo->last_directory );
593                         }
594                 }
595
596                 terminated = valerie_dir_count( dir ) == -1;
597
598                 if ( !terminated )
599                 {
600                         int index = 0;
601                         int selected = 0;
602                         int max = 9;
603                         int end = 0;
604
605                         end = valerie_dir_count( dir );
606
607                         strcpy( demo->last_directory, demo->current_directory );
608
609                         while ( !selected && !terminated )
610                         {
611                                 valerie_dir_entry_t entry;
612                                 int pressed;
613
614                                 if ( refresh )
615                                 {
616                                         const char *action = "Load & Play";
617                                         if ( demo->queues[ demo->selected_unit ].mode )
618                                                 action = "Queue";
619                                         printf( "%s from %s\n\n", action, demo->current_directory );
620                                         if ( strcmp( demo->current_directory, "/" ) )
621                                                 printf( "-: Parent directory\n" );
622                                         for ( index = start; index < end && ( index - start ) < max; index ++ )
623                                         {
624                                                 valerie_dir_get( dir, index, &entry );
625                                                 printf( "%d: %s\n", index - start + 1, entry.name );
626                                         }
627                                         while ( ( index ++ % 9 ) != 0 )
628                                                 printf( "\n" );
629                                         printf( "\n" );
630                                         if ( start + max < end )
631                                                 printf( "space = more files" );
632                                         else if ( end > max )
633                                                 printf( "space = return to start of list" );
634                                         if ( start > 0 )
635                                                 printf( ", b = previous files" );
636                                         printf( "\n" );
637                                         printf( "0 = abort, t = transport, x = execute command, q = queue maintenance\n\n" );
638                                         refresh = 0;
639                                 }
640
641                                 dv_demo_change_status( demo, 1 );
642
643                                 pressed = term_read( );
644                                 switch( pressed )
645                                 {
646                                         case -1:
647                                                 break;
648                                         case '0':
649                                                 terminated = 1;
650                                                 break;
651                                         case 'b':
652                                                 refresh = start - max >= 0;
653                                                 if ( refresh )
654                                                         start = start - max;
655                                                 break;
656                                         case ' ':
657                                                 refresh = start + max < end;
658                                                 if ( refresh )
659                                                 {
660                                                         start = start + max;
661                                                 }
662                                                 else if ( end > max )
663                                                 {
664                                                         start = 0;
665                                                         refresh = 1;
666                                                 }
667                                                 break;
668                                         case '-':
669                                                 if ( strcmp( demo->current_directory, "/" ) )
670                                                 {
671                                                         selected = 1;
672                                                         ( *strrchr( demo->current_directory, '/' ) ) = '\0';
673                                                         ( *( strrchr( demo->current_directory, '/' ) + 1 ) ) = '\0';
674                                                 }
675                                                 break;
676                                         case 't':
677                                                 dv_demo_change_status( demo, 0 );
678                                                 term_exit( );
679                                                 dv_demo_transport( demo );
680                                                 term_init( );
681                                                 selected = 1;
682                                                 break;
683                                         case 'x':
684                                                 dv_demo_change_status( demo, 0 );
685                                                 term_exit( );
686                                                 dv_demo_execute( demo );
687                                                 term_init( );
688                                                 selected = 1;
689                                                 break;
690                                         case 'q':
691                                                 dv_demo_change_status( demo, 0 );
692                                                 term_exit( );
693                                                 dv_demo_queue_maintenance( demo, &demo->queues[ demo->selected_unit ] );
694                                                 term_init( );
695                                                 selected = 1;
696                                                 break;
697                                         default:
698                                                 if ( pressed >= '1' && pressed <= '9' )
699                                                 {
700                                                         if ( ( start + pressed - '1' ) < end )
701                                                         {
702                                                                 valerie_dir_get( dir, start + pressed - '1', &entry );
703                                                                 selected = 1;
704                                                                 strcat( demo->current_directory, entry.name );
705                                                         }
706                                                 }
707                                                 break;
708                                 }
709
710                                 dv_demo_change_status( demo, 0 );
711                         }
712
713                         valerie_dir_close( dir );
714                 }
715
716                 if ( !terminated && demo->current_directory[ strlen( demo->current_directory ) - 1 ] != '/' )
717                 {
718                         if ( demo->queues[ demo->selected_unit ].mode == 0 )
719                         {
720                                 error = valerie_unit_load( demo->dv, demo->selected_unit, demo->current_directory );
721                                 valerie_unit_play( demo->dv, demo->selected_unit );
722                         }
723                         else
724                         {
725                                 dv_demo_queue_add( demo, &demo->queues[ demo->selected_unit ], demo->current_directory );
726                                 printf( "File %s added to queue.\n", demo->current_directory );
727                         }
728                         strcpy( demo->current_directory, demo->last_directory );
729                         refresh = 0;
730                 }
731                 else
732                 {
733                         refresh = 1;
734                         start = 0;
735                 }
736         }
737
738         term_exit( );
739
740         return error;
741 }
742
743 /** Set the in point of the clip on the select unit.
744 */
745
746 valerie_error_code dv_demo_set_in( dv_demo demo )
747 {
748         int position = 0;
749         valerie_status_t status;
750         valerie_notifier notifier = valerie_parser_get_notifier( demo->parser );
751         valerie_notifier_get( notifier, &status, demo->selected_unit );
752         position = status.position;
753         return valerie_unit_set_in( demo->dv, demo->selected_unit, position );
754 }
755
756 /** Set the out point of the clip on the selected unit.
757 */
758
759 valerie_error_code dv_demo_set_out( dv_demo demo )
760 {
761         int position = 0;
762         valerie_status_t status;
763         valerie_notifier notifier = valerie_parser_get_notifier( demo->parser );
764         valerie_notifier_get( notifier, &status, demo->selected_unit );
765         position = status.position;
766         return valerie_unit_set_out( demo->dv, demo->selected_unit, position );
767 }
768
769 /** Clear the in and out points on the selected unit.
770 */
771
772 valerie_error_code dv_demo_clear_in_out( dv_demo demo )
773 {
774         return valerie_unit_clear_in_out( demo->dv, demo->selected_unit );
775 }
776
777 /** Goto a user specified frame on the selected unit.
778 */
779
780 valerie_error_code dv_demo_goto( dv_demo demo )
781 {
782         int frame = 0;
783         printf( "Frame: " );
784         if ( get_int( &frame, 0 ) )
785                 return valerie_unit_goto( demo->dv, demo->selected_unit, frame );
786         return valerie_ok;
787 }
788
789 /** Manipulate playback on the selected unit.
790 */
791
792 valerie_error_code dv_demo_transport( dv_demo demo )
793 {
794         valerie_error_code error = valerie_ok;
795         int refresh = 1;
796         int terminated = 0;
797         valerie_status_t status;
798         valerie_notifier notifier = valerie_get_notifier( demo->dv );
799
800         while ( !terminated )
801         {
802                 if ( refresh )
803                 {
804                         printf( "  +----+ +------+ +----+ +------+ +---+ +-----+ +------+ +-----+ +---+  \n" );
805                         printf( "  |1=-5| |2=-2.5| |3=-1| |4=-0.5| |5=1| |6=0.5| |7=1.25| |8=2.5| |9=5|  \n" );
806                         printf( "  +----+ +------+ +----+ +------+ +---+ +-----+ +------+ +-----+ +---+  \n" );
807                         printf( "\n" );
808                         printf( "+----------------------------------------------------------------------+\n" );
809                         printf( "|              0 = quit, x = eXecute, 'space' = pause                  |\n" );
810                         printf( "|              g = goto a frame, q = queue maintenance                 |\n" );
811                         printf( "|     h = step -1, j = end of clip, k = start of clip, l = step 1      |\n" );
812                         printf( "|        eof handling: p = pause, r = repeat, t = terminate            |\n" );
813                         printf( "|       i = set in point, o = set out point, c = clear in/out          |\n" );
814                         printf( "|       u = use point settings, d = don't use point settings           |\n" );
815                         printf( "+----------------------------------------------------------------------+\n" );
816                         printf( "\n" );
817                         term_init( );
818                         refresh = 0;
819                 }
820
821                 dv_demo_change_status( demo, 1 );
822
823                 switch( term_read( ) )
824                 {
825                         case '0':
826                                 terminated = 1;
827                                 break;
828                         case -1:
829                                 break;
830                         case ' ':
831                                 error = valerie_unit_pause( demo->dv, demo->selected_unit );
832                                 break;
833                         case '1':
834                                 error = valerie_unit_play_at_speed( demo->dv, demo->selected_unit, -5000 );
835                                 break;
836                         case '2':
837                                 error = valerie_unit_play_at_speed( demo->dv, demo->selected_unit, -2500 );
838                                 break;
839                         case '3':
840                                 error = valerie_unit_play_at_speed( demo->dv, demo->selected_unit, -1000 );
841                                 break;
842                         case '4':
843                                 error = valerie_unit_play_at_speed( demo->dv, demo->selected_unit, -500 );
844                                 break;
845                         case '5':
846                                 error = valerie_unit_play( demo->dv, demo->selected_unit );
847                                 break;
848                         case '6':
849                                 error = valerie_unit_play_at_speed( demo->dv, demo->selected_unit, 500 );
850                                 break;
851                         case '7':
852                                 error = valerie_unit_play_at_speed( demo->dv, demo->selected_unit, 1250 );
853                                 break;
854                         case '8':
855                                 error = valerie_unit_play_at_speed( demo->dv, demo->selected_unit, 2500 );
856                                 break;
857                         case '9':
858                                 error = valerie_unit_play_at_speed( demo->dv, demo->selected_unit, 5000 );
859                                 break;
860                         case 's':
861                                 error = valerie_unit_goto( demo->dv, demo->selected_unit, 0 );
862                                 break;
863                         case 'h':
864                                 error = valerie_unit_step( demo->dv, demo->selected_unit, -1 );
865                                 break;
866                         case 'j':
867                                 valerie_notifier_get( notifier, &status, demo->selected_unit );
868                                 error = valerie_unit_goto( demo->dv, demo->selected_unit, status.tail_out );
869                                 break;
870                         case 'k':
871                                 valerie_notifier_get( notifier, &status, demo->selected_unit );
872                                 error = valerie_unit_goto( demo->dv, demo->selected_unit, status.in );
873                                 break;
874                         case 'l':
875                                 error = valerie_unit_step( demo->dv, demo->selected_unit, 1 );
876                                 break;
877                         case 'p':
878                                 error = valerie_unit_set( demo->dv, demo->selected_unit, "eof", "pause" );
879                                 break;
880                         case 'r':
881                                 error = valerie_unit_set( demo->dv, demo->selected_unit, "eof", "loop" );
882                                 break;
883                         case 't':
884                                 error = valerie_unit_set( demo->dv, demo->selected_unit, "eof", "stop" );
885                                 break;
886                         case 'i':
887                                 error = dv_demo_set_in( demo );
888                                 break;
889                         case 'o':
890                                 error = dv_demo_set_out( demo );
891                                 break;
892                         case 'g':
893                                 dv_demo_change_status( demo, 0 );
894                                 term_exit( );
895                                 error = dv_demo_goto( demo );
896                                 refresh = 1;
897                                 break;
898                         case 'c':
899                                 error = dv_demo_clear_in_out( demo );
900                                 break;
901                         case 'u':
902                                 error = valerie_unit_set( demo->dv, demo->selected_unit, "points", "use" );
903                                 break;
904                         case 'd':
905                                 error = valerie_unit_set( demo->dv, demo->selected_unit, "points", "ignore" );
906                                 break;
907                         case 'x':
908                                 dv_demo_change_status( demo, 0 );
909                                 term_exit( );
910                                 dv_demo_execute( demo );
911                                 refresh = 1;
912                                 break;
913                         case 'q':
914                                 dv_demo_change_status( demo, 0 );
915                                 term_exit( );
916                                 dv_demo_queue_maintenance( demo, &demo->queues[ demo->selected_unit ] );
917                                 refresh = 1;
918                                 break;
919                 }
920
921                 dv_demo_change_status( demo, 0 );
922         }
923
924         term_exit( );
925
926         return error;
927 }
928
929 /** Recursive menu execution.
930 */
931
932 valerie_error_code dv_demo_run_menu( dv_demo demo, dv_demo_menu menu )
933 {
934         const char *items = "123456789abcdefghijklmnopqrstuvwxyz";
935         int refresh_menu = 1;
936         int terminated = 0;
937         int item_count = 0;
938         int item_selected = 0;
939         int index = 0;
940         char key;
941
942         while( !terminated )
943         {
944
945                 if ( refresh_menu )
946                 {
947                         printf( "%s\n\n", menu->description );
948                         for ( index = 0; menu->array[ index ].option != NULL; index ++ )
949                                 printf( "%c: %s\n", items[ index ], menu->array[ index ].option );
950                         printf( "0: Exit\n\n" );
951                         printf( "Select Option: " );
952                         refresh_menu = 0;
953                         item_count = index;
954                 }
955
956                 key = get_keypress( );
957
958                 if ( demo->disconnected && key != '0' )
959                 {
960                         valerie_error_code error = valerie_connect( demo->dv );
961                         if ( error == valerie_ok )
962                                 demo->disconnected = 0;
963                         else
964                                 beep();
965                 }
966
967                 if ( !demo->disconnected || key == '0' )
968                 {
969                         item_selected = strchr( items, key ) - items;
970
971                         if ( key == '0' )
972                         {
973                                 printf( "%c\n\n", key );
974                                 terminated = 1;
975                         }
976                         else if ( item_selected >= 0 && item_selected < item_count )
977                         {
978                                 printf( "%c\n\n", key );
979                                 menu->array[ item_selected ].function( demo );
980                                 refresh_menu = 1;
981                         }
982                         else
983                         {
984                                 beep( );
985                         }
986                 }
987         }
988
989         return valerie_ok;
990 }
991
992 /** Entry point for main menu.
993 */
994
995 void dv_demo_run( dv_demo this )
996 {
997         this->dv = valerie_init( this->parser );
998         this->dv_status = valerie_init( this->parser );
999         if ( valerie_connect( this->dv ) == valerie_ok )
1000         {
1001                 pthread_create( &this->thread, NULL, dv_demo_status_thread, this );
1002                 dv_demo_run_menu( this, &connected_menu );
1003                 this->terminated = 1;
1004                 pthread_join( this->thread, NULL );
1005                 this->terminated = 0;
1006         }
1007         else
1008         {
1009                 printf( "Unable to connect." );
1010                 wait_for_any_key( "" );
1011         }
1012
1013         valerie_close( this->dv_status );
1014         valerie_close( this->dv );
1015
1016         printf( "Demo Exit.\n" );
1017 }
1018
1019 /** Close the demo structure.
1020 */
1021
1022 void dv_demo_close( dv_demo demo )
1023 {
1024         free( demo );
1025 }