00001 #include "asset.h"
00002 #include "clip.h"
00003 #include "condition.h"
00004 #include "edit.h"
00005 #include "edl.h"
00006 #include "edlsession.h"
00007 #include "filexml.h"
00008 #include "filesystem.h"
00009 #include "errorbox.h"
00010 #include "file.h"
00011 #include "indexfile.h"
00012 #include "indexthread.h"
00013 #include "language.h"
00014 #include "localsession.h"
00015 #include "mainprogress.h"
00016 #include "mwindow.h"
00017 #include "mwindowgui.h"
00018 #include "preferences.h"
00019 #include "resourcepixmap.h"
00020 #include "theme.h"
00021 #include "bctimer.h"
00022 #include "trackcanvas.h"
00023 #include "tracks.h"
00024 #include "vframe.h"
00025
00026
00027
00028
00029 IndexFile::IndexFile(MWindow *mwindow)
00030 {
00031
00032 this->mwindow = mwindow;
00033
00034 file = 0;
00035 interrupt_flag = 0;
00036 redraw_timer = new Timer;
00037 }
00038
00039 IndexFile::IndexFile(MWindow *mwindow, Asset *asset)
00040 {
00041
00042 file = 0;
00043 this->mwindow = mwindow;
00044 this->asset = asset;
00045 interrupt_flag = 0;
00046 redraw_timer = new Timer;
00047 }
00048
00049 IndexFile::~IndexFile()
00050 {
00051
00052 delete redraw_timer;
00053 }
00054
00055 int IndexFile::open_index(Asset *asset)
00056 {
00057
00058 this->asset = asset;
00059 int result = 0;
00060
00061 if(asset->index_status == INDEX_BUILDING)
00062 {
00063
00064 result = 0;
00065 }
00066 else
00067 if(!(result = open_file()))
00068 {
00069
00070 if(read_info())
00071 {
00072 result = 1;
00073 close_index();
00074 }
00075 else
00076 {
00077 asset->index_status = INDEX_READY;
00078 }
00079 }
00080 else
00081 {
00082 result = 1;
00083 }
00084
00085 return result;
00086 }
00087
00088 int IndexFile::open_index(MWindow *mwindow, Asset *asset)
00089 {
00090 return open_index(asset);
00091 }
00092
00093 void IndexFile::delete_index(Preferences *preferences, Asset *asset)
00094 {
00095 char index_filename[BCTEXTLEN];
00096 char source_filename[BCTEXTLEN];
00097 get_index_filename(source_filename,
00098 preferences->index_directory,
00099 index_filename,
00100 asset->path);
00101
00102 remove(index_filename);
00103 }
00104
00105 int IndexFile::open_file()
00106 {
00107 int result = 0;
00108 get_index_filename(source_filename,
00109 mwindow->preferences->index_directory,
00110 index_filename,
00111 asset->path);
00112
00113 if(file = fopen(index_filename, "rb"))
00114 {
00115
00116
00117 Asset test_asset;
00118 test_asset = *asset;
00119 read_info(&test_asset);
00120
00121 FileSystem fs;
00122 if(fs.get_date(index_filename) < fs.get_date(test_asset.path))
00123 {
00124
00125 result = 2;
00126 fclose(file);
00127 }
00128 else
00129 if(fs.get_size(asset->path) != test_asset.index_bytes)
00130 {
00131
00132 result = 2;
00133 fclose(file);
00134 }
00135 else
00136 {
00137 fseek(file, 0, SEEK_END);
00138 file_length = ftell(file);
00139 fseek(file, 0, SEEK_SET);
00140 result = 0;
00141 }
00142 }
00143 else
00144 {
00145
00146 result = 1;
00147 }
00148
00149 return result;
00150 }
00151
00152 int IndexFile::open_source(File *source)
00153 {
00154
00155 if(source->open_file(mwindow->preferences,
00156 asset,
00157 1,
00158 0,
00159 0,
00160 0))
00161 {
00162
00163 return 1;
00164 }
00165 else
00166 {
00167 FileSystem fs;
00168 asset->index_bytes = fs.get_size(asset->path);
00169 return 0;
00170 }
00171 }
00172
00173 int64_t IndexFile::get_required_scale(File *source)
00174 {
00175 int64_t result = 1;
00176
00177 int64_t length_source = source->get_audio_length(0);
00178
00179
00180
00181
00182
00183 int64_t peak_count = mwindow->preferences->index_size / (2 * sizeof(float) * asset->channels);
00184 for(result = 1;
00185 length_source / result > peak_count;
00186 result *= 2)
00187 ;
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198 return result;
00199 }
00200
00201 int IndexFile::get_index_filename(char *source_filename,
00202 char *index_directory,
00203 char *index_filename,
00204 char *input_filename)
00205 {
00206
00207 int i, j;
00208 int len = strlen(input_filename);
00209 for(i = 0, j = 0; i < len; i++)
00210 {
00211 if(input_filename[i] != '/' &&
00212 input_filename[i] != '.')
00213 source_filename[j++] = input_filename[i];
00214 else
00215 {
00216 if(i > 0)
00217 source_filename[j++] = '_';
00218 }
00219 }
00220 source_filename[j] = 0;
00221 FileSystem fs;
00222 fs.join_names(index_filename, index_directory, source_filename);
00223 strcat(index_filename, ".idx");
00224 return 0;
00225 }
00226
00227 int IndexFile::interrupt_index()
00228 {
00229 interrupt_flag = 1;
00230 return 0;
00231 }
00232
00233
00234
00235 int IndexFile::create_index(Asset *asset, MainProgressBar *progress)
00236 {
00237 int result = 0;
00238 this->mwindow = mwindow;
00239 this->asset = asset;
00240 interrupt_flag = 0;
00241
00242
00243 File source;
00244 if(open_source(&source)) return 1;
00245
00246
00247 get_index_filename(source_filename,
00248 mwindow->preferences->index_directory,
00249 index_filename,
00250 asset->path);
00251
00252
00253
00254 if(!source.get_index(index_filename))
00255 {
00256 printf("IndexFile::create_index 1\n");
00257 redraw_edits(1);
00258 }
00259 else
00260
00261 {
00262
00263
00264
00265
00266 asset->index_zoom = get_required_scale(&source);
00267
00268
00269
00270
00271
00272
00273 int64_t length_source = source.get_audio_length(0);
00274
00275
00276 int64_t buffersize = 65536;
00277 char string[BCTEXTLEN];
00278 sprintf(string, _("Creating %s."), index_filename);
00279
00280 progress->update_title(string);
00281 progress->update_length(length_source);
00282 redraw_timer->update();
00283
00284
00285 IndexThread *index_thread = new IndexThread(mwindow,
00286 this,
00287 asset,
00288 index_filename,
00289 buffersize,
00290 length_source);
00291 index_thread->start_build();
00292
00293
00294 int64_t position = 0;
00295 int64_t fragment_size = buffersize;
00296 int current_buffer = 0;
00297
00298
00299
00300 while(position < length_source && !result)
00301 {
00302 if(length_source - position < fragment_size && fragment_size == buffersize) fragment_size = length_source - position;
00303
00304 index_thread->input_lock[current_buffer]->lock("IndexFile::create_index 1");
00305 index_thread->input_len[current_buffer] = fragment_size;
00306
00307 int cancelled = progress->update(position);
00308 if(cancelled ||
00309 index_thread->interrupt_flag ||
00310 interrupt_flag)
00311 {
00312 result = 3;
00313 }
00314
00315 for(int channel = 0; !result && channel < asset->channels; channel++)
00316 {
00317 source.set_audio_position(position, 0);
00318 source.set_channel(channel);
00319
00320
00321 if(source.read_samples(index_thread->buffer_in[current_buffer][channel],
00322 fragment_size,
00323 0)) result = 1;
00324 }
00325
00326
00327 if(!result)
00328 {
00329 index_thread->output_lock[current_buffer]->unlock();
00330 current_buffer++;
00331 if(current_buffer >= TOTAL_BUFFERS) current_buffer = 0;
00332 position += fragment_size;
00333 }
00334 else
00335 {
00336 index_thread->input_lock[current_buffer]->unlock();
00337 }
00338 }
00339
00340
00341 index_thread->input_lock[current_buffer]->lock("IndexFile::create_index 2");
00342 index_thread->last_buffer[current_buffer] = 1;
00343 index_thread->output_lock[current_buffer]->unlock();
00344
00345 index_thread->stop_build();
00346 delete index_thread;
00347 }
00348
00349
00350 source.close_file();
00351
00352
00353 open_index(asset);
00354 close_index();
00355 mwindow->edl->set_index_file(asset);
00356
00357 return 0;
00358 }
00359
00360
00361 int IndexFile::create_index(MWindow *mwindow,
00362 Asset *asset,
00363 MainProgressBar *progress)
00364 {
00365 return create_index(asset, progress);
00366 }
00367
00368
00369
00370 int IndexFile::redraw_edits(int force)
00371 {
00372 int64_t difference = redraw_timer->get_scaled_difference(1000);
00373
00374 if(difference > 250 || force)
00375 {
00376 redraw_timer->update();
00377
00378
00379 mwindow->gui->lock_window("IndexFile::redraw_edits");
00380 mwindow->edl->set_index_file(asset);
00381 mwindow->gui->canvas->draw_indexes(asset);
00382 asset->old_index_end = asset->index_end;
00383 mwindow->gui->unlock_window();
00384 }
00385 return 0;
00386 }
00387
00388
00389
00390
00391 int IndexFile::draw_index(ResourcePixmap *pixmap, Edit *edit, int x, int w)
00392 {
00393
00394 if(asset->index_zoom == 0)
00395 {
00396 printf(_("IndexFile::draw_index: index has 0 zoom\n"));
00397 return 0;
00398 }
00399
00400
00401 if(edit->channel > asset->channels) return 1;
00402
00403
00404 double virtual_edit_x = 1.0 * edit->track->from_units(edit->startproject) *
00405 mwindow->edl->session->sample_rate /
00406 mwindow->edl->local_session->zoom_sample -
00407 mwindow->edl->local_session->view_start;
00408
00409
00410 double asset_over_session = (double)edit->asset->sample_rate /
00411 mwindow->edl->session->sample_rate;
00412
00413 int64_t startsource = (int64_t)(((pixmap->pixmap_x - virtual_edit_x + x) *
00414 mwindow->edl->local_session->zoom_sample +
00415 edit->startsource) *
00416 asset_over_session);
00417
00418 if (startsource < 0) startsource = 0;
00419 int64_t length = (int64_t)(w *
00420 mwindow->edl->local_session->zoom_sample *
00421 asset_over_session);
00422
00423 if(asset->index_status == INDEX_BUILDING)
00424 {
00425 if(startsource + length > asset->index_end)
00426 length = asset->index_end - startsource;
00427 }
00428
00429
00430 int64_t lengthindex = length / asset->index_zoom * 2;
00431
00432 int64_t startindex = startsource / asset->index_zoom * 2;
00433
00434 if(startindex + lengthindex > asset->get_index_size(edit->channel))
00435 lengthindex = asset->get_index_size(edit->channel) - startindex;
00436 if(lengthindex <= 0) return 0;
00437
00438
00439
00440
00441
00442 int64_t length_read;
00443
00444 int64_t startfile, lengthfile;
00445 float *buffer = 0;
00446 int buffer_shared = 0;
00447 int i;
00448 int center_pixel = mwindow->edl->local_session->zoom_track / 2;
00449 if(mwindow->edl->session->show_titles) center_pixel += mwindow->theme->title_bg_data->get_h();
00450 int miny = center_pixel - mwindow->edl->local_session->zoom_track / 2;
00451 int maxy = center_pixel + mwindow->edl->local_session->zoom_track / 2;
00452 int x1 = 0, y1, y2;
00453
00454 double index_frames_per_pixel = mwindow->edl->local_session->zoom_sample /
00455 asset->index_zoom *
00456 asset_over_session;
00457
00458
00459 startindex += asset->get_index_offset(edit->channel);
00460
00461
00462 if(asset->index_status == INDEX_BUILDING)
00463 {
00464
00465 buffer = &(asset->index_buffer[startindex]);
00466 buffer_shared = 1;
00467 }
00468 else
00469 {
00470
00471 buffer = new float[lengthindex + 1];
00472 buffer_shared = 0;
00473 startfile = asset->index_start + startindex * sizeof(float);
00474 lengthfile = lengthindex * sizeof(float);
00475 length_read = 0;
00476
00477 if(startfile < file_length)
00478 {
00479 fseek(file, startfile, SEEK_SET);
00480
00481 length_read = lengthfile;
00482 if(startfile + length_read > file_length)
00483 length_read = file_length - startfile;
00484
00485 fread(buffer, length_read + sizeof(float), 1, file);
00486 }
00487
00488 if(length_read < lengthfile)
00489 for(i = length_read / sizeof(float);
00490 i < lengthfile / sizeof(float);
00491 i++)
00492 buffer[i] = 0;
00493 }
00494
00495
00496
00497 pixmap->canvas->set_color(mwindow->theme->audio_color);
00498
00499
00500 double current_frame = 0;
00501 float highsample = buffer[0];
00502 float lowsample = buffer[1];
00503 int prev_y1 = center_pixel;
00504 int prev_y2 = center_pixel;
00505 int first_frame = 1;
00506
00507 for(int bufferposition = 0;
00508 bufferposition < lengthindex;
00509 bufferposition += 2)
00510 {
00511 if(current_frame >= index_frames_per_pixel)
00512 {
00513 int next_y1 = (int)(center_pixel - highsample * mwindow->edl->local_session->zoom_y / 2);
00514 int next_y2 = (int)(center_pixel - lowsample * mwindow->edl->local_session->zoom_y / 2);
00515 int y1 = next_y1;
00516 int y2 = next_y2;
00517
00518
00519
00520 if(mwindow->edl->local_session->zoom_sample == 1)
00521 {
00522 pixmap->canvas->draw_line(x1 + x - 1, prev_y1, x1 + x, y1, pixmap);
00523 }
00524 else
00525 {
00526
00527 if(!first_frame)
00528 {
00529 if(y1 > prev_y2) y1 = prev_y2 + 1;
00530 if(y2 < prev_y1) y2 = prev_y1 - 1;
00531 }
00532 else
00533 {
00534 first_frame = 0;
00535 }
00536 pixmap->canvas->draw_line(x1 + x, y1, x1 + x, y2, pixmap);
00537 }
00538 current_frame -= index_frames_per_pixel;
00539 x1++;
00540 prev_y1 = next_y1;
00541 prev_y2 = next_y2;
00542 highsample = buffer[bufferposition];
00543 lowsample = buffer[bufferposition + 1];
00544 }
00545
00546 current_frame++;
00547 highsample = MAX(highsample, buffer[bufferposition]);
00548 lowsample = MIN(lowsample, buffer[bufferposition + 1]);
00549 }
00550
00551
00552 if(current_frame)
00553 {
00554 y1 = (int)(center_pixel - highsample * mwindow->edl->local_session->zoom_y / 2);
00555 y2 = (int)(center_pixel - lowsample * mwindow->edl->local_session->zoom_y / 2);
00556 pixmap->canvas->draw_line(x1 + x, y1, x1 + x, y2, pixmap);
00557 }
00558
00559
00560
00561
00562 if(!buffer_shared) delete [] buffer;
00563 return 0;
00564 }
00565
00566 int IndexFile::close_index()
00567 {
00568 if(file)
00569 {
00570 fclose(file);
00571 file = 0;
00572 }
00573 }
00574
00575 int IndexFile::remove_index()
00576 {
00577 if(asset->index_status == INDEX_READY || asset->index_status == INDEX_NOTTESTED)
00578 {
00579 close_index();
00580 remove(index_filename);
00581 }
00582 }
00583
00584 int IndexFile::read_info(Asset *test_asset)
00585 {
00586 if(!test_asset) test_asset = asset;
00587 if(test_asset->index_status == INDEX_NOTTESTED)
00588 {
00589
00590 fread((char*)&(test_asset->index_start), sizeof(int64_t), 1, file);
00591
00592
00593 char *data;
00594
00595 data = new char[test_asset->index_start];
00596 fread(data, test_asset->index_start - sizeof(int64_t), 1, file);
00597 data[test_asset->index_start - sizeof(int64_t)] = 0;
00598 FileXML xml;
00599 xml.read_from_string(data);
00600 test_asset->read(&xml);
00601
00602 delete [] data;
00603 if(test_asset->format == FILE_UNKNOWN)
00604 {
00605 return 1;
00606 }
00607 }
00608 return 0;
00609 }