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