}
}
- if(renderengine->command->single_frame() && !renderengine->command->audio_toggle)
+ if(renderengine->command->single_frame() && !renderengine->command->toggle_audio)
current_render_length = 1;
if(current_render_length < 0) current_render_length = 0;
current_position += current_render_length;
int64_t start_position, end_position;
- int play_loop = renderengine->command->play_loop;
+ int play_loop = renderengine->command->loop_play;
int loop_playback = renderengine->get_edl()->local_session->loop_playback;
if( play_loop || !loop_playback ) {
start_position = tounits(renderengine->command->start_position, 0);
transport->change_position(position);
}
else
- transport->handle_transport(next_command, 0, 0);
+ transport->handle_transport(next_command);
return 1;
}
#include <locale.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/time.h>
+#include <sys/resource.h>
#ifdef LEAKER
#define STRC(v) printf("==new %p from %p sz %jd\n", v, __builtin_return_address(0), n)
time_t et; time(&et);
long dt = et - st;
printf("Session time: %ld:%02ld:%02ld\n", dt/3600, dt%3600/60, dt%60);
+ struct rusage ru;
+ getrusage(RUSAGE_SELF, &ru);
+ long usr_ms = ru.ru_utime.tv_sec*1000 + ru.ru_utime.tv_usec/1000;
+ long us = usr_ms/1000; int ums = usr_ms%1000;
+ long sys_ms = ru.ru_stime.tv_sec*1000 + ru.ru_stime.tv_usec/1000;
+ long ss = sys_ms/1000; int sms = sys_ms%1000;
+ printf("Cpu time: user: %ld:%02ld:%02ld.%03d sys: %ld:%02ld:%02ld.%03d\n",
+ us/3600, us%3600/60, us%60, ums, ss/3600, ss%3600/60, ss%60, sms);
return 0;
}
zwindows_lock->unlock();
}
-void MWindow::queue_mixers(EDL *edl, int command, int wait_tracking,
- int use_inout, int update_refresh, int toggle_audio, int loop_play)
+void MWindow::handle_mixers(EDL *edl, int command, int wait_tracking,
+ int use_inout, int toggle_audio, int loop_play, float speed)
{
- zwindows_lock->lock("MWindow::queue_mixers");
+ zwindows_lock->lock("MWindow::handle_mixers");
for( int vidx=0; vidx<zwindows.size(); ++vidx ) {
ZWindow *zwindow = zwindows[vidx];
if( zwindow->idx < 0 ) continue;
track->record = track->play = 0;
}
zwindow->change_source(mixer_edl);
- zwindow->issue_command(command,
- wait_tracking, use_inout, update_refresh, toggle_audio, loop_play);
+ zwindow->handle_mixer(command, wait_tracking,
+ use_inout, toggle_audio, loop_play, speed);
}
zwindows_lock->unlock();
}
void MWindow::refresh_mixers(int dir)
{
int command = dir >= 0 ? CURRENT_FRAME : LAST_FRAME;
- queue_mixers(edl,command,0,0,1,0,0);
+ handle_mixers(edl, command, 0, 0, 0, 0, 0);
}
void MWindow::stop_mixers()
for( int vidx=0; vidx<zwindows.size(); ++vidx ) {
ZWindow *zwindow = zwindows[vidx];
if( zwindow->idx < 0 ) continue;
- zwindow->issue_command(STOP, 0, 0, 0, 0, 0);
+ zwindow->handle_mixer(STOP, 0, 0, 0, 0, 0);
}
}
void MWindow::undo_before(const char *description, void *creator)
{
- if( cwindow->playback_engine->is_playing_back ) {
- undo_command = cwindow->playback_engine->command->command;
- cwindow->playback_engine->que->send_command(STOP, CHANGE_NONE, 0, 0);
- gui->unlock_window();
- cwindow->playback_engine->interrupt_playback(1);
- gui->lock_window(description);
- }
undo->update_undo_before(description, creator);
}
void MWindow::undo_after(const char *description, uint32_t load_flags, int changes_made)
{
- if( undo_command != COMMAND_NONE ) {
- cwindow->playback_engine->que->send_command(undo_command, CHANGE_NONE, edl, 1, 0);
- undo_command = COMMAND_NONE;
- }
-
undo->update_undo_after(description, load_flags, changes_made);
}
if( in_destructor ) return;
// Sync engines which are playing back
- if(cwindow->playback_engine->is_playing_back)
- {
- if(change_type == CHANGE_PARAMS)
- {
+ if( cwindow->playback_engine->is_playing_back ) {
+ if( change_type == CHANGE_PARAMS ) {
// TODO: block keyframes until synchronization is done
cwindow->playback_engine->sync_parameters(edl);
}
- else
+ else {
// Stop and restart
- {
int command = cwindow->playback_engine->command->command;
- cwindow->playback_engine->que->send_command(STOP,
- CHANGE_NONE,
- 0,
- 0);
+ cwindow->playback_engine->transport_stop();
// Waiting for tracking to finish would make the restart position more
// accurate but it can't lock the window to stop tracking for some reason.
// Not waiting for tracking gives a faster response but restart position is
// only as accurate as the last tracking update.
cwindow->playback_engine->interrupt_playback(0);
- cwindow->playback_engine->que->send_command(command,
- change_type,
- edl,
- 1,
- 0);
+ cwindow->playback_engine->next_command->realtime = 1;
+ cwindow->playback_engine->transport_command(command, change_type, edl, 0);
}
}
- else
- {
+ else {
cwindow->refresh_frame(change_type);
}
}
void undo_before(const char *description = "", void *creator = 0);
void undo_after(const char *description, uint32_t load_flags, int changes_made = 1);
- void queue_mixers(EDL *edl, int command, int wait_tracking,
- int use_inout, int update_refresh, int toggle_audio, int loop_play);
+ void handle_mixers(EDL *edl, int command, int wait_tracking,
+ int use_inout, int toggle_audio, int loop_play, float speed);
ZWindow *create_mixer(Indexable *indexable);
void create_mixers();
void refresh_mixers(int dir=1);
{
if( !mbuttons->transport->is_stopped() ) {
if( lock_msg ) unlock_window();
- mbuttons->transport->handle_transport(STOP, 1, 0, 0);
+ mbuttons->transport->handle_transport(STOP, 1);
if( lock_msg ) lock_window(lock_msg);
}
}
command->command = NORMAL_FWD;
command->get_edl()->copy_all(edl);
command->change_type = CHANGE_ALL;
- command->set_playback_range(edl);
+ command->set_playback_range();
default_asset->frame_rate = command->get_edl()->session->frame_rate;
default_asset->sample_rate = command->get_edl()->session->sample_rate;
tracking_active = 0;
audio_cache = 0;
video_cache = 0;
- last_command = STOP;
+ command = new TransportCommand();
+ command->command = STOP;
+ next_command = new TransportCommand();
+ next_command->change_type = CHANGE_ALL;
+ curr_command = new TransportCommand();
+ stop_command = new TransportCommand();
+ stop_command->command = STOP;
tracking_lock = new Mutex("PlaybackEngine::tracking_lock");
renderengine_lock = new Mutex("PlaybackEngine::renderengine_lock");
tracking_done = new Condition(1, "PlaybackEngine::tracking_done");
pause_lock = new Condition(0, "PlaybackEngine::pause_lock");
start_lock = new Condition(0, "PlaybackEngine::start_lock");
+ input_lock = new Condition(1, "PlaybackEngine::input_lock");
+ output_lock = new Condition(0, "PlaybackEngine::output_lock", 1);
+
render_engine = 0;
debug = 0;
}
PlaybackEngine::~PlaybackEngine()
{
done = 1;
- que->send_command(STOP,
- CHANGE_NONE,
- 0,
- 0);
+ transport_stop();
interrupt_playback();
Thread::join();
delete preferences;
- delete command;
- delete que;
delete_render_engine();
delete audio_cache;
delete video_cache;
delete pause_lock;
delete start_lock;
delete renderengine_lock;
+ delete command;
+ delete next_command;
+ delete curr_command;
+ delete stop_command;
+ delete input_lock;
+ delete output_lock;
}
void PlaybackEngine::create_objects()
{
preferences = new Preferences;
- command = new TransportCommand;
- que = new TransportQue;
-// Set the first change to maximum
- que->command.change_type = CHANGE_ALL;
-
preferences->copy_from(mwindow->preferences);
done = 0;
void PlaybackEngine::perform_change()
{
- switch(command->change_type)
+ switch( command->change_type )
{
case CHANGE_ALL:
create_cache();
// Interpolate
{
double loop_start, loop_end;
- int play_loop = command->play_loop ? 1 : 0;
+ int play_loop = command->loop_play ? 1 : 0;
EDL *edl = command->get_edl();
int loop_playback = edl->local_session->loop_playback ? 1 : 0;
if( play_loop || !loop_playback ) {
while( !done ) {
// Wait for current command to finish
- que->output_lock->lock("PlaybackEngine::run");
+ output_lock->lock("PlaybackEngine::run");
wait_render_engine();
// Read the new command
- que->input_lock->lock("PlaybackEngine::run");
- if(done) return;
-
- command->copy_from(&que->command);
- que->command.reset();
- que->input_lock->unlock();
+ input_lock->lock("PlaybackEngine::run");
+ if( done ) return;
+ command->copy_from(curr_command);
+ input_lock->unlock();
//printf("PlaybackEngine::run 1 %d\n", command->command);
switch( command->command ) {
// Parameter change only
case COMMAND_NONE:
-// command->command = last_command;
perform_change();
break;
case CURRENT_FRAME:
case LAST_FRAME:
- last_command = command->command;
perform_change();
arm_render_engine();
// Dispatch the command
case SINGLE_FRAME_REWIND:
// fall through
default:
- last_command = command->command;
is_playing_back = 1;
perform_change();
void PlaybackEngine::stop_playback(int wait)
{
- que->send_command(STOP, CHANGE_NONE, 0, 0);
+ transport_stop();
interrupt_playback(wait);
renderengine_lock->lock("PlaybackEngine::stop_playback");
if(render_engine)
}
-void PlaybackEngine::issue_command(EDL *edl, int command, int wait_tracking,
- int use_inout, int update_refresh, int toggle_audio, int loop_play)
+void PlaybackEngine::send_command(int command, EDL *edl, int wait_tracking, int use_inout)
{
-//printf("PlaybackEngine::issue_command 1 %d\n", command);
+//printf("PlaybackEngine::send_command 1 %d\n", command);
// Stop requires transferring the output buffer to a refresh buffer.
- int do_stop = 0, resume = 0;
- int prev_command = this->command->command;
- int prev_single_frame = this->command->single_frame();
- int prev_audio = this->command->audio_toggle ?
- !prev_single_frame : prev_single_frame;
- int cur_single_frame = TransportCommand::single_frame(command);
- int cur_audio = toggle_audio ?
- !cur_single_frame : cur_single_frame;
+ int do_stop = 0, do_resume = 0;
+ int curr_command = this->command->command;
+ int curr_single_frame = TransportCommand::single_frame(curr_command);
+ int curr_audio = this->command->toggle_audio ?
+ !curr_single_frame : curr_single_frame;
+ int single_frame = TransportCommand::single_frame(command);
+ int next_audio = next_command->toggle_audio ? !single_frame : single_frame;
// Dispatch command
- switch(command) {
+ switch( command ) {
case FAST_REWIND: // Commands that play back
case NORMAL_REWIND:
case SLOW_REWIND:
case FAST_FWD:
case CURRENT_FRAME:
case LAST_FRAME:
- if( !prev_single_frame &&
- prev_command == command &&
- cur_audio == prev_audio ) {
-// Same direction pressed twice and no change in audio state, Stop
+ if( curr_command == command && !next_command->speed &&
+ !curr_single_frame && curr_audio == next_audio ) {
+// Same direction pressed twice, not shuttle, and no change in audio state, Stop
do_stop = 1;
break;
}
// Resume or change direction
- switch( prev_command ) {
+ switch( curr_command ) {
default:
- que->send_command(STOP, CHANGE_NONE, 0, 0);
+ transport_stop();
interrupt_playback(wait_tracking);
- resume = 1;
+ do_resume = 1;
// fall through
case STOP:
case COMMAND_NONE:
case SINGLE_FRAME_REWIND:
case CURRENT_FRAME:
case LAST_FRAME:
+ next_command->realtime = 1;
+ next_command->resume = do_resume;
// Start from scratch
- que->send_command(command, CHANGE_NONE, edl,
- 1, resume, use_inout, toggle_audio, loop_play,
- mwindow->preferences->forward_render_displacement);
+ transport_command(command, CHANGE_NONE, edl, use_inout);
break;
}
break;
}
if( do_stop ) {
- que->send_command(STOP, CHANGE_NONE, 0, 0);
+ transport_stop();
interrupt_playback(wait_tracking);
}
}
+int PlaybackEngine::transport_stop()
+{
+ input_lock->lock("PlaybackEngine::transport_stop 1");
+ curr_command->copy_from(stop_command);
+ input_lock->unlock();
+ output_lock->unlock();
+ return 0;
+}
+
+int PlaybackEngine::transport_command(int command, int change_type, EDL *new_edl, int use_inout)
+{
+ input_lock->lock("PlaybackEngine::transport_command 1");
+ next_command->command = command;
+ next_command->change_type |= change_type;
+ if( new_edl ) {
+// Just change the EDL if the change requires it because renderengine
+// structures won't point to the new EDL otherwise and because copying the
+// EDL for every cursor movement is slow.
+ switch( change_type ) {
+ case CHANGE_EDL:
+ case CHANGE_ALL:
+ next_command->get_edl()->copy_all(new_edl);
+ break;
+ case CHANGE_PARAMS:
+ next_command->get_edl()->synchronize_params(new_edl);
+ break;
+ }
+ next_command->set_playback_range(new_edl, use_inout,
+ preferences->forward_render_displacement);
+ }
+ curr_command->copy_from(next_command);
+ next_command->reset();
+ input_lock->unlock();
+ output_lock->unlock();
+ return 0;
+}
+
void PlaybackEngine::refresh_frame(int change_type, EDL *edl, int dir)
{
- que->send_command(dir >= 0 ? CURRENT_FRAME : LAST_FRAME,
- change_type, edl, 1);
+ int command = dir >= 0 ? CURRENT_FRAME : LAST_FRAME;
+ next_command->realtime = 1;
+ transport_command(command, change_type, edl);
}
#include "renderengine.inc"
#include "thread.h"
#include "bctimer.h"
-#include "transportque.inc"
+#include "transportque.h"
class PlaybackEngine : public Thread
{
ChannelDB* get_channeldb();
void run();
+ void send_command(int command, EDL *edl, int wait_tracking, int use_inout);
void stop_playback(int wait);
- void issue_command(EDL *edl, int command, int wait_tracking,
- int use_inout, int update_refresh, int toggle_audio, int loop_play);
void refresh_frame(int change_type, EDL *edl, int dir=1);
// Maintain caches through console changes
Canvas *output;
// Copy of main preferences
Preferences *preferences;
-// Next command
- TransportQue *que;
-// Currently executing command
- TransportCommand *command;
-// Last command which affected transport
- int last_command;
- int done;
- int do_cwindow;
+
+ int transport_stop();
+ int transport_command(int command, int change_type=CHANGE_NONE,
+ EDL *new_edl=0, int use_inout=0);
+
+ Condition *input_lock, *output_lock;
+// active command
+ TransportCommand *command, *stop_command;
+ TransportCommand *curr_command, *next_command;
+
// Render engine
RenderEngine *render_engine;
-// Used by label commands to get current position
+ int done;
int is_playing_back;
// General purpose debugging register
#include "playbackengine.h"
#include "playtransport.h"
#include "preferences.h"
+#include "shuttle.h"
#include "theme.h"
#include "transportque.h"
#include "vframe.h"
goto_end();
return result;
}
-// as in play_command
+
int ctrl_key = subwindow->ctrl_down() ? 1 : 0;
int shft_key = subwindow->shift_down() ? 1 : 0;
int alt_key = subwindow->alt_down() ? 1 : 0;
int use_inout = ctrl_key;
int toggle_audio = shft_key & ~ctrl_key;
int loop_play = shft_key & ctrl_key;
- int command = -1, prev_command = engine->command->command;
- using_inout = use_inout;
+ float speed = 0;
+ int command = -1;
+ int curr_command = engine->command->command;
subwindow->unlock_window();
result = 0;
- switch( key ) {
+
+ if( key >= SKEY_MIN && key <= SKEY_MAX ) {
+ speed = SHUTTLE_MAX_SPEED *
+ (key - (SKEY_MAX + SKEY_MIN)/2.f) /
+ ((SKEY_MAX - SKEY_MIN) / 2.f);
+ if( speed < 0 ) {
+ speed = -speed;
+ command = speed < 1 ? SLOW_REWIND :
+ speed > 1 ? FAST_REWIND : NORMAL_REWIND;
+ }
+ else if( speed > 0 ) {
+ command = speed < 1 ? SLOW_FWD :
+ speed > 1 ? FAST_FWD : NORMAL_FWD;
+ }
+ else
+ command = STOP;
+ use_inout = 0;
+ loop_play = 0;
+ }
+ else switch( key ) {
case KPINS: command = STOP; break;
case KPPLUS: command = FAST_REWIND; break;
case KP6: command = NORMAL_REWIND; break;
case KP2: command = SLOW_FWD; break;
case KP3: command = NORMAL_FWD; break;
case KPENTER: command = FAST_FWD; break;
+
case ' ':
- switch( prev_command ) {
+ switch( curr_command ) {
case COMMAND_NONE:
case CURRENT_FRAME:
case LAST_FRAME:
break;
}
if( command >= 0 ) {
- handle_transport(command, 0, use_inout, 1, toggle_audio, loop_play);
+ handle_transport(command, 0, use_inout, toggle_audio, loop_play, speed);
result = 1;
}
void PlayTransport::goto_start()
{
- handle_transport(REWIND, 1, 0);
+ handle_transport(REWIND, 1);
}
void PlayTransport::goto_end()
{
- handle_transport(GOTO_END, 1, 0);
+ handle_transport(GOTO_END, 1);
}
-void PlayTransport::handle_transport(int command, int wait_tracking, int use_inout,
- int update_refresh, int toggle_audio, int loop_play)
+void PlayTransport::handle_transport(int command, int wait_tracking,
+ int use_inout, int toggle_audio, int loop_play, float speed)
{
EDL *edl = get_edl();
if( !edl ) return;
+ using_inout = use_inout;
+
if( !is_vwindow() )
- mwindow->queue_mixers(edl, command, wait_tracking, use_inout, update_refresh, toggle_audio, 0);
- engine->issue_command(edl, command, wait_tracking, use_inout, update_refresh, toggle_audio, loop_play);
+ mwindow->handle_mixers(edl, command, wait_tracking,
+ use_inout, toggle_audio, 0, speed);
+ engine->next_command->toggle_audio = toggle_audio;
+ engine->next_command->loop_play = loop_play;
+ engine->next_command->speed = speed;
+ engine->send_command(command, edl, wait_tracking, use_inout);
}
EDL* PlayTransport::get_edl()
int toggle_audio = shft_key & ~ctrl_key;
int loop_play = shft_key & ctrl_key;
unlock_window();
- transport->handle_transport(command, 0, use_inout, 0, toggle_audio, loop_play);
+ transport->handle_transport(command, 0, use_inout, toggle_audio, loop_play, 0);
lock_window(lock_msg);
return 1;
}
int StopButton::handle_event()
{
unlock_window();
- transport->handle_transport(STOP, 0, 0);
+ transport->handle_transport(STOP);
lock_window("StopButton::handle_event");
return 1;
}
void PlayTransport::change_position(double position)
{
if( !get_edl() ) return;
- int prev_command = engine->command->command;
+ int command = engine->command->command;
// stop transport
- if( prev_command != STOP && prev_command != COMMAND_NONE &&
- prev_command != SINGLE_FRAME_FWD && prev_command != SINGLE_FRAME_REWIND ) {
- engine->que->send_command(STOP, CHANGE_NONE, 0, 0);
+ if( command != STOP && command != COMMAND_NONE &&
+ command != SINGLE_FRAME_FWD && command != SINGLE_FRAME_REWIND ) {
+ engine->transport_stop();
engine->interrupt_playback(0);
}
mwindow->gui->lock_window("PlayTransport::change_position");
mwindow->goto_position(position);
mwindow->gui->unlock_window();
// restart command
- switch(prev_command) {
+ switch( command ) {
case FAST_REWIND:
case NORMAL_REWIND:
case SLOW_REWIND:
case SLOW_FWD:
case NORMAL_FWD:
case FAST_FWD:
- engine->que->send_command(prev_command, CHANGE_NONE,
- get_edl(), 1, 1, using_inout, 0);
+ engine->next_command->realtime = 1;
+ engine->next_command->resume = 1;
+ engine->transport_command(command, CHANGE_NONE, get_edl(), using_inout);
}
}
int flip_vertical(int vertical, int &x, int &y);
int keypress_event();
int do_keypress(int key);
-// Abstract TransportQue::send_command.
+// Abstract transport send_command.
// wait_tracking - causes stop to wail until the final tracking position
// is updated before returning
// use_inout - causes the in/out points to determine the beginning and end
// the refresh frame.
// toggle_audio - reverses audio playback enable in RenderEngine::get_duty
// loop_play - sets play_loop and plays btwn start/end position (in a loop)
+// speed - play speed for SLOW/FAST playback, zero defaults to slow=.5,fast=2.
void handle_transport(int command, int wait_tracking=0,
- int use_inout=0, int update_refresh=1, int toggle_audio=0,
- int loop_play=0);
+ int use_inout=0, int toggle_audio=0, int loop_play=0, float speed=0);
int pause_transport();
int reset_transport();
int get_w();
get_edl()->session->audio_channels )
{
do_audio = !command->single_frame() ? 1 : 0;
- if( command->audio_toggle ) do_audio = !do_audio;
+ if( command->toggle_audio ) do_audio = !do_audio;
}
//printf("RenderEngine::get_duty %d\n", __LINE__);
playback_engine->tracking_position = position >= 0 ? position : 0;
}
- if(!interrupted) playback_engine->command->command = STOP;
+ if( !interrupted )
+ playback_engine->command->command = STOP;
playback_engine->stop_tracking();
}
#include "cstrdup.h"
#include "file.h"
#include "guicast.h"
+#include "keys.h"
#include "linklist.h"
#include "loadfile.h"
#include "mainmenu.h"
}
KeySymMapping KeySymMapping::key_sym_mapping[] = {
+// button keycodes
{ "XK_Button_1", XK_Button_1 },
{ "XK_Button_2", XK_Button_2 },
{ "XK_Button_3", XK_Button_3 },
KeySym KeySymMapping::to_keysym(const char *str)
{
+ if( !strncmp("FWD_",str, 4) ) {
+ float speed = atof(str+4) / SHUTTLE_MAX_SPEED;
+ if( speed > SHUTTLE_MAX_SPEED ) return 0;
+ int key_code = (SKEY_MAX+SKEY_MIN)/2. +
+ (SKEY_MAX-SKEY_MIN)/2. * speed;
+ if( key_code > SKEY_MAX ) key_code = SKEY_MAX;
+ return key_code;
+ }
+ if( !strncmp("REV_",str, 4) ) {
+ float speed = atof(str+4) / SHUTTLE_MAX_SPEED;
+ if( speed > SHUTTLE_MAX_SPEED ) return 0;
+ int key_code = (SKEY_MAX+SKEY_MIN)/2. -
+ (SKEY_MAX-SKEY_MIN)/2. * speed;
+ if( key_code < SKEY_MIN ) key_code = SKEY_MIN;
+ return key_code;
+ }
for( KeySymMapping *ksp = &key_sym_mapping[0]; ksp->str; ++ksp )
if( !strcmp(str, ksp->str) ) return ksp->sym;
return 0;
{
for( KeySymMapping *ksp = &key_sym_mapping[0]; ksp->sym; ++ksp )
if( ksp->sym == ks ) return ksp->str;
+ if( ks >= SKEY_MIN && ks <= SKEY_MAX ) {
+ double speed = SHUTTLE_MAX_SPEED *
+ (ks-(SKEY_MAX+SKEY_MIN)/2.) / ((SKEY_MAX-SKEY_MIN)/2.);
+ static char text[BCSTRLEN];
+ sprintf(text, "%s_%0.3f", speed>=0 ? "FWD" : "REV", fabs(speed));
+ char *bp = strchr(text,'.');
+ if( bp ) {
+ char *cp = bp+strlen(bp);
+ while( --cp>bp && *cp=='0' ) *cp=0;
+ if( cp == bp ) *cp = 0;
+ }
+ return text;
+ }
return 0;
}
memset(b, 0, sizeof(*b));
b->type = press ? ButtonPress : ButtonRelease;
b->time = milliTimeClock();
+ b->send_event = 1;
b->display = wdw->top_level->display;
b->root = wdw->top_level->rootwin;
b->window = win;
wdw->top_level->put_event((XEvent *) b);
return 0;
}
-int Shuttle::send_key(KeySym keysym, int press)
+int Shuttle::send_keycode(unsigned int keycode, int press, int send)
{
- KeyCode keycode = XKeysymToKeycode(wdw->top_level->display, keysym);
- if( debug )
- printf("key: %04x %d\n", (unsigned)keycode, press);
+ if( debug ) {
+ const char *cp = !send ? 0 :
+ KeySymMapping::to_string(keycode);
+ if( cp )
+ printf("key: %s %d\n", cp, press);
+ else
+ printf("key: %04x %d\n", keycode, press);
+ }
XKeyEvent *k = new XKeyEvent();
memset(k, 0, sizeof(*k));
k->type = press ? KeyPress : KeyRelease;
k->time = milliTimeClock();
+ k->send_event = send;
k->display = wdw->top_level->display;
k->root = wdw->top_level->rootwin;
k->window = win;
{
return keysym >= XK_Button_1 && keysym <= XK_Scroll_Down ?
send_button((unsigned int)keysym - XK_Button_0, press) :
- send_key(keysym, press ? True : False);
+ send_keycode((unsigned int)keysym, press, 1);
+// unsigned int keycode = XKeysymToKeycode(wdw->top_level->display, keysym);
+// return send_keycode(keycode, press, 0);
}
}
-void Shuttle:: shuttle(int value)
+void Shuttle::shuttle(int value)
{
if( value < S_7 || value > S7 ) {
fprintf(stderr, "shuttle(%d) out of range\n", value);
Display *dpy = gui->display;
Window focus = 0;
int ret = 0, revert = 0;
- char win_title[BCTEXTLEN];
+ char win_title[BCTEXTLEN]; win_title[0] = 0;
gui->lock_window("Shuttle::get_focused_window_translation");
XGetInputFocus(dpy, &focus, &revert);
if( last_focused != focus ) {
wdw = mwindow->cwindow->gui->canvas->get_canvas();
cin = FOCUS_CWINDOW;
}
- else if( (wdw=mwindow->gui->mainmenu->load_file->thread->window) != 0 &&
+ else if( mwindow->gui->mainmenu->load_file->thread->running() &&
+ (wdw=mwindow->gui->mainmenu->load_file->thread->window) != 0 &&
wdw->win == focus )
cin = FOCUS_LOAD;
else {
// delay in ms before processing each XTest event
// CurrentTime means no delay
#define DELAY CurrentTime
+// playback max speed -64x .. 64x
+#define SHUTTLE_MAX_SPEED 64.
// protocol for events from the shuttlepro HUD device
//
~Shuttle();
int send_button(unsigned int button, int press);
- int send_key(KeySym keysym, int press);
+ int send_keycode(unsigned int keycode, int press, int send);
int send_keysym(KeySym keysym, int press);
void send_stroke_sequence(int kjs, int index);
void key(unsigned short code, unsigned int value);
PlaybackEngine *playback_engine = mwindow->cwindow->playback_engine;
if( playback_engine->is_playing_back )
playback_engine->stop_playback(1);
- mwindow->cwindow->playback_engine->refresh_frame(CHANGE_EDL, edl, 0);
+ mwindow->cwindow->playback_engine->refresh_frame(CHANGE_NONE, edl, 0);
break; }
}
return result;
#include "edl.h"
#include "edlsession.h"
#include "localsession.h"
+#include "playbackengine.h"
#include "tracks.h"
#include "transportque.h"
infinite = 0;
realtime = 0;
resume = 0;
- audio_toggle = 0;
- play_loop = 0;
- displacement = 0;
+ toggle_audio = 0;
+ loop_play = 0;
+ speed = 0;
// Don't reset the change type for commands which don't perform the change
if(command != STOP) change_type = 0;
command = COMMAND_NONE;
this->playbackstart = command->playbackstart;
this->realtime = command->realtime;
this->resume = command->resume;
- this->audio_toggle = command->audio_toggle;
- this->play_loop = command->play_loop;
+ this->toggle_audio = command->toggle_audio;
+ this->loop_play = command->loop_play;
this->displacement = command->displacement;
+ this->speed = command->speed;
}
TransportCommand& TransportCommand::operator=(TransportCommand &command)
return (command == SINGLE_FRAME_FWD || command == SINGLE_FRAME_REWIND ||
command == CURRENT_FRAME || command == LAST_FRAME);
}
-int TransportCommand::single_frame()
-{
- return single_frame(command);
-}
-
int TransportCommand::get_direction(int command)
{
}
return PLAY_FORWARD;
}
-int TransportCommand::get_direction()
-{
- return get_direction(command);
-}
-float TransportCommand::get_speed(int command)
+float TransportCommand::get_speed(int command, float speed)
{
switch(command) {
case SLOW_FWD:
case SLOW_REWIND:
- return 0.5;
+ return speed ? speed : 0.5;
case NORMAL_FWD:
case NORMAL_REWIND:
case FAST_FWD:
case FAST_REWIND:
- return 2.;
+ return speed ? speed : 2.;
}
return 0.;
}
-float TransportCommand::get_speed()
-{
- return get_speed(command);
-}
// Assume starting without pause
-void TransportCommand::set_playback_range(EDL *edl,
- int use_inout, int toggle_audio, int loop_play, int use_displacement)
+void TransportCommand::set_playback_range(EDL *edl, int use_inout, int do_displacement)
{
- if(!edl) edl = this->edl;
+ if( !edl ) edl = this->edl;
double length = edl->tracks->total_playable_length();
double frame_period = 1.0 / edl->session->frame_rate;
-
displacement = 0;
- audio_toggle = toggle_audio;
- play_loop = loop_play;
start_position = use_inout && edl->local_session->inpoint_valid() ?
edl->local_session->get_inpoint() :
break;
}
- if( use_displacement && (
- (command != CURRENT_FRAME && get_direction() == PLAY_FORWARD ) ||
- (command != LAST_FRAME && get_direction() == PLAY_REVERSE ) ) ) {
- start_position += frame_period;
- end_position += frame_period;
- displacement = 1;
+ if( realtime && do_displacement ) {
+ if( (command != CURRENT_FRAME && get_direction() == PLAY_FORWARD ) ||
+ (command != LAST_FRAME && get_direction() == PLAY_REVERSE ) ) {
+ start_position += frame_period;
+ end_position += frame_period;
+ displacement = 1;
+ }
}
}
+// if( start_position < 0 )
+// start_position = 0;
+// if( end_position > length )
+// end_position = length;
if( end_position < start_position )
end_position = start_position;
}
-TransportQue::TransportQue()
-{
- input_lock = new Condition(1, "TransportQue::input_lock");
- output_lock = new Condition(0, "TransportQue::output_lock", 1);
-}
-
-TransportQue::~TransportQue()
-{
- delete input_lock;
- delete output_lock;
-}
-
-int TransportQue::send_command(int command, int change_type,
- EDL *new_edl, int realtime, int resume, int use_inout,
- int toggle_audio, int loop_play, int use_displacement)
-{
- input_lock->lock("TransportQue::send_command 1");
- this->command.command = command;
-// Mutually exclusive operation
- this->command.change_type |= change_type;
- this->command.realtime = realtime;
- this->command.resume = resume;
-
- if(new_edl)
- {
-// Just change the EDL if the change requires it because renderengine
-// structures won't point to the new EDL otherwise and because copying the
-// EDL for every cursor movement is slow.
- if(change_type == CHANGE_EDL ||
- (uint32_t)change_type == CHANGE_ALL)
- {
-// Copy EDL
- this->command.get_edl()->copy_all(new_edl);
- }
- else
- if(change_type == CHANGE_PARAMS)
- {
- this->command.get_edl()->synchronize_params(new_edl);
- }
-
-// Set playback range
- this->command.set_playback_range(new_edl, use_inout,
- toggle_audio, loop_play, use_displacement);
- }
-
- input_lock->unlock();
-
- output_lock->unlock();
- return 0;
-}
-
-void TransportQue::update_change_type(int change_type)
-{
- input_lock->lock("TransportQue::update_change_type");
- this->command.change_type |= change_type;
- input_lock->unlock();
-}
*
*/
-#ifndef TRANSPORTQUE_H
-#define TRANSPORTQUE_H
+#ifndef __TRANSPORTQUE_H__
+#define __TRANSPORTQUE_H__
#include "canvas.inc"
#include "condition.inc"
#include "edl.inc"
-#include "preferences.inc"
+#include "playbackengine.inc"
#include "transportque.inc"
class TransportCommand
~TransportCommand();
void reset();
- static int single_frame(int command);
- int single_frame();
-// Get the direction based on the command
- static int get_direction(int command);
- int get_direction();
- static float get_speed(int command);
- float get_speed();
void copy_from(TransportCommand *command);
TransportCommand& operator=(TransportCommand &command);
// Get the range to play back from the EDL
- void set_playback_range(EDL *edl=0, int use_inout=0,
- int toggle_audio=0, int loop_play=0, int use_displacement=0);
+ void set_playback_range(EDL *edl, int use_inout, int do_displacement);
+ static int single_frame(int command);
+ static int get_direction(int command);
+ static float get_speed(int command, float speed=0);
// Adjust playback range with in/out points for rendering
void playback_range_adjust_inout();
void delete_edl();
void new_edl();
+ PlaybackEngine *engine;
int command;
int change_type;
-// lowest numbered second in playback range
- double start_position;
-// highest numbered second in playback range
- double end_position;
+// playback range
+ double start_position, end_position;
int infinite;
// Position used when starting playback
double playbackstart;
-// start position at this=0/next=1 frame
+// start at this=0/next=1 frame
int displacement;
// Send output to device
int realtime;
// Use persistant starting point
int resume;
// reverse audio duty
- int audio_toggle;
+ int toggle_audio;
// playback loop
- int play_loop;
+ int loop_play;
+// SLOW,FAST play speed
+ float speed;
+
+ int single_frame() { return single_frame(command); }
+ int get_direction() { return get_direction(command); }
+ float get_speed() { return get_speed(command, speed); }
+ void set_playback_range() { set_playback_range(0, 0, 0); }
private:
// Copied to render engines
EDL *edl;
};
-class TransportQue
-{
-public:
- TransportQue();
- ~TransportQue();
-
- int send_command(int command,
-// The change type is ORed to accumulate changes.
- int change_type, EDL *new_edl, int realtime,
-// Persistent starting point
- int resume = 0, int use_inout = 0, int toggle_audio = 0,
- int loop_play = 0, int use_displacement = 0);
- void update_change_type(int change_type);
-
- TransportCommand command;
- Condition *input_lock, *output_lock;
-};
-
#endif
*
*/
-#ifndef TRANSPORTQUE_INC
-#define TRANSPORTQUE_INC
+#ifndef __TRANSPORTQUE_INC__
+#define __TRANSPORTQUE_INC__
// Directions
#define PLAY_FORWARD 0
#define CHANGE_NONE 0x0
class TransportCommand;
-class TransportQue;
#endif
{
if( !transport->is_stopped() ) {
unlock_window();
- transport->handle_transport(STOP, 1, 0, 0);
+ transport->handle_transport(STOP, 1);
lock_window("VWindowGUI::panel_stop_transport");
}
}
zgui->playback_engine->stop_playback(wait);
}
-void ZWindow::issue_command(int command, int wait_tracking,
- int use_inout, int update_refresh, int toggle_audio, int loop_play)
+void ZWindow::handle_mixer(int command, int wait_tracking,
+ int use_inout, int toggle_audio, int loop_play, float speed)
{
- zgui->playback_engine->issue_command(edl, command,
- wait_tracking, use_inout, update_refresh, toggle_audio, loop_play);
+ PlaybackEngine *engine = zgui->playback_engine;
+ engine->next_command->toggle_audio = toggle_audio;
+ engine->next_command->loop_play = loop_play;
+ engine->next_command->speed = speed;
+ engine->send_command(command, edl, wait_tracking, use_inout);
}
void ZWindow::update_mixer_ids()
void handle_close_event(int result);
void change_source(EDL *edl);
void stop_playback(int wait);
- void issue_command(int command, int wait_tracking, int use_inout,
- int update_refresh, int toggle_audio, int loop_play);
+ void handle_mixer(int command, int wait_tracking,
+ int use_inout, int toggle_audio, int loop_play, float speed);
void update_mixer_ids();
void set_title(const char *tp);
void reposition(int x, int y, int w, int h);
}
else {
#endif
-
- switch(keysym) {
+// shuttle speed codes
+ if( keysym >= SKEY_MIN && keysym <= SKEY_MAX ) {
+ key_pressed = keysym;
+ }
+ else switch( keysym ) {
// block out extra keys
case XK_Alt_L:
case XK_Alt_R:
#define RETURN 13
#define NEWLINE 13
+#define SKEY_MIN 0x3000000 // Shuttle speed codes
+#define SKEY_MAX 0x3010000
+
#endif
K3 "c" # Pro Only - Copy
K4 "v" # Pro Only - Paste
- S-3 XK_KP_Add # Fast reverse
- S-2 XK_KP_6 # Play reverse
- S-1 XK_KP_5 # Slow reverse
- S0 XK_KP_0 # Stop
- S1 XK_KP_2 # Slow forward
- S2 XK_KP_3 # Play forward
- S3 XK_KP_Enter # Fast forward
+ S-7 REV_16 # Next 7 are reverse keys
+ S-6 REV_8 # the number on the end represents speed
+ S-5 REV_4 # number can be decimal up to 64
+ S-4 REV_2 # 2 means 2x or double speed
+ S-3 REV_1
+ S-2 REV_0.5 # note 0.25 represents 1/4 speed
+ S-1 REV_0.25
+ S0 XK_KP_0 # Stop
+ S1 FWD_0.25 # Next 7 are forward keys
+ S2 FWD_0.5
+ S3 FWD_1
+ S4 FWD_2
+ S5 FWD_4
+ S6 FWD_8
+ S7 FWD_16
JL XK_KP_4 # Frame reverse
JR XK_KP_1 # Frame forward