5 #include "edlsession.h"
7 #include "filesystem.h"
10 #include "indexfile.h"
11 #include "indexthread.h"
12 #include "localsession.h"
13 #include "mainprogress.h"
15 #include "mwindowgui.h"
16 #include "preferences.h"
17 #include "resourcepixmap.h"
20 #include "trackcanvas.h"
26 #define _(String) gettext(String)
27 #define gettext_noop(String) String
28 #define N_(String) gettext_noop (String)
30 // Use native sampling rates for files so the same index can be used in
33 IndexFile::IndexFile(MWindow *mwindow)
35 //printf("IndexFile::IndexFile 1\n");
36 this->mwindow = mwindow;
37 //printf("IndexFile::IndexFile 2\n");
40 redraw_timer = new Timer;
43 IndexFile::IndexFile(MWindow *mwindow, Asset *asset)
45 //printf("IndexFile::IndexFile 2\n");
47 this->mwindow = mwindow;
50 redraw_timer = new Timer;
53 IndexFile::~IndexFile()
55 //printf("IndexFile::~IndexFile 1\n");
59 int IndexFile::open_index(Asset *asset)
61 // use buffer if being built
65 //printf("IndexFile::open_index 1\n");
66 if(asset->index_status == INDEX_BUILDING)
72 if(!(result = open_file()))
74 // opened existing file
77 //printf("IndexFile::open_index 2\n");
83 //printf("IndexFile::open_index 3\n");
84 asset->index_status = INDEX_READY;
91 //printf("IndexFile::open_index 4 %d\n", result);
96 int IndexFile::open_index(MWindow *mwindow, Asset *asset)
98 return open_index(asset);
101 void IndexFile::delete_index(Preferences *preferences, Asset *asset)
103 char index_filename[BCTEXTLEN];
104 char source_filename[BCTEXTLEN];
105 get_index_filename(source_filename,
106 preferences->index_directory,
109 //printf("IndexFile::delete_index %s %s\n", source_filename, index_filename);
110 remove(index_filename);
113 int IndexFile::open_file()
116 get_index_filename(source_filename,
117 mwindow->preferences->index_directory,
121 //printf("IndexFile::open_file 1 %s\n", index_filename);
122 if(file = fopen(index_filename, "rb"))
124 // Index file already exists.
125 // Get its last size without changing the status.
128 read_info(&test_asset);
131 //printf("IndexFile::open_file 1.5 %s %u %u\n",
133 //fs.get_date(index_filename),
134 //fs.get_date(test_asset.path));
135 if(fs.get_date(index_filename) < fs.get_date(test_asset.path))
137 // index older than source
138 //printf("IndexFile::open_file 2\n", index_filename);
143 if(fs.get_size(asset->path) != test_asset.index_bytes)
145 // source file is a different size than index source file
146 //printf("IndexFile::open_file 3 %s %lld %lld %lld\n",
148 //fs.get_size(asset->path),
149 //test_asset.index_bytes,
150 //asset->index_bytes);
156 //printf("IndexFile::open_file 4 %s %lld %lld %lld\n",
158 //fs.get_size(asset->path),
159 //test_asset.index_bytes,
160 //asset->index_bytes);
161 fseek(file, 0, SEEK_END);
162 file_length = ftell(file);
163 fseek(file, 0, SEEK_SET);
170 //printf("IndexFile::open_file 5\n", index_filename);
177 int IndexFile::open_source(File *source)
179 //printf("IndexFile::open_source %p %s\n", asset, asset->path);
180 if(source->open_file(mwindow->plugindb,
187 //printf("IndexFile::open_source() Couldn't open %s.\n", asset->path);
193 asset->index_bytes = fs.get_size(asset->path);
198 int64_t IndexFile::get_required_scale(File *source)
201 // total length of input file
202 int64_t length_source = source->get_audio_length(0);
204 // get scale of index file
205 // if(length_source > mwindow->preferences->index_size)
207 // Total peaks which may be stored in buffer
208 int64_t peak_count = mwindow->preferences->index_size / (2 * sizeof(float) * asset->channels);
210 length_source / result > peak_count;
216 // too small to build an index for
220 // Takes too long to draw from source on a CDROM. Make indexes for
226 int IndexFile::get_index_filename(char *source_filename,
227 char *index_directory,
228 char *index_filename,
229 char *input_filename)
231 // Replace slashes and dots
233 int len = strlen(input_filename);
234 for(i = 0, j = 0; i < len; i++)
236 if(input_filename[i] != '/' &&
237 input_filename[i] != '.')
238 source_filename[j++] = input_filename[i];
242 source_filename[j++] = '_';
245 source_filename[j] = 0;
247 fs.join_names(index_filename, index_directory, source_filename);
248 strcat(index_filename, ".idx");
252 int IndexFile::interrupt_index()
258 // Read data into buffers
260 int IndexFile::create_index(Asset *asset, MainProgressBar *progress)
263 IndexThread *index_thread;
264 this->mwindow = mwindow;
268 // open the source file
270 if(open_source(&source)) return 1;
272 asset->index_zoom = get_required_scale(&source);
273 //printf("IndexFile::create_index 1 %d %s\n", asset->index_zoom, asset->path);
275 // Indexes are now built for everything since it takes too long to draw
276 // from CDROM source.
278 // too small to build an index for.
279 // if(asset->index_zoom == 0)
281 // source.close_file();
282 // asset->index_status = INDEX_TOOSMALL;
283 // // Update the EDL and timeline
285 // //printf("IndexFile::create_index 2\n");
288 //printf("IndexFile::create_index 2\n");
290 // total length of input file
291 int64_t length_source = source.get_audio_length(0);
293 // get amount to read at a time in floats
294 int64_t buffersize = 65536;
296 get_index_filename(source_filename,
297 mwindow->preferences->index_directory,
300 sprintf(string, _("Creating %s."), index_filename);
302 progress->update_title(string);
303 progress->update_length(length_source);
304 redraw_timer->update();
306 // thread out index thread
307 index_thread = new IndexThread(mwindow,
313 index_thread->start_build();
315 int64_t position = 0; // current sample in source file
316 int64_t fragment_size = buffersize;
317 int current_buffer = 0;
318 //printf("IndexFile::create_index 3\n");
320 // pass through file once
321 while(position < length_source && !result)
323 if(length_source - position < fragment_size && fragment_size == buffersize) fragment_size = length_source - position;
325 //printf("IndexFile::create_index 1 %d\n", position);
326 index_thread->input_lock[current_buffer].lock();
327 index_thread->input_len[current_buffer] = fragment_size;
329 //printf("IndexFile::create_index 2 %d\n", position);
330 int cancelled = progress->update(position);
331 //printf("IndexFile::create_index 3 %d\n", position);
333 index_thread->interrupt_flag ||
336 result = 3; // user cancelled
339 //printf("IndexFile::create_index 4 %d\n", position);
340 for(int channel = 0; !result && channel < asset->channels; channel++)
342 source.set_audio_position(position, 0);
343 source.set_channel(channel);
346 //printf("IndexFile::create_index 5\n");
347 if(source.read_samples(index_thread->buffer_in[current_buffer][channel],
350 //printf("IndexFile::create_index 6\n");
352 //printf("IndexFile::create_index 7 %d\n", position);
356 index_thread->output_lock[current_buffer].unlock();
358 if(current_buffer >= TOTAL_BUFFERS) current_buffer = 0;
359 position += fragment_size;
363 index_thread->input_lock[current_buffer].unlock();
365 //printf("IndexFile::create_index 8 %d\n", position);
367 //printf("IndexFile::create_index 10\n");
369 // end thread cleanly
370 index_thread->input_lock[current_buffer].lock();
371 index_thread->last_buffer[current_buffer] = 1;
372 index_thread->output_lock[current_buffer].unlock();
374 index_thread->stop_build();
382 mwindow->edl->set_index_file(asset);
383 //printf("IndexFile::create_index 11\n");
388 int IndexFile::create_index(MWindow *mwindow,
390 MainProgressBar *progress)
392 return create_index(asset, progress);
397 int IndexFile::redraw_edits(int force)
399 int64_t difference = redraw_timer->get_scaled_difference(1000);
401 //printf("IndexFile::redraw_edits 1 %d %d\n", difference, force);
402 if(difference > 250 || force)
404 redraw_timer->update();
405 // Can't lock window here since the window is only redrawn when the pixel
407 //printf("IndexFile::redraw_edits 2\n");
408 mwindow->gui->lock_window();
409 mwindow->edl->set_index_file(asset);
410 //printf("IndexFile::redraw_edits 3\n");
411 mwindow->gui->canvas->draw_indexes(asset);
412 //printf("IndexFile::redraw_edits 4\n");
413 asset->old_index_end = asset->index_end;
414 mwindow->gui->unlock_window();
415 //printf("IndexFile::redraw_edits 5\n");
423 int IndexFile::draw_index(ResourcePixmap *pixmap, Edit *edit, int x, int w)
425 // check against index_end when being built
426 if(asset->index_zoom == 0)
428 printf(_("IndexFile::draw_index: index has 0 zoom\n"));
432 // samples in segment to draw relative to asset
433 double asset_over_session = (double)edit->asset->sample_rate /
434 mwindow->edl->session->sample_rate;
435 int64_t startsource = (int64_t)(((pixmap->pixmap_x - pixmap->edit_x + x) *
436 mwindow->edl->local_session->zoom_sample +
439 int64_t length = (int64_t)(w *
440 mwindow->edl->local_session->zoom_sample *
443 if(asset->index_status == INDEX_BUILDING)
445 if(startsource + length > asset->index_end)
446 length = asset->index_end - startsource;
449 // length of index to read in samples * 2
450 int64_t lengthindex = length / asset->index_zoom * 2;
451 // start of data in samples
452 int64_t startindex = startsource / asset->index_zoom * 2;
453 int64_t length_read; // Actual length read from file in bytes
454 int64_t startfile, lengthfile; // Start and length of fragment to read from file in bytes.
456 int buffer_shared = 0;
458 int center_pixel = mwindow->edl->local_session->zoom_track / 2;
459 if(mwindow->edl->session->show_titles) center_pixel += mwindow->theme->title_bg_data->get_h();
460 int miny = center_pixel - mwindow->edl->local_session->zoom_track / 2;
461 int maxy = center_pixel + mwindow->edl->local_session->zoom_track / 2;
463 // get zoom_sample relative to index zoomx
464 double index_frames_per_pixel = mwindow->edl->local_session->zoom_sample /
468 // test channel number
469 if(edit->channel > asset->channels) return 1;
471 // get channel offset
472 startindex += asset->get_index_offset(edit->channel);
475 if(asset->index_status == INDEX_BUILDING)
477 // index is in RAM, being built
478 buffer = &(asset->index_buffer[startindex]);
483 // index is stored in a file
484 buffer = new float[lengthindex + 1];
486 startfile = asset->index_start + startindex * sizeof(float);
487 lengthfile = lengthindex * sizeof(float);
490 if(startfile < file_length)
492 fseek(file, startfile, SEEK_SET);
494 length_read = lengthfile;
495 if(startfile + length_read > file_length)
496 length_read = file_length - startfile;
498 fread(buffer, length_read + sizeof(float), 1, file);
501 if(length_read < lengthfile)
502 for(i = length_read / sizeof(float);
503 i < lengthfile / sizeof(float);
510 pixmap->canvas->set_color(mwindow->theme->audio_color);
513 double current_frame = 0;
514 float highsample = buffer[0];
515 float lowsample = buffer[1];
516 int prev_y1 = center_pixel;
517 int prev_y2 = center_pixel;
520 for(int bufferposition = 0;
521 bufferposition < lengthindex;
524 if(current_frame >= index_frames_per_pixel)
526 int next_y1 = (int)(center_pixel - highsample * mwindow->edl->local_session->zoom_y / 2);
527 int next_y2 = (int)(center_pixel - lowsample * mwindow->edl->local_session->zoom_y / 2);
531 // A different algorithm has to be used if it's 1 sample per pixel and the
532 // index is used. Now the min and max values are equal so we join the max samples.
533 if(mwindow->edl->local_session->zoom_sample == 1)
535 pixmap->canvas->draw_line(x1 + x - 1, prev_y1, x1 + x, y1, pixmap);
539 // Extend line height if it doesn't connect to previous line
542 if(y1 > prev_y2) y1 = prev_y2 + 1;
543 if(y2 < prev_y1) y2 = prev_y1 - 1;
549 pixmap->canvas->draw_line(x1 + x, y1, x1 + x, y2, pixmap);
551 current_frame -= index_frames_per_pixel;
555 highsample = buffer[bufferposition];
556 lowsample = buffer[bufferposition + 1];
560 highsample = MAX(highsample, buffer[bufferposition]);
561 lowsample = MIN(lowsample, buffer[bufferposition + 1]);
567 y1 = (int)(center_pixel - highsample * mwindow->edl->local_session->zoom_y / 2);
568 y2 = (int)(center_pixel - lowsample * mwindow->edl->local_session->zoom_y / 2);
569 pixmap->canvas->draw_line(x1 + x, y1, x1 + x, y2, pixmap);
575 if(!buffer_shared) delete [] buffer;
579 int IndexFile::close_index()
588 int IndexFile::remove_index()
590 if(asset->index_status == INDEX_READY || asset->index_status == INDEX_NOTTESTED)
593 remove(index_filename);
597 int IndexFile::read_info(Asset *test_asset)
599 //printf("IndexFile::read_info 1 %p\n", test_asset);
600 if(!test_asset) test_asset = asset;
601 //printf("IndexFile::read_info 2 %d\n", test_asset->index_status);
602 if(test_asset->index_status == INDEX_NOTTESTED)
604 // read start of index data
605 fread((char*)&(test_asset->index_start), sizeof(int64_t), 1, file);
607 // read test_asset info from index
610 data = new char[test_asset->index_start];
611 fread(data, test_asset->index_start - sizeof(int64_t), 1, file);
612 data[test_asset->index_start - sizeof(int64_t)] = 0;
614 xml.read_from_string(data);
615 test_asset->read(mwindow->plugindb, &xml);
618 if(test_asset->format == FILE_UNKNOWN)
620 //printf("IndexFile::read_info 3\n");