double TimeBar::get_edl_length()
{
	edl_length = 0;

	if(get_edl())
	{
//printf("TimeBar::get_edl_length 1 %f\n", get_edl()->tracks->total_playable_length());
		edl_length = get_edl()->tracks->total_playable_length();
	}

//printf("TimeBar::get_edl_length 2\n");
	if(!EQUIV(edl_length, 0))
	{
//printf("TimeBar::get_edl_length 3\n");
		time_per_pixel = edl_length / get_w();
//printf("TimeBar::get_edl_length 4\n");
	}
	else
	{
		time_per_pixel = 0;
	}
//printf("TimeBar::get_edl_length 5\n");

	return edl_length;
}
Beispiel #2
0
void PlayTransport::change_position(double position)
{
	EDL *edl = get_edl();
	if( !edl ) return;
	int prev_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, 0, 0);
		engine->interrupt_playback(0);
	}
	mwindow->gui->lock_window("PlayTransport::change_position");
	mwindow->goto_position(position);
	mwindow->gui->unlock_window();
// restart command
	switch(prev_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);
	}
}
void TimeBar::update(int flush)
{
	draw_time();
// Need to redo these when range is drawn to get the background updated.
	update_labels();
	update_points();


 	EDL *edl = get_edl();
	int64_t pixel = -1;

// Draw highlight position
	if(edl &&
		(highlighted || current_operation == TIMEBAR_DRAG) &&
		get_cursor_x() >= 0 &&
		get_cursor_y() < get_w())
	{
//printf("TimeBar::update %d %d\n", __LINE__, get_cursor_x());
		double position = pixel_to_position(get_cursor_x());

		position = get_edl()->align_to_frame(position, 0);
		pixel = position_to_pixel(position);
		update_clock(position);
	}

	if(pixel < 0) 
	{
		double position = test_highlight();
		if(position >= 0) pixel = position_to_pixel(position);
	}


	if(pixel >= 0 && pixel < get_w())
	{
		set_color(mwindow->theme->timebar_cursor_color);
		set_line_dashes(1);
//printf("TimeBar::update %d pane=%d pixel=%jd\n", __LINE__, pane->number, pixel);
		draw_line(pixel, 0, pixel, get_h());
		set_line_dashes(0);
	}
	

 	if(edl)
 	{
 		int64_t pixel = position_to_pixel(
 			edl->local_session->get_selectionstart(1));
// Draw insertion point position.
 		set_color(mwindow->theme->timebar_cursor_color);
 		draw_line(pixel, 0, pixel, get_h());
 	}

	update_highlights();

// Get the labels to show	
	show_window(0);
	flash(flush);
//printf("TimeBar::update %d this=%p %d\n", __LINE__, this, current_operation);
}
Beispiel #4
0
void VWindow::goto_start()
{
	if(get_edl())
	{
		get_edl()->local_session->set_selectionstart(0);
		get_edl()->local_session->set_selectionend(0);
		update_position(CHANGE_NONE, 
			0, 
			1);
	}
}
Beispiel #5
0
void VWindow::goto_end()
{
	if(get_edl())
	{
		double position = get_edl()->tracks->total_length();
		get_edl()->local_session->set_selectionstart(position);
		get_edl()->local_session->set_selectionend(position);
		update_position(CHANGE_NONE, 
			0, 
			1);
	}
}
Beispiel #6
0
void VWindow::change_source()
{
//printf("VWindow::change_source() 1 %p\n", mwindow->edl->vwindow_edl);
	if(mwindow->edl->vwindow_edl)
	{
		gui->change_source(get_edl(), get_edl()->local_session->clip_title);
		update_position(CHANGE_ALL, 1, 1);
	}
	else
	{
		if(asset) Garbage::delete_object(asset);
		asset = 0;
		mwindow->edl->vwindow_edl_shared = 0;
	}
}
void TimeBar::draw_range()
{
 	int x1 = 0, x2 = get_w();


//printf("TimeBar::draw_range %d %p\n", __LINE__, get_edl());
 	if(get_edl())
 	{
// 		get_preview_pixels(x1, x2);
// 
// //printf("TimeBar::draw_range %f %d %d\n", edl_length, x1, x2);
// 		draw_3segmenth(0, 0, x1, mwindow->theme->timebar_view_data);
 		draw_top_background(get_parent(), x1, 0, x2 - x1, get_h());
// 		draw_3segmenth(x2, 0, get_w() - x2, mwindow->theme->timebar_view_data);
// 
// 		set_color(BLACK);
// 		draw_line(x1, 0, x1, get_h());
// 		draw_line(x2, 0, x2, get_h());
// 		

//  		EDL *edl = get_edl();
//  		if(edl)
//  		{
//  			int64_t pixel = position_to_pixel(
//  				edl->local_session->get_selectionstart(1));
// // Draw insertion point position if this timebar belongs to a window which 
// // has something other than the master EDL.
//  			set_color(mwindow->theme->timebar_cursor_color);
//  			draw_line(pixel, 0, pixel, get_h());
//  		}
 	}
 	else
		draw_top_background(get_parent(), 0, 0, get_w(), get_h());
}
Beispiel #8
0
void VWindow::update_position(int change_type, 
	int use_slider, 
	int update_slider)
{
	EDL *edl = get_edl();
	if(edl)
	{
		Asset *asset = edl->assets->first;
		if(use_slider) 
		{
			edl->local_session->set_selectionstart(gui->slider->get_value());
			edl->local_session->set_selectionend(gui->slider->get_value());
		}

		if(update_slider)
		{
			gui->slider->set_position();
		}

		playback_engine->que->send_command(CURRENT_FRAME, 
			change_type,
			edl,
			1);

		gui->clock->update(edl->local_session->get_selectionstart(1) +
			asset->tcstart / 
			(asset->video_data ? asset->frame_rate : asset->sample_rate));
	}
}
Beispiel #9
0
void VWindow::set_outpoint()
{
	EDL *edl = get_edl();
	if(edl)
	{
		edl->set_outpoint(edl->local_session->get_selectionstart(1));
		gui->timebar->update();
	}
}
Beispiel #10
0
void VWindow::clear_outpoint()
{
	EDL *edl = get_edl();
	if(edl)
	{
		edl->local_session->unset_outpoint();
		gui->timebar->update();
	}
}
Beispiel #11
0
double VTimeBar::pixel_to_position(int pixel)
{
	double start = 0, length = 0;
	EDL *edl = get_edl();
	if(edl)
	{
		start = edl->local_session->preview_start;
		if(start >= 0)
			length = edl->local_session->preview_end - start;
	}
	if(length <= 0)
		length = get_edl_length();
	return start + (double)pixel * length / get_w();
}
Beispiel #12
0
void VTimeBar::select_label(double position)
{
	EDL *edl = get_edl();

	if(edl)
	{
		unlock_window();
		gui->transport->handle_transport(STOP, 1, 0, 0);
		lock_window();

		position = mwindow->edl->align_to_frame(position, 1);

		if(shift_down())
		{
			if(position > edl->local_session->get_selectionend(1) / 2 + 
				edl->local_session->get_selectionstart(1) / 2)
			{

				edl->local_session->set_selectionend(position);
			}
			else
			{
				edl->local_session->set_selectionstart(position);
			}
		}
		else
		{
			edl->local_session->set_selectionstart(position);
			edl->local_session->set_selectionend(position);
		}

// Que the CWindow
		gui->vwindow->update_position(CHANGE_NONE, 
			0, 
			1,
			0);
		update(1);
	}
}
Beispiel #13
0
void VWindow::copy()
{
	EDL *edl = get_edl();
	if(edl)
	{
		double start = edl->local_session->get_selectionstart();
		double end = edl->local_session->get_selectionend();
		FileXML file;
		edl->copy(start,
			end,
			0,
			0,
			0,
			&file,
			mwindow->plugindb,
			"",
			1);
		mwindow->gui->lock_window();
		mwindow->gui->get_clipboard()->to_clipboard(file.string,
			strlen(file.string),
			SECONDARY_SELECTION);
		mwindow->gui->unlock_window();
	}
}
Beispiel #14
0
void PlayTransport::handle_transport(int command, 
	int wait_tracking,
	int use_inout,
	int update_refresh)
{
	if(!get_edl()) return;

// Stop requires transferring the output buffer to a refresh buffer.
	int do_stop = 0;
//printf("PlayTransport::handle_transport 1 %d\n", command);
	int prev_command = engine->command->command;
	int prev_direction = engine->command->get_direction();
	int prev_single_frame = engine->command->single_frame();

// Dispatch command
	switch(command)
	{
// Commands that play back
		case FAST_REWIND:
		case NORMAL_REWIND:
		case SLOW_REWIND:
		case SINGLE_FRAME_REWIND:
		case SINGLE_FRAME_FWD:
		case SLOW_FWD:
		case NORMAL_FWD:
		case FAST_FWD:
// Same direction pressed twice.  Stop
			if(prev_command == command && 
				!prev_single_frame)
			{
				do_stop = 1;
			}
			else
// Resume or change direction
			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,
					0,
					0);
				engine->interrupt_playback(wait_tracking);
				engine->que->send_command(command,
					CHANGE_NONE, 
					get_edl(),
					1,
					1,
					use_inout);
			}
			else
// Start from scratch
			{
				engine->que->send_command(command,
					CHANGE_NONE, 
					get_edl(),
					1,
					0,
					use_inout);
			}
			break;

// Commands that stop
		case STOP:
			do_stop = 1;
			break;

		case REWIND:
		case GOTO_END:
			engine->que->send_command(STOP,
				CHANGE_NONE, 
				0,
				0,
				0,
				0);
			engine->interrupt_playback(wait_tracking);
			break;
	}

	if(do_stop)
	{
		engine->que->send_command(STOP,
			CHANGE_NONE, 
			0,
			0,
			0,
			0);
		engine->interrupt_playback(wait_tracking);
// This is necessary to get an OpenGL output buffer
// printf("PlayTransport::handle_transport 2 update_refresh=%d prev_command=%d prev_direction=%d\n", 
// update_refresh, prev_command, prev_direction);
		if(!prev_single_frame && 
			update_refresh &&
			prev_command != STOP &&
			prev_command != COMMAND_NONE)
		{
			engine->que->send_command(
				(prev_direction == PLAY_FORWARD) ? SINGLE_FRAME_REWIND : SINGLE_FRAME_FWD,
				CHANGE_NONE, 
				get_edl(),
				1,
				0,
				0);
		}
	}
}
Beispiel #15
0
int AModule::render(Samples *buffer, 
	int64_t input_len,
	int64_t start_position,
	int direction,
	int sample_rate,
	int use_nudge)
{
	int64_t edl_rate = get_edl()->session->sample_rate;
	const int debug = 0;

if(debug) printf("AModule::render %d\n", __LINE__);

	if(use_nudge) 
		start_position += track->nudge * 
			sample_rate /
			edl_rate;
	AEdit *playable_edit;
	int64_t end_position;
	if(direction == PLAY_FORWARD)
		end_position = start_position + input_len;
	else
		end_position = start_position - input_len;
	int buffer_offset = 0;
	int result = 0;


// // Flip range around so the source is always read forward.
// 	if(direction == PLAY_REVERSE)
// 	{
// 		start_project -= input_len;
// 		end_position -= input_len;
// 	}


// Clear buffer
	bzero(buffer->get_data(), input_len * sizeof(double));

// The EDL is normalized to the requested sample rate because 
// the requested rate may be the project sample rate and a sample rate 
// might as well be directly from the source rate to the requested rate.
// Get first edit containing the range
	if(direction == PLAY_FORWARD)
		playable_edit = (AEdit*)track->edits->first;
	else
		playable_edit = (AEdit*)track->edits->last;
if(debug) printf("AModule::render %d\n", __LINE__);

	while(playable_edit)
	{
		int64_t edit_start = playable_edit->startproject;
		int64_t edit_end = playable_edit->startproject + playable_edit->length;

// Normalize to requested rate
		edit_start = edit_start * sample_rate / edl_rate;
		edit_end = edit_end * sample_rate / edl_rate;

		if(direction == PLAY_FORWARD)
		{
			if(start_position < edit_end && end_position > edit_start)
			{
				break;
			}
			playable_edit = (AEdit*)playable_edit->next;
		}
		else
		{
			if(end_position < edit_end && start_position > edit_start)
			{
				break;
			}
			playable_edit = (AEdit*)playable_edit->previous;
		}
	}


if(debug) printf("AModule::render %d\n", __LINE__);





// Fill output one fragment at a time
	while(start_position != end_position)
	{
		int64_t fragment_len = input_len;

if(debug) printf("AModule::render %d " _LD " " _LD "\n", __LINE__, start_position, end_position);
// Clamp fragment to end of input
		if(direction == PLAY_FORWARD &&
			start_position + fragment_len > end_position)
			fragment_len = end_position - start_position;
		else
		if(direction == PLAY_REVERSE &&
			start_position - fragment_len < end_position)
			fragment_len = start_position - end_position;
if(debug) printf("AModule::render %d " _LD "\n", __LINE__, fragment_len);

// Normalize position here since update_transition is a boolean operation.
		update_transition(start_position * 
				edl_rate / 
				sample_rate, 
			PLAY_FORWARD);

		if(playable_edit)
		{
			AEdit *previous_edit = (AEdit*)playable_edit->previous;

// Normalize EDL positions to requested rate
			int64_t edit_startproject = playable_edit->startproject;
			int64_t edit_endproject = playable_edit->startproject + playable_edit->length;
			int64_t edit_startsource = playable_edit->startsource;
if(debug) printf("AModule::render %d " _LD "\n", __LINE__, fragment_len);

			edit_startproject = edit_startproject * sample_rate / edl_rate;
			edit_endproject = edit_endproject * sample_rate / edl_rate;
			edit_startsource = edit_startsource * sample_rate / edl_rate;
if(debug) printf("AModule::render %d " _LD "\n", __LINE__, fragment_len);



// Clamp fragment to end of edit
			if(direction == PLAY_FORWARD &&
				start_position + fragment_len > edit_endproject)
				fragment_len = edit_endproject - start_position;
			else
			if(direction == PLAY_REVERSE &&
				start_position - fragment_len < edit_startproject)
				fragment_len = start_position - edit_startproject;
if(debug) printf("AModule::render %d " _LD "\n", __LINE__, fragment_len);

// Clamp to end of transition
			int64_t transition_len = 0;
			
			if(transition &&
				previous_edit)
			{
				transition_len = transition->length * 
					sample_rate / 
					edl_rate;
				if(direction == PLAY_FORWARD &&
					start_position < edit_startproject + transition_len &&
					start_position + fragment_len > edit_startproject + transition_len)
					fragment_len = edit_startproject + transition_len - start_position;
				else
				if(direction == PLAY_REVERSE && 
					start_position > edit_startproject + transition_len &&
					start_position - fragment_len < edit_startproject + transition_len)
					fragment_len = start_position - edit_startproject - transition_len;
			}
if(debug) printf("AModule::render %d buffer_offset=%d fragment_len=" _LD "\n", 
__LINE__, 
buffer_offset,
fragment_len);

			Samples output(buffer);
			output.set_offset(output.get_offset() + buffer_offset);
			if(import_samples(playable_edit, 
				start_position,
				edit_startproject,
				edit_startsource,
				direction,
				sample_rate,
				&output,
				fragment_len)) result = 1;

if(debug) printf("AModule::render %d\n", __LINE__);


// Read transition into temp and render
			if(transition && previous_edit)
			{
				int64_t previous_startproject = previous_edit->startproject *
					sample_rate /
					edl_rate;
				int64_t previous_startsource = previous_edit->startsource *
					sample_rate /
					edl_rate;

// Allocate transition temp size
				int transition_fragment_len = fragment_len;
				if(direction == PLAY_FORWARD &&
					fragment_len + start_position > edit_startproject + transition_len)
					fragment_len = edit_startproject + transition_len - start_position;


// Read into temp buffers
// Temp + master or temp + temp ? temp + master
				if(transition_temp && 
					transition_temp->get_allocated() < fragment_len)
				{
					delete transition_temp;
					transition_temp = 0;
				}

				if(!transition_temp)
				{
					transition_temp = new Samples(fragment_len);
				}

if(debug) printf("AModule::render %d " _LD "\n", __LINE__, fragment_len);

				if(transition_fragment_len > 0)
				{
// Previous_edit is always the outgoing segment, regardless of direction
					import_samples(previous_edit, 
						start_position,
						previous_startproject,
						previous_startsource,
						direction,
						sample_rate,
						transition_temp,
						transition_fragment_len);
					int64_t current_position;

// Reverse buffers here so transitions always render forward.
					if(direction == PLAY_REVERSE)
					{
						Resample::reverse_buffer(output.get_data(), transition_fragment_len);
						Resample::reverse_buffer(transition_temp->get_data(), transition_fragment_len);
						current_position = start_position - 
							transition_fragment_len -
							edit_startproject;
					}
					else
					{
						current_position = start_position - edit_startproject;
					}

					transition_server->process_transition(
						transition_temp,
						&output,
						current_position,
						transition_fragment_len,
						transition->length);

// Reverse output buffer here so transitions always render forward.
					if(direction == PLAY_REVERSE)
						Resample::reverse_buffer(output.get_data(), 
							transition_fragment_len);
				}
			}
if(debug) printf("AModule::render %d start_position=" _LD " end_position=" _LD " fragment_len=" _LD "\n", 
__LINE__, 
start_position,
end_position,
fragment_len);

			if(direction == PLAY_REVERSE)
			{
				if(playable_edit && start_position - fragment_len <= edit_startproject)
					playable_edit = (AEdit*)playable_edit->previous;
			}
			else
			{
				if(playable_edit && start_position + fragment_len >= edit_endproject)
					playable_edit = (AEdit*)playable_edit->next;
			}
		}

		if(fragment_len > 0)
		{
			buffer_offset += fragment_len;
			if(direction == PLAY_FORWARD)
				start_position += fragment_len;
			else
				start_position -= fragment_len;
		}
	}

if(debug) printf("AModule::render %d\n", __LINE__);

	return result;
}
Beispiel #16
0
int AModule::import_samples(AEdit *edit, 
	int64_t start_project,
	int64_t edit_startproject,
	int64_t edit_startsource,
	int direction,
	int sample_rate,
	Samples *buffer,
	int64_t fragment_len)
{
	int result = 0;
// start in EDL samplerate
	int64_t start_source = start_project - 
		edit_startproject + 
		edit_startsource;
// fragment size adjusted for speed curve
	int64_t speed_fragment_len = fragment_len;
// boundaries of input fragment required for speed curve
	double max_position = 0;
	double min_position = 0;

	double speed_position = edit_startsource;
// position in source where speed curve starts reading
	double speed_position1 = speed_position;
// position in source where speed curve finishes
	double speed_position2 = speed_position;

// Need speed curve processing
	int have_speed = 0;
// Temporary buffer for rendering speed curve
	Samples *speed_buffer = buffer;
	const int debug = 0;

if(debug) printf("AModule::import_samples %d edit=%p nested_edl=%p\n", 
__LINE__,
edit,
nested_edl);
	if(nested_edl && edit->channel >= nested_edl->session->audio_channels)
		return 1;
if(debug) printf("AModule::import_samples %d\n", __LINE__);

	this->channel = edit->channel;
if(debug) printf("AModule::import_samples %d speed_fragment_len=%ld\n", 
__LINE__,
speed_fragment_len);




// apply speed curve to source position so the timeline agrees with the playback
	if(track->has_speed())
	{
// get speed adjusted position from start of edit.
		FloatAuto *previous = 0;
		FloatAuto *next = 0;
		FloatAutos *speed_autos = (FloatAutos*)track->automation->autos[AUTOMATION_SPEED];
		for(int64_t i = edit_startproject; i < start_project; i++)
		{
			double speed = speed_autos->get_value(i, 
				PLAY_FORWARD,
				previous,
				next);
			speed_position += speed;
		}

		speed_position1 = speed_position;


// calculate boundaries of input fragment required for speed curve
		max_position = speed_position;
		min_position = speed_position;
		for(int64_t i = start_project; i < start_project + fragment_len; i++)
		{
			double speed = speed_autos->get_value(i, 
				PLAY_FORWARD,
				previous,
				next);
			speed_position += speed;
			if(speed_position > max_position) max_position = speed_position;
			if(speed_position < min_position) min_position = speed_position;
		}

		speed_position2 = speed_position;
		if(speed_position2 < speed_position1)
		{
			max_position += 1.0;
//			min_position -= 1.0;
			speed_fragment_len = (int64_t)(max_position - min_position);
		}
		else
		{
			max_position += 1.0;
			speed_fragment_len = (int64_t)(max_position - min_position);
		}

printf("AModule::import_samples %d %f %f %f %f\n", 
__LINE__, 
min_position, 
max_position,
speed_position1,
speed_position2);

// new start of source to read from file
		start_source = (int64_t)min_position;
		have_speed = 1;



// swap in the temp buffer
		if(speed_temp && speed_temp->get_allocated() < speed_fragment_len)
		{
			delete speed_temp;
			speed_temp = 0;
		}
		
		if(!speed_temp)
		{
			speed_temp = new Samples(speed_fragment_len);
		}
		
		speed_buffer = speed_temp;
	}



	if(speed_fragment_len == 0)
		return 1;



// Source is a nested EDL
	if(edit->nested_edl)
	{
		int command;
		asset = 0;
		
		if(direction == PLAY_REVERSE)
			command = NORMAL_REWIND;
		else
			command = NORMAL_FWD;

if(debug) printf("AModule::import_samples %d\n", __LINE__);
		if(!nested_edl || nested_edl->id != edit->nested_edl->id)
		{
			nested_edl = edit->nested_edl;
			if(nested_renderengine)
			{
				delete nested_renderengine;
				nested_renderengine = 0;
			}

			if(!nested_command)
			{
				nested_command = new TransportCommand;
			}


			if(!nested_renderengine)
			{
				nested_command->command = command;
				nested_command->get_edl()->copy_all(nested_edl);
				nested_command->change_type = CHANGE_ALL;
				nested_command->realtime = renderengine->command->realtime;
				nested_renderengine = new RenderEngine(0,
					get_preferences(), 
					0,
					renderengine ? renderengine->channeldb : 0,
					1);
				nested_renderengine->set_acache(get_cache());
// Must use a private cache for the audio
// 				if(!cache) 
// 				{
// 					cache = new CICache(get_preferences());
// 					private_cache = 1;
// 				}
// 				nested_renderengine->set_acache(cache);
				nested_renderengine->arm_command(nested_command);
			}
		}
if(debug) printf("AModule::import_samples %d speed_fragment_len=%d\n", __LINE__, (int)speed_fragment_len);

// Allocate output buffers for all channels
		for(int i = 0; i < nested_edl->session->audio_channels; i++)
		{
			if(nested_allocation < speed_fragment_len)
			{
				delete nested_output[i];
				nested_output[i] = 0;
			}

			if(!nested_output[i])
			{
				nested_output[i] = new Samples(speed_fragment_len);
			}
		}
if(debug) printf("AModule::import_samples %d\n", __LINE__);

		if(nested_allocation < speed_fragment_len)
			nested_allocation = speed_fragment_len;

// Update direction command
		nested_renderengine->command->command = command;

// Render the segment
		if(!nested_renderengine->arender)
		{
			bzero(speed_buffer->get_data(), speed_fragment_len * sizeof(double));
		}
		else
		if(sample_rate != nested_edl->session->sample_rate)
		{
// Read through sample rate converter.
			if(!resample)
			{
				resample = new AModuleResample(this);
			}

if(debug) printf("AModule::import_samples %d %d %d\n", 
__LINE__,
(int)sample_rate,
(int)nested_edl->session->sample_rate);
			result = resample->resample(speed_buffer,
				speed_fragment_len,
				nested_edl->session->sample_rate,
				sample_rate,
				start_source,
				direction);
// Resample reverses to keep it running forward.
if(debug) printf("AModule::import_samples %d\n", __LINE__);
		}
		else
		{
// Render without resampling
if(debug) printf("AModule::import_samples %d\n", __LINE__);
			result = nested_renderengine->arender->process_buffer(
				nested_output, 
				speed_fragment_len,
				start_source);
if(debug) printf("AModule::import_samples %d\n", __LINE__);
			memcpy(speed_buffer->get_data(),
				nested_output[edit->channel]->get_data(),
				speed_fragment_len * sizeof(double));
if(debug) printf("AModule::import_samples %d\n", __LINE__);

// Reverse fragment so ::render can apply transitions going forward.
			if(direction == PLAY_REVERSE)
			{
				Resample::reverse_buffer(speed_buffer->get_data(), speed_fragment_len);
			}
		}

if(debug) printf("AModule::import_samples %d\n", __LINE__);
	}
	else
// Source is an asset
	if(edit->asset)
	{
		nested_edl = 0;
if(debug) printf("AModule::import_samples %d\n", __LINE__);
		asset = edit->asset;

if(debug) printf("AModule::import_samples %d\n", __LINE__);
		get_cache()->age();

if(debug) printf("AModule::import_samples %d\n", __LINE__);
		if(nested_renderengine)
		{
			delete nested_renderengine;
			nested_renderengine = 0;
		}

if(debug) printf("AModule::import_samples %d\n", __LINE__);

		if(!(file = get_cache()->check_out(
			asset,
			get_edl())))
		{
// couldn't open source file / skip the edit
			printf(_("AModule::import_samples Couldn't open %s.\n"), asset->path);
			result = 1;
		}
		else
		{
			result = 0;


			if(sample_rate != asset->sample_rate)
			{
// Read through sample rate converter.
				if(!resample)
				{
					resample = new AModuleResample(this);
				}

if(debug) printf("AModule::import_samples %d %d %d\n", 
__LINE__,
sample_rate,
asset->sample_rate);
				result = resample->resample(speed_buffer,
					speed_fragment_len,
					asset->sample_rate,
					sample_rate,
					start_source,
					direction);
// Resample reverses to keep it running forward.
			}
			else
			{

if(debug)
printf("AModule::import_samples %d channel=%d start_source=%ld len=%d\n", __LINE__, edit->channel, start_source, (int)speed_fragment_len);
				file->set_audio_position(start_source);
				file->set_channel(edit->channel);
				result = file->read_samples(speed_buffer, speed_fragment_len);
// Reverse fragment so ::render can apply transitions going forward.
if(debug) printf("AModule::import_samples %d speed_buffer=%p data=%p speed_fragment_len=%d\n", 
__LINE__, 
(void*)speed_buffer,
(void*)speed_buffer->get_data(), 
(int)speed_fragment_len);
				if(direction == PLAY_REVERSE)
				{
					Resample::reverse_buffer(speed_buffer->get_data(), speed_fragment_len);
				}
if(debug) printf("AModule::import_samples %d\n", __LINE__);
			}

if(debug) printf("AModule::import_samples %d\n", __LINE__);
			get_cache()->check_in(asset);
if(debug) printf("AModule::import_samples %d\n", __LINE__);
			file = 0;





		}
	}
	else
	{
		nested_edl = 0;
		asset = 0;
if(debug) printf("AModule::import_samples %d %p %d\n", __LINE__, speed_buffer->get_data(), (int)speed_fragment_len);
		if(speed_fragment_len > 0) bzero(speed_buffer->get_data(), speed_fragment_len * sizeof(double));
if(debug) printf("AModule::import_samples %d\n", __LINE__);
	}
if(debug) printf("AModule::import_samples %d\n", __LINE__);









// Stretch it to fit the speed curve
// Need overlapping buffers to get the interpolation to work, but this
// screws up sequential effects.
	if(have_speed)
	{
		FloatAuto *previous = 0;
		FloatAuto *next = 0;
		FloatAutos *speed_autos = (FloatAutos*)track->automation->autos[AUTOMATION_SPEED];
		double *buffer_samples = buffer->get_data();
		double *speed_samples = speed_buffer->get_data();

//printf("AModule::import_samples %d %lld\n", __LINE__, speed_fragment_len);

		if(speed_fragment_len == 0)
		{
			bzero(buffer_samples, fragment_len * sizeof(double));
			bzero(prev_tail, SPEED_OVERLAP * sizeof(double));
			bzero(prev_head, SPEED_OVERLAP * sizeof(double));
		}
		else
		{
// buffer is now reversed
			if(direction == PLAY_REVERSE)
			{
				int out_offset = 0;
				speed_position = speed_position2;
	//printf("AModule::import_samples %d %lld %lld\n", __LINE__, start_project, speed_fragment_len);
				for(int64_t i = start_project + fragment_len;
					i != start_project;
					i--)
				{
	// funky sample reordering, because the source is a reversed buffer
					int in_offset = (int64_t)(speed_fragment_len - 1 - speed_position);
					CLAMP(in_offset, 0, speed_fragment_len - 1);
					buffer_samples[out_offset++] = speed_samples[in_offset];
					double speed = speed_autos->get_value(i, 
						PLAY_REVERSE,
						previous,
						next);
					speed_position -= speed;
				}
	//printf("AModule::import_samples %d %f\n", __LINE__, speed_position);
 			}
			else
			{
				int out_offset = 0;
// position in buffer to read
				speed_position = speed_position1 - start_source;

//printf("AModule::import_samples %d %f\n", __LINE__, speed_position);
				for(int64_t i = start_project; i < start_project + fragment_len; i++)
				{
					double speed = speed_autos->get_value(i, 
						PLAY_FORWARD,
						previous,
						next);
					double next_speed_position = speed_position + speed;

					int in_offset = (int)(speed_position);
					if(fabs(speed) >= 1.0)
					{
						int total = abs(speed);
						double accum = 0;
						for(int j = 0; j < total; j++)
						{
							int in_offset2 = in_offset + (speed > 0 ? j : -j);

							CLAMP(in_offset2, 0, speed_fragment_len - 1);
							accum += speed_samples[in_offset2];
						}


						buffer_samples[out_offset++] = accum / total;
					}
					else
					{


// if(in_offset < 0 || in_offset >= speed_fragment_len)
// printf("AModule::import_samples %d %d %d\n", 
// __LINE__, 
// in_offset, 
// speed_fragment_len);

						int in_offset1 = in_offset;
						int in_offset2 = in_offset;

						if(speed < 0)
						{
							in_offset1 += SPEED_OVERLAP;
							in_offset2 = in_offset1 - 1;
						}
						else
						{
							in_offset1 -= SPEED_OVERLAP;
							in_offset2 = in_offset1 + 1;
						}

						CLAMP(in_offset1, -SPEED_OVERLAP, speed_fragment_len - 1 + SPEED_OVERLAP);
						CLAMP(in_offset2, -SPEED_OVERLAP, speed_fragment_len - 1 + SPEED_OVERLAP);
						
						double value1 = 0;
						if(in_offset1 >= speed_fragment_len)
						{
							value1 = prev_head[in_offset1 - speed_fragment_len];
						}
						else
						if(in_offset1 >= 0)
						{ 
							value1 = speed_samples[in_offset1];
						}
						else
						{
//printf("AModule::import_samples %d %d\n", __LINE__, in_offset1);
							value1 = prev_tail[SPEED_OVERLAP + in_offset1];
						}
#if 0
						double value2 = 0;
						if(in_offset2 >= speed_fragment_len)
						{
							value2 = prev_head[in_offset2 - speed_fragment_len];
						}
						else
						if(in_offset2 >= 0)
						{
							value2 = speed_samples()[in_offset2];
						}
						else
						{
							value2 = prev_tail[SPEED_OVERLAP + in_offset2];
						}

						double fraction = speed_position - floor(speed_position);
						buffer_samples[out_offset++] = 
							value1 * (1.0 - fraction) +
							value2 * fraction;
#endif
						buffer_samples[out_offset++] = value1;


					}

					speed_position = next_speed_position;
				}
			}
			
			for(int i = 0; i < SPEED_OVERLAP; i++)
			{
				int offset = speed_fragment_len - 
					SPEED_OVERLAP +
					i;
				CLAMP(offset, 0, speed_fragment_len - 1);
//printf("AModule::import_samples %d %d\n", __LINE__, offset, );
				prev_tail[i] = speed_samples[offset];
				offset = i;
				CLAMP(offset, 0, speed_fragment_len - 1);
				prev_head[i] = speed_samples[offset];
			}
		}
	}
	
	
	
 

	return result;
}
void TimeBar::update_points()
{
	EDL *edl = get_edl();
	int64_t pixel;

	if(edl) pixel = position_to_pixel(edl->local_session->get_inpoint());


	if(in_point)
	{
		if(edl && 
			edl->local_session->inpoint_valid() && 
			pixel >= 0 && 
			pixel < get_w())
		{
			if(!EQUIV(edl->local_session->get_inpoint(), in_point->position) ||
				in_point->pixel != pixel)
			{
				in_point->pixel = pixel;
				in_point->position = edl->local_session->get_inpoint();
				in_point->reposition(0);
			}
			else
			{
				in_point->draw_face(1, 0);
			}
		}
		else
		{
			delete in_point;
			in_point = 0;
		}
	}
	else
	if(edl && edl->local_session->inpoint_valid() && 
		pixel >= 0 && pixel < get_w())
	{
		add_subwindow(in_point = new InPointGUI(mwindow, 
			this, 
			pixel, 
			edl->local_session->get_inpoint()));
		in_point->set_cursor(ARROW_CURSOR, 0, 0);
	}

	if(edl) pixel = position_to_pixel(edl->local_session->get_outpoint());

	if(out_point)
	{
		if(edl &&
			edl->local_session->outpoint_valid() && 
			pixel >= 0 && 
			pixel < get_w())
		{
			if(!EQUIV(edl->local_session->get_outpoint(), out_point->position) ||
				out_point->pixel != pixel) 
			{
				out_point->pixel = pixel;
				out_point->position = edl->local_session->get_outpoint();
				out_point->reposition(0);
			}
			else
			{
				out_point->draw_face(1, 0);
			}
		}
		else
		{
			delete out_point;
			out_point = 0;
		}
	}
	else
	if(edl && 
		edl->local_session->outpoint_valid() && 
		pixel >= 0 && pixel < get_w())
	{
		add_subwindow(out_point = new OutPointGUI(mwindow, 
			this, 
			pixel, 
			edl->local_session->get_outpoint()));
		out_point->set_cursor(ARROW_CURSOR, 0, 0);
	}
	
//	flush();
}
void TimeBar::update_labels()
{
	int output = 0;
	EDL *edl = get_edl();

	if(edl)
	{
		for(Label *current = edl->labels->first;
			current;
			current = NEXT)
		{
			int64_t pixel = position_to_pixel(current->position);

			if(pixel >= 0 && pixel < get_w())
			{
// Create new label
				if(output >= labels.total)
				{
					LabelGUI *new_label;
					add_subwindow(new_label = 
						new LabelGUI(mwindow, 
							this, 
							pixel, 
							LabelGUI::get_y(mwindow, this), 
							current->position));
					new_label->set_cursor(ARROW_CURSOR, 0, 0);
					labels.append(new_label);
				}
				else
// Reposition old label
				{
					LabelGUI *gui = labels.values[output];
					if(gui->pixel != pixel)
					{
						gui->pixel = pixel;
						gui->reposition(0);
					}
					else
					{
						gui->draw_face(1,0);
					}

					labels.values[output]->position = current->position;
				}

				if(edl->local_session->get_selectionstart(1) <= current->position &&
					edl->local_session->get_selectionend(1) >= current->position)
					labels.values[output]->update(1);
				else
				if(labels.values[output]->get_value())
					labels.values[output]->update(0);

				output++;
			}
		}
	}

// Delete excess labels
	while(labels.total > output)
	{
		labels.remove_object();
	}
	
// Get the labels to show	
	show_window(0);
}