6 #include "edlsession.h"
8 #include "filesystem.h"
11 #include "indexfile.h"
12 #include "indexthread.h"
14 #include "localsession.h"
15 #include "mainprogress.h"
17 #include "mwindowgui.h"
18 #include "preferences.h"
19 #include "resourcepixmap.h"
22 #include "trackcanvas.h"
26 // Use native sampling rates for files so the same index can be used in
29 IndexFile::IndexFile(MWindow *mwindow)
31 //printf("IndexFile::IndexFile 1\n");
32 this->mwindow = mwindow;
33 //printf("IndexFile::IndexFile 2\n");
36 redraw_timer = new Timer;
39 IndexFile::IndexFile(MWindow *mwindow, Asset *asset)
41 //printf("IndexFile::IndexFile 2\n");
43 this->mwindow = mwindow;
46 redraw_timer = new Timer;
49 IndexFile::~IndexFile()
51 //printf("IndexFile::~IndexFile 1\n");
55 int IndexFile::open_index(Asset *asset)
57 // use buffer if being built
61 if(asset->index_status == INDEX_BUILDING)
67 if(!(result = open_file()))
69 // opened existing file
77 asset->index_status = INDEX_READY;
88 int IndexFile::open_index(MWindow *mwindow, Asset *asset)
90 return open_index(asset);
93 void IndexFile::delete_index(Preferences *preferences, Asset *asset)
95 char index_filename[BCTEXTLEN];
96 char source_filename[BCTEXTLEN];
97 get_index_filename(source_filename,
98 preferences->index_directory,
101 //printf("IndexFile::delete_index %s %s\n", source_filename, index_filename);
102 remove(index_filename);
105 int IndexFile::open_file()
108 get_index_filename(source_filename,
109 mwindow->preferences->index_directory,
113 if(file = fopen(index_filename, "rb"))
115 // Index file already exists.
116 // Get its last size without changing the status.
119 read_info(&test_asset);
122 if(fs.get_date(index_filename) < fs.get_date(test_asset.path))
124 // index older than source
129 if(fs.get_size(asset->path) != test_asset.index_bytes)
131 // source file is a different size than index source file
137 fseek(file, 0, SEEK_END);
138 file_length = ftell(file);
139 fseek(file, 0, SEEK_SET);
152 int IndexFile::open_source(File *source)
154 //printf("IndexFile::open_source %p %s\n", asset, asset->path);
155 if(source->open_file(mwindow->preferences,
162 //printf("IndexFile::open_source() Couldn't open %s.\n", asset->path);
168 asset->index_bytes = fs.get_size(asset->path);
173 int64_t IndexFile::get_required_scale(File *source)
176 // total length of input file
177 int64_t length_source = source->get_audio_length(0);
179 // get scale of index file
180 // if(length_source > mwindow->preferences->index_size)
182 // Total peaks which may be stored in buffer
183 int64_t peak_count = mwindow->preferences->index_size / (2 * sizeof(float) * asset->channels);
185 length_source / result > peak_count;
191 // too small to build an index for
195 // Takes too long to draw from source on a CDROM. Make indexes for
201 int IndexFile::get_index_filename(char *source_filename,
202 char *index_directory,
203 char *index_filename,
204 char *input_filename)
206 // Replace slashes and dots
208 int len = strlen(input_filename);
209 for(i = 0, j = 0; i < len; i++)
211 if(input_filename[i] != '/' &&
212 input_filename[i] != '.')
213 source_filename[j++] = input_filename[i];
217 source_filename[j++] = '_';
220 source_filename[j] = 0;
222 fs.join_names(index_filename, index_directory, source_filename);
223 strcat(index_filename, ".idx");
227 int IndexFile::interrupt_index()
233 // Read data into buffers
235 int IndexFile::create_index(Asset *asset, MainProgressBar *progress)
238 this->mwindow = mwindow;
242 // open the source file
244 if(open_source(&source)) return 1;
247 get_index_filename(source_filename,
248 mwindow->preferences->index_directory,
253 // Test for index in stream table of contents
254 if(!source.get_index(index_filename))
256 printf("IndexFile::create_index 1\n");
260 // Build index from scratch
266 asset->index_zoom = get_required_scale(&source);
268 // Indexes are now built for everything since it takes too long to draw
269 // from CDROM source.
272 // total length of input file
273 int64_t length_source = source.get_audio_length(0);
275 // get amount to read at a time in floats
276 int64_t buffersize = 65536;
277 char string[BCTEXTLEN];
278 sprintf(string, _("Creating %s."), index_filename);
280 progress->update_title(string);
281 progress->update_length(length_source);
282 redraw_timer->update();
284 // thread out index thread
285 IndexThread *index_thread = new IndexThread(mwindow,
291 index_thread->start_build();
293 // current sample in source file
294 int64_t position = 0;
295 int64_t fragment_size = buffersize;
296 int current_buffer = 0;
299 // pass through file once
300 while(position < length_source && !result)
302 if(length_source - position < fragment_size && fragment_size == buffersize) fragment_size = length_source - position;
304 index_thread->input_lock[current_buffer]->lock("IndexFile::create_index 1");
305 index_thread->input_len[current_buffer] = fragment_size;
307 int cancelled = progress->update(position);
309 index_thread->interrupt_flag ||
315 for(int channel = 0; !result && channel < asset->channels; channel++)
317 source.set_audio_position(position, 0);
318 source.set_channel(channel);
320 // Read from source file
321 if(source.read_samples(index_thread->buffer_in[current_buffer][channel],
326 // Release buffer to thread
329 index_thread->output_lock[current_buffer]->unlock();
331 if(current_buffer >= TOTAL_BUFFERS) current_buffer = 0;
332 position += fragment_size;
336 index_thread->input_lock[current_buffer]->unlock();
340 // end thread cleanly
341 index_thread->input_lock[current_buffer]->lock("IndexFile::create_index 2");
342 index_thread->last_buffer[current_buffer] = 1;
343 index_thread->output_lock[current_buffer]->unlock();
345 index_thread->stop_build();
355 mwindow->edl->set_index_file(asset);
356 //printf("IndexFile::create_index 11\n");
361 int IndexFile::create_index(MWindow *mwindow,
363 MainProgressBar *progress)
365 return create_index(asset, progress);
370 int IndexFile::redraw_edits(int force)
372 int64_t difference = redraw_timer->get_scaled_difference(1000);
374 if(difference > 250 || force)
376 redraw_timer->update();
377 // Can't lock window here since the window is only redrawn when the pixel
379 mwindow->gui->lock_window("IndexFile::redraw_edits");
380 mwindow->edl->set_index_file(asset);
381 mwindow->gui->canvas->draw_indexes(asset);
382 asset->old_index_end = asset->index_end;
383 mwindow->gui->unlock_window();
391 int IndexFile::draw_index(ResourcePixmap *pixmap, Edit *edit, int x, int w)
393 // check against index_end when being built
394 if(asset->index_zoom == 0)
396 printf(_("IndexFile::draw_index: index has 0 zoom\n"));
400 // test channel number
401 if(edit->channel > asset->channels) return 1;
403 // calculate a virtual x where the edit_x should be in floating point
404 double virtual_edit_x = 1.0 * edit->track->from_units(edit->startproject) *
405 mwindow->edl->session->sample_rate /
406 mwindow->edl->local_session->zoom_sample -
407 mwindow->edl->local_session->view_start;
409 // samples in segment to draw relative to asset
410 double asset_over_session = (double)edit->asset->sample_rate /
411 mwindow->edl->session->sample_rate;
412 // int64_t startsource = (int64_t)(((pixmap->pixmap_x - pixmap->edit_x + x) *
413 int64_t startsource = (int64_t)(((pixmap->pixmap_x - virtual_edit_x + x) *
414 mwindow->edl->local_session->zoom_sample +
417 // just in case we get a numerical error
418 if (startsource < 0) startsource = 0;
419 int64_t length = (int64_t)(w *
420 mwindow->edl->local_session->zoom_sample *
423 if(asset->index_status == INDEX_BUILDING)
425 if(startsource + length > asset->index_end)
426 length = asset->index_end - startsource;
429 // length of index to read in samples * 2
430 int64_t lengthindex = length / asset->index_zoom * 2;
431 // start of data in samples
432 int64_t startindex = startsource / asset->index_zoom * 2;
433 // Clamp length of index to read by available data
434 if(startindex + lengthindex > asset->get_index_size(edit->channel))
435 lengthindex = asset->get_index_size(edit->channel) - startindex;
436 if(lengthindex <= 0) return 0;
441 // Actual length read from file in bytes
443 // Start and length of fragment to read from file in bytes.
444 int64_t startfile, lengthfile;
446 int buffer_shared = 0;
448 int center_pixel = mwindow->edl->local_session->zoom_track / 2;
449 if(mwindow->edl->session->show_titles) center_pixel += mwindow->theme->title_bg_data->get_h();
450 int miny = center_pixel - mwindow->edl->local_session->zoom_track / 2;
451 int maxy = center_pixel + mwindow->edl->local_session->zoom_track / 2;
453 // get zoom_sample relative to index zoomx
454 double index_frames_per_pixel = mwindow->edl->local_session->zoom_sample /
458 // get channel offset
459 startindex += asset->get_index_offset(edit->channel);
462 if(asset->index_status == INDEX_BUILDING)
464 // index is in RAM, being built
465 buffer = &(asset->index_buffer[startindex]);
470 // index is stored in a file
471 buffer = new float[lengthindex + 1];
473 startfile = asset->index_start + startindex * sizeof(float);
474 lengthfile = lengthindex * sizeof(float);
477 if(startfile < file_length)
479 fseek(file, startfile, SEEK_SET);
481 length_read = lengthfile;
482 if(startfile + length_read > file_length)
483 length_read = file_length - startfile;
485 fread(buffer, length_read + sizeof(float), 1, file);
488 if(length_read < lengthfile)
489 for(i = length_read / sizeof(float);
490 i < lengthfile / sizeof(float);
497 pixmap->canvas->set_color(mwindow->theme->audio_color);
500 double current_frame = 0;
501 float highsample = buffer[0];
502 float lowsample = buffer[1];
503 int prev_y1 = center_pixel;
504 int prev_y2 = center_pixel;
507 for(int bufferposition = 0;
508 bufferposition < lengthindex;
511 if(current_frame >= index_frames_per_pixel)
513 int next_y1 = (int)(center_pixel - highsample * mwindow->edl->local_session->zoom_y / 2);
514 int next_y2 = (int)(center_pixel - lowsample * mwindow->edl->local_session->zoom_y / 2);
518 // A different algorithm has to be used if it's 1 sample per pixel and the
519 // index is used. Now the min and max values are equal so we join the max samples.
520 if(mwindow->edl->local_session->zoom_sample == 1)
522 pixmap->canvas->draw_line(x1 + x - 1, prev_y1, x1 + x, y1, pixmap);
526 // Extend line height if it doesn't connect to previous line
529 if(y1 > prev_y2) y1 = prev_y2 + 1;
530 if(y2 < prev_y1) y2 = prev_y1 - 1;
536 pixmap->canvas->draw_line(x1 + x, y1, x1 + x, y2, pixmap);
538 current_frame -= index_frames_per_pixel;
542 highsample = buffer[bufferposition];
543 lowsample = buffer[bufferposition + 1];
547 highsample = MAX(highsample, buffer[bufferposition]);
548 lowsample = MIN(lowsample, buffer[bufferposition + 1]);
554 y1 = (int)(center_pixel - highsample * mwindow->edl->local_session->zoom_y / 2);
555 y2 = (int)(center_pixel - lowsample * mwindow->edl->local_session->zoom_y / 2);
556 pixmap->canvas->draw_line(x1 + x, y1, x1 + x, y2, pixmap);
562 if(!buffer_shared) delete [] buffer;
566 int IndexFile::close_index()
575 int IndexFile::remove_index()
577 if(asset->index_status == INDEX_READY || asset->index_status == INDEX_NOTTESTED)
580 remove(index_filename);
584 int IndexFile::read_info(Asset *test_asset)
586 if(!test_asset) test_asset = asset;
587 if(test_asset->index_status == INDEX_NOTTESTED)
589 // read start of index data
590 fread((char*)&(test_asset->index_start), sizeof(int64_t), 1, file);
592 // read test_asset info from index
595 data = new char[test_asset->index_start];
596 fread(data, test_asset->index_start - sizeof(int64_t), 1, file);
597 data[test_asset->index_start - sizeof(int64_t)] = 0;
599 xml.read_from_string(data);
600 test_asset->read(&xml);
603 if(test_asset->format == FILE_UNKNOWN)