7 #include "edlsession.h"
9 #include "filesystem.h"
12 #include "indexfile.h"
13 #include "indexthread.h"
15 #include "localsession.h"
16 #include "mainprogress.h"
18 #include "mwindowgui.h"
19 #include "preferences.h"
20 #include "resourcepixmap.h"
23 #include "trackcanvas.h"
28 // Use native sampling rates for files so the same index can be used in
31 IndexFile::IndexFile(MWindow *mwindow)
33 //printf("IndexFile::IndexFile 1\n");
34 this->mwindow = mwindow;
35 //printf("IndexFile::IndexFile 2\n");
38 redraw_timer = new Timer;
41 IndexFile::IndexFile(MWindow *mwindow, Asset *asset)
43 //printf("IndexFile::IndexFile 2\n");
45 this->mwindow = mwindow;
48 redraw_timer = new Timer;
51 IndexFile::~IndexFile()
53 //printf("IndexFile::~IndexFile 1\n");
57 int IndexFile::open_index(Asset *asset)
59 // use buffer if being built
63 if(asset->index_status == INDEX_BUILDING)
69 if(!(result = open_file()))
71 // opened existing file
79 asset->index_status = INDEX_READY;
90 int IndexFile::open_index(MWindow *mwindow, Asset *asset)
92 return open_index(asset);
95 void IndexFile::delete_index(Preferences *preferences, Asset *asset)
97 char index_filename[BCTEXTLEN];
98 char source_filename[BCTEXTLEN];
99 get_index_filename(source_filename,
100 preferences->index_directory,
103 //printf("IndexFile::delete_index %s %s\n", source_filename, index_filename);
104 remove(index_filename);
107 int IndexFile::open_file()
110 get_index_filename(source_filename,
111 mwindow->preferences->index_directory,
115 if(file = fopen(index_filename, "rb"))
117 // Index file already exists.
118 // Get its last size without changing the status.
119 Asset *test_asset = new Asset;
120 *test_asset = *asset;
121 read_info(test_asset);
124 if(fs.get_date(index_filename) < fs.get_date(test_asset->path))
126 // index older than source
132 if(fs.get_size(asset->path) != test_asset->index_bytes)
134 // source file is a different size than index source file
141 fseek(file, 0, SEEK_END);
142 file_length = ftell(file);
143 fseek(file, 0, SEEK_SET);
146 Garbage::delete_object(test_asset);
157 int IndexFile::open_source(File *source)
159 //printf("IndexFile::open_source %p %s\n", asset, asset->path);
160 if(source->open_file(mwindow->preferences,
167 //printf("IndexFile::open_source() Couldn't open %s.\n", asset->path);
173 asset->index_bytes = fs.get_size(asset->path);
178 int64_t IndexFile::get_required_scale(File *source)
181 // total length of input file
182 int64_t length_source = source->get_audio_length(0);
184 // get scale of index file
185 // if(length_source > mwindow->preferences->index_size)
187 // Total peaks which may be stored in buffer
188 int64_t peak_count = mwindow->preferences->index_size / (2 * sizeof(float) * asset->channels);
190 length_source / result > peak_count;
196 // too small to build an index for
200 // Takes too long to draw from source on a CDROM. Make indexes for
206 int IndexFile::get_index_filename(char *source_filename,
207 char *index_directory,
208 char *index_filename,
209 char *input_filename)
211 // Replace slashes and dots
213 int len = strlen(input_filename);
214 for(i = 0, j = 0; i < len; i++)
216 if(input_filename[i] != '/' &&
217 input_filename[i] != '.')
218 source_filename[j++] = input_filename[i];
222 source_filename[j++] = '_';
225 source_filename[j] = 0;
227 fs.join_names(index_filename, index_directory, source_filename);
228 strcat(index_filename, ".idx");
232 int IndexFile::interrupt_index()
238 // Read data into buffers
240 int IndexFile::create_index(Asset *asset, MainProgressBar *progress)
243 this->mwindow = mwindow;
247 // open the source file
249 if(open_source(&source)) return 1;
252 get_index_filename(source_filename,
253 mwindow->preferences->index_directory,
258 // Test for index in stream table of contents
259 if(!source.get_index(index_filename))
261 printf("IndexFile::create_index 1\n");
265 // Build index from scratch
271 asset->index_zoom = get_required_scale(&source);
273 // Indexes are now built for everything since it takes too long to draw
274 // from CDROM source.
277 // total length of input file
278 int64_t length_source = source.get_audio_length(0);
280 // get amount to read at a time in floats
281 int64_t buffersize = 65536;
282 char string[BCTEXTLEN];
283 sprintf(string, _("Creating %s."), index_filename);
285 progress->update_title(string);
286 progress->update_length(length_source);
287 redraw_timer->update();
289 // thread out index thread
290 IndexThread *index_thread = new IndexThread(mwindow,
296 index_thread->start_build();
298 // current sample in source file
299 int64_t position = 0;
300 int64_t fragment_size = buffersize;
301 int current_buffer = 0;
304 // pass through file once
305 while(position < length_source && !result)
307 if(length_source - position < fragment_size && fragment_size == buffersize) fragment_size = length_source - position;
309 index_thread->input_lock[current_buffer]->lock("IndexFile::create_index 1");
310 index_thread->input_len[current_buffer] = fragment_size;
312 int cancelled = progress->update(position);
314 index_thread->interrupt_flag ||
320 for(int channel = 0; !result && channel < asset->channels; channel++)
322 source.set_audio_position(position, 0);
323 source.set_channel(channel);
325 // Read from source file
326 if(source.read_samples(index_thread->buffer_in[current_buffer][channel],
331 // Release buffer to thread
334 index_thread->output_lock[current_buffer]->unlock();
336 if(current_buffer >= TOTAL_BUFFERS) current_buffer = 0;
337 position += fragment_size;
341 index_thread->input_lock[current_buffer]->unlock();
345 // end thread cleanly
346 index_thread->input_lock[current_buffer]->lock("IndexFile::create_index 2");
347 index_thread->last_buffer[current_buffer] = 1;
348 index_thread->output_lock[current_buffer]->unlock();
349 index_thread->stop_build();
363 mwindow->edl->set_index_file(asset);
368 int IndexFile::create_index(MWindow *mwindow,
370 MainProgressBar *progress)
372 return create_index(asset, progress);
377 int IndexFile::redraw_edits(int force)
379 int64_t difference = redraw_timer->get_scaled_difference(1000);
381 if(difference > 250 || force)
383 redraw_timer->update();
384 // Can't lock window here since the window is only redrawn when the pixel
386 mwindow->gui->lock_window("IndexFile::redraw_edits");
387 mwindow->edl->set_index_file(asset);
388 mwindow->gui->canvas->draw_indexes(asset);
389 asset->old_index_end = asset->index_end;
390 mwindow->gui->unlock_window();
398 int IndexFile::draw_index(ResourcePixmap *pixmap, Edit *edit, int x, int w)
400 // check against index_end when being built
401 if(asset->index_zoom == 0)
403 printf(_("IndexFile::draw_index: index has 0 zoom\n"));
407 // test channel number
408 if(edit->channel > asset->channels) return 1;
410 // calculate a virtual x where the edit_x should be in floating point
411 double virtual_edit_x = 1.0 * edit->track->from_units(edit->startproject) *
412 mwindow->edl->session->sample_rate /
413 mwindow->edl->local_session->zoom_sample -
414 mwindow->edl->local_session->view_start;
416 // samples in segment to draw relative to asset
417 double asset_over_session = (double)edit->asset->sample_rate /
418 mwindow->edl->session->sample_rate;
419 // int64_t startsource = (int64_t)(((pixmap->pixmap_x - pixmap->edit_x + x) *
420 int64_t startsource = (int64_t)(((pixmap->pixmap_x - virtual_edit_x + x) *
421 mwindow->edl->local_session->zoom_sample +
424 // just in case we get a numerical error
425 if (startsource < 0) startsource = 0;
426 int64_t length = (int64_t)(w *
427 mwindow->edl->local_session->zoom_sample *
430 if(asset->index_status == INDEX_BUILDING)
432 if(startsource + length > asset->index_end)
433 length = asset->index_end - startsource;
436 // length of index to read in samples * 2
437 int64_t lengthindex = length / asset->index_zoom * 2;
438 // start of data in samples
439 int64_t startindex = startsource / asset->index_zoom * 2;
440 // Clamp length of index to read by available data
441 if(startindex + lengthindex > asset->get_index_size(edit->channel))
442 lengthindex = asset->get_index_size(edit->channel) - startindex;
443 if(lengthindex <= 0) return 0;
448 // Actual length read from file in bytes
450 // Start and length of fragment to read from file in bytes.
451 int64_t startfile, lengthfile;
453 int buffer_shared = 0;
455 int center_pixel = mwindow->edl->local_session->zoom_track / 2;
456 if(mwindow->edl->session->show_titles) center_pixel += mwindow->theme->get_image("title_bg_data")->get_h();
457 int miny = center_pixel - mwindow->edl->local_session->zoom_track / 2;
458 int maxy = center_pixel + mwindow->edl->local_session->zoom_track / 2;
460 // get zoom_sample relative to index zoomx
461 double index_frames_per_pixel = mwindow->edl->local_session->zoom_sample /
465 // get channel offset
466 startindex += asset->get_index_offset(edit->channel);
469 if(asset->index_status == INDEX_BUILDING)
471 // index is in RAM, being built
472 buffer = &(asset->index_buffer[startindex]);
477 // index is stored in a file
478 buffer = new float[lengthindex + 1];
480 startfile = asset->index_start + startindex * sizeof(float);
481 lengthfile = lengthindex * sizeof(float);
484 if(startfile < file_length)
486 fseek(file, startfile, SEEK_SET);
488 length_read = lengthfile;
489 if(startfile + length_read > file_length)
490 length_read = file_length - startfile;
492 fread(buffer, length_read + sizeof(float), 1, file);
495 if(length_read < lengthfile)
496 for(i = length_read / sizeof(float);
497 i < lengthfile / sizeof(float);
504 pixmap->canvas->set_color(mwindow->theme->audio_color);
507 double current_frame = 0;
508 float highsample = buffer[0];
509 float lowsample = buffer[1];
510 int prev_y1 = center_pixel;
511 int prev_y2 = center_pixel;
514 for(int bufferposition = 0;
515 bufferposition < lengthindex;
518 if(current_frame >= index_frames_per_pixel)
520 int next_y1 = (int)(center_pixel - highsample * mwindow->edl->local_session->zoom_y / 2);
521 int next_y2 = (int)(center_pixel - lowsample * mwindow->edl->local_session->zoom_y / 2);
525 // A different algorithm has to be used if it's 1 sample per pixel and the
526 // index is used. Now the min and max values are equal so we join the max samples.
527 if(mwindow->edl->local_session->zoom_sample == 1)
529 pixmap->canvas->draw_line(x1 + x - 1, prev_y1, x1 + x, y1, pixmap);
533 // Extend line height if it doesn't connect to previous line
536 if(y1 > prev_y2) y1 = prev_y2 + 1;
537 if(y2 < prev_y1) y2 = prev_y1 - 1;
543 pixmap->canvas->draw_line(x1 + x, y1, x1 + x, y2, pixmap);
545 current_frame -= index_frames_per_pixel;
549 highsample = buffer[bufferposition];
550 lowsample = buffer[bufferposition + 1];
554 highsample = MAX(highsample, buffer[bufferposition]);
555 lowsample = MIN(lowsample, buffer[bufferposition + 1]);
561 y1 = (int)(center_pixel - highsample * mwindow->edl->local_session->zoom_y / 2);
562 y2 = (int)(center_pixel - lowsample * mwindow->edl->local_session->zoom_y / 2);
563 pixmap->canvas->draw_line(x1 + x, y1, x1 + x, y2, pixmap);
569 if(!buffer_shared) delete [] buffer;
573 int IndexFile::close_index()
584 int IndexFile::remove_index()
586 if(asset->index_status == INDEX_READY || asset->index_status == INDEX_NOTTESTED)
589 remove(index_filename);
593 int IndexFile::read_info(Asset *test_asset)
595 if(!test_asset) test_asset = asset;
596 if(test_asset->index_status == INDEX_NOTTESTED)
598 // read start of index data
599 fread((char*)&(test_asset->index_start), sizeof(int64_t), 1, file);
601 // read test_asset info from index
604 data = new char[test_asset->index_start];
605 fread(data, test_asset->index_start - sizeof(int64_t), 1, file);
606 data[test_asset->index_start - sizeof(int64_t)] = 0;
608 xml.read_from_string(data);
609 test_asset->read(&xml);
612 if(test_asset->format == FILE_UNKNOWN)