3 * Copyright (C) 2011 Adam Williams <broadcast at earthling dot net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "bcsignals.h"
27 #include "filescene.h"
28 #include "filesystem.h"
30 #include "scenegraph.h"
46 // Paths relative to the exe path
47 #define FESTIVAL_PATH "/festival"
48 #define FESTIVAL_LIB_PATH "/lib/"
49 #define ASSET_PATH "/models/"
50 #define FREAD_SIZE 0x10000
52 #define FESTIVAL_SAMPLERATE 16000
53 #define PAUSE_SAMPLES FESTIVAL_SAMPLERATE
54 // Amount to truncate if ...
55 #define ADVANCE_SAMPLES FESTIVAL_SAMPLERATE
57 // Maximum characters in a line of dialog is limited by festival
58 #define MAX_CHARS 65536
60 #define STRIP_LINE(string) \
61 /* Strip linefeeds */ \
62 while(len > 0 && (string[len - 1] == '\n' || \
63 string[len - 1] == ' ')) \
65 string[len - 1] = 0; \
69 /* Strip comments */ \
70 for(i = 0; i < len; i++) \
72 if(string[i] == '#') \
82 #define STRING_PARAMETER(title, need_char, dst) \
83 if(!strncmp(command, title, strlen(title))) \
85 /* advance to argument */ \
87 while(string[i] != 0 && string[i] == ' ') \
90 if(current_char || !need_char) \
92 /* printf("STRING_PARAMETER %s %s %p\n", title, string + i, dst); */ \
93 strcpy(dst, string + i); \
97 printf("FileScene::read_script %d Line %d: %s but no current character\n", \
106 static int read_parameter(char *string,
114 char *command = string + *i;
117 if(!strncmp(command, title, strlen(title)))
121 for(int j = 0; j < 4; j++)
123 /* skip to start of argument */
124 while(string[*i] != 0 && string[*i] == ' ')
129 arg_text[j] = string + *i;
130 while(string[*i] != 0 && string[*i] != ' ')
139 // printf("read_parameter %d %s %s %s %s\n",
150 char *ptr1 = dst_string;
151 char *ptr2 = arg_text[0];
152 while(*ptr2 != 0 && *ptr2 != ' ')
159 *dst_float0 = atof(arg_text[0]);
167 *dst_float1 = atof(arg_text[1]);
175 *dst_float2 = atof(arg_text[2]);
197 FileScene::FileScene(Asset *asset, File *file)
198 : FileBase(asset, file)
201 get_exe_path(exe_path);
205 FileScene::~FileScene()
212 int FileScene::open_file(int rd, int wr)
214 // Load the script to get character count
220 asset->format = FILE_SCENE;
221 asset->video_data = 1;
222 // Should be set in the scene file
226 // Dictated by character animations
227 asset->frame_rate = (double)30000 / 1001;
228 // Some arbitrary default length.
229 // Hard to calculate without rendering it.
230 asset->video_length = -1;
234 asset->audio_data = 1;
235 // The speech synthesizer outputs different samplerates depending on the speaker.
236 // The heroine voices are all 16khz
237 asset->sample_rate = FESTIVAL_SAMPLERATE;
238 // Mono voice placement for now
239 // Maybe a different track for each voice in the future or 3D positioning
240 asset->channels = script->total_characters();
241 asset->audio_length = -1;
247 int FileScene::close_file()
250 delete [] audio_temp;
253 FileBase::close_file();
258 int FileScene::check_sig(Asset *asset, char *test)
260 if(!strncmp(test, "TEXT2MOVIE", 10)) return 1;
267 int FileScene::set_video_position(int64_t x)
273 int FileScene::set_audio_position(int64_t x)
279 int FileScene::read_frame(VFrame *frame)
281 // Everything is timed based on speech, so render the audio for this frame.
285 frame->clear_frame();
286 int64_t audio_position1 = (int64_t)(file->current_frame *
289 int64_t audio_position2 = (int64_t)(audio_position1 +
293 if(debug) printf("FileScene::read_frame %d frame=%jd"
294 " frame_rate=%f sample_rate=%d audio_position1=%jd"
295 " audio_position2=%jd\n", __LINE__,
296 file->current_frame, asset->frame_rate,
297 asset->sample_rate, audio_position1,
300 render_chunks(audio_position1,
301 audio_position2 - audio_position1,
303 if(!script) return 1;
304 if(debug) printf("FileScene::read_frame %d\n", __LINE__);
309 // Determine lip position from amplitude
311 for(int i = 0; i < audio_position2 - audio_position1; i++)
313 double sample_float = fabs((double)audio_temp[i] / 32768);
314 if(sample_float > accum) accum = sample_float;
316 if(debug) printf("FileScene::read_frame %d accum=%f\n", __LINE__, accum);
319 for(int i = 0; i < script->total_characters(); i++)
321 SceneChar *character = script->get_character(i);
322 character->current_camera = SceneChar::CAMERA_WIDE;
323 character->is_speeking = 0;
327 // Now determine most recent character which is speaking from the sample times.
328 int64_t current_sample = 0;
329 SceneChar *speeking_character = 0;
330 // Sample relative to start of chunk
331 int64_t chunk_sample = 0;
333 i < script->total_chunks() && current_sample < audio_position2;
336 SceneChunk *chunk = script->get_chunk(i);
337 int samples = chunk->audio_size / 2;
340 if(audio_position1 >= current_sample &&
341 audio_position1 < current_sample + samples)
343 speeking_character = chunk->character;
344 speeking_character->max = chunk->max;
345 chunk->character->is_speeking = 1;
346 chunk_sample = audio_position1 - current_sample;
350 if(!chunk->character->is_speeking)
352 chunk->character->increment_camera();
355 current_sample += chunk->advance_samples;
360 if(debug) printf("FileScene::read_frame %d\n", __LINE__);
363 // Store component placement in a scene graph.
365 //SceneNode *speeking_node = 0;
367 // Scale for the entire scene
368 SceneCamera *camera = new SceneCamera;
369 scene.append_camera(camera);
374 if(script->background[0])
376 script->render_background(&scene);
379 if(debug) printf("FileScene::read_frame %d\n", __LINE__);
382 for(int i = 0; i < script->total_characters(); i++)
384 SceneChar *character = script->get_character(i);
386 character->read_model();
388 // Nodes for the character
389 SceneNode *character_node = new SceneNode(character->name);
390 scene.append(character_node);
391 character_node->sx = character_node->sy = character->scale;
393 SceneNode *head_node = new SceneNode("head");
395 SceneNode *body_node = new SceneNode("body");
397 // Render in the order listed in the file
398 if(debug) printf("FileScene::read_frame %d\n", __LINE__);
399 for(int j = 0; j < 2; j++)
401 if(debug) printf("FileScene::read_frame %d j=%d head_order=%d body_order=%d\n",
404 character->head_order,
405 character->body_order);
406 if(j == character->head_order) character_node->append(head_node);
408 if(j == character->body_order) character_node->append(body_node);
411 SceneNode *eye_node = 0;
412 if(character->eyes.size())
414 eye_node = new SceneNode("eyes");
415 head_node->append(eye_node);
418 SceneNode *mouth_node = new SceneNode("mouth");
419 head_node->append(mouth_node);
421 // Logical character placement
422 switch(script->total_characters())
425 if(speeking_character == character &&
426 speeking_character->current_camera == SceneChar::CAMERA_CU)
428 camera->at_x = asset->width / 4;
431 character_node->x = (int)(asset->width / 2 -
432 character->w * character->scale / 2);
433 character_node->y = (int)(asset->height -
434 character->h * character->scale);
440 character_node->x = 0;
441 character_node->y = (int)(asset->height -
442 character->h * character->scale);
444 if(speeking_character == character &&
445 speeking_character->current_camera == SceneChar::CAMERA_CU)
447 camera->at_y = character_node->y;
448 camera->at_x = character_node->x +
449 (character->head->x + character->head->image->get_w() / 2) * character->scale -
451 CLAMP(camera->at_x, 0, asset->width / 2);
452 CLAMP(camera->at_y, 0, asset->height);
453 //printf("FileScene::read_frame %d camera->at_x=%f camera->at_y=%f\n", __LINE__, camera->at_x, camera->at_y);
456 if(character->faces_left)
458 character_node->flip = 1;
459 character_node->x = asset->width -
460 character->w * character->scale;
466 character_node->x = (int)(asset->width -
467 character->w * character->scale);
468 character_node->y = (int)(asset->height -
469 character->h * character->scale);
471 if(speeking_character == character &&
472 speeking_character->current_camera == SceneChar::CAMERA_CU)
474 camera->at_x = character_node->x +
475 character->head->x * character->scale -
477 CLAMP(camera->at_x, 0, asset->width / 2);
480 if(!character->faces_left)
482 character_node->flip = 1;
483 character_node->x = 0;
491 character_node->x = 0;
492 character_node->y = (int)(asset->height -
493 character->h * character->scale);
494 if(character->faces_left)
496 character_node->flip = 1;
502 if(speeking_character == character &&
503 speeking_character->current_camera == SceneChar::CAMERA_CU)
505 camera->at_x = asset->width / 4;
507 character_node->x = (int)(asset->width / 2 -
508 character->w * character->scale / 2);
509 character_node->y = (int)(asset->height -
510 character->h * character->scale);
511 if(character->faces_left)
513 character_node->flip = 1;
518 if(speeking_character == character &&
519 speeking_character->current_camera == SceneChar::CAMERA_CU)
521 camera->at_x = asset->width / 2;
523 character_node->x = (int)(asset->width -
524 character->w * character->scale);
525 character_node->y = (int)(asset->height -
526 character->h * character->scale);
527 if(!character->faces_left)
529 character_node->flip = 1;
530 character_node->x = 0;
537 if(character_node->y < 0) character_node->y = 0;
539 // Add remaining parts
540 body_node->copy_ref(character->body);
541 head_node->copy_ref(character->head);
543 // Speeker head rotation
544 if(speeking_character == character)
546 //speeking_node = character_node;
548 int head_time = (chunk_sample / asset->sample_rate / 2) % 2;
553 double anim_position = modf((double)chunk_sample / asset->sample_rate / 2, &temp);
554 double anim_length = 0.1;
555 // printf("FileScene::read_frame %d %d %f\n",
560 if(anim_position < anim_length)
561 head_node->ry = -5 * anim_position / anim_length;
563 if(anim_position > 1.0 - anim_length)
564 head_node->ry = -5 * (1.0 - anim_position) / anim_length;
570 //head_node->ry = -5;
574 if(character->eyes.size())
576 if(modf((file->current_frame / asset->frame_rate + script->get_char_number(character)) / 5, &intpart) <=
578 file->current_frame / asset->frame_rate > 1)
580 eye_node->copy_ref(character->eyes.get(0));
583 eye_node->copy_ref(character->eyes.get(1));
586 // Compute the mouth image
588 if(character->is_speeking && character->max > 0)
590 fraction = (int)(accum * character->mouths.size() / character->max);
591 if(fraction >= character->mouths.size())
592 fraction = character->mouths.size() - 1;
595 mouth_node->copy_ref(character->mouths.get(fraction));
598 // camera->scale = 2;
599 // camera->at_x = asset->width / 2;
603 if(speeking_character == character &&
604 speeking_character->current_camera == SceneChar::CAMERA_CU)
606 // If closeup, increase scene scale
614 if(debug) printf("FileScene::read_frame %d\n", __LINE__);
618 // Render scene graph
619 scene.render(frame, file->cpus);
623 if(debug) printf("FileScene::read_frame %d\n", __LINE__);
630 int FileScene::read_samples(double *buffer, int64_t len)
633 // Everything is timed based on speech, so we have to do this for video, too.
634 render_chunks(file->current_sample, len, 0);
639 // Convert temp to output
640 for(int i = 0; i < len; i++)
642 buffer[i] = (double)audio_temp[i] / 32768;
649 int64_t FileScene::get_memory_usage()
652 int total = 0x100000;
655 total += script->get_memory_usage();
664 int FileScene::get_best_colormodel(Asset *asset, int driver)
670 int FileScene::colormodel_supported(int colormodel)
676 int FileScene::can_copy_from(Asset *asset, int64_t position)
682 int FileScene::reset_parameters_derived()
694 void FileScene::render_chunks(int64_t start_position,
698 int64_t end_position = start_position + len;
702 if(debug) printf("FileScene::render_chunks %d start_position=%jd"
703 " len=%jd\n", __LINE__, start_position, len);
710 if(debug) PRINT_TRACE
712 // Reallocate temp buffer
713 if(len > temp_allocated)
715 delete [] audio_temp;
716 audio_temp = new int16_t[len];
717 temp_allocated = len;
719 bzero(audio_temp, sizeof(int16_t) * len);
721 if(debug) PRINT_TRACE
726 // Find start_position in script output.
727 // Must know length of every chunk before end of buffer
728 int64_t current_sample = 0;
729 for(int i = 0; i < script->total_chunks() &&
730 current_sample < end_position; i++)
732 SceneChunk *chunk = script->get_chunk(i);
734 if(debug) printf("FileScene::render_chunks %d\n", __LINE__);
736 // If extent of audio output hasn't been calculated, render it
737 if(!chunk->audio_size)
739 if(debug) printf("FileScene::render_chunks %d i=%d\n", __LINE__, i);
743 // Dialog chunk is inside output buffer
744 if(current_sample + chunk->audio_size / 2 > start_position &&
745 current_sample < end_position)
747 if(debug) printf("FileScene::render_chunks %d\n", __LINE__);
749 // If no audio output exists, render it
752 if(debug) printf("FileScene::render_chunks %d rerendering audio\n", __LINE__);
756 if(debug) printf("FileScene::render_chunks %d: Using \"%s\" samples=%d\n",
759 chunk->audio_size / 2);
760 if(debug) printf("FileScene::render_chunks %d: start_position=%jd"
761 " current_sample=%jd\n", __LINE__,
762 start_position, current_sample);
765 // TODO: allow characters to talk simultaneously
766 int64_t src_offset = start_position - current_sample;
767 int64_t dst_offset = 0;
768 int64_t src_len = chunk->audio_size / 2 - src_offset;
770 if(debug) printf("FileScene::render_chunks %d: src_offset=%jd"
771 " dst_offset=%jd src_len=%jd\n", __LINE__,
772 src_offset, dst_offset, src_len);
776 dst_offset -= src_offset;
777 src_len += src_offset;
781 if(dst_offset + src_len > len)
783 src_len = len - dst_offset;
786 if(debug) printf("FileScene::render_chunks %d: src_offset=%jd"
787 " dst_offset=%jd src_len=%jd\n", __LINE__,
788 src_offset, dst_offset, src_len);
790 // Transfer if right channel
792 file->current_channel == script->get_char_number(chunk->character))
794 for(int j = 0; j < src_len; j++)
796 audio_temp[dst_offset + j] =
797 chunk->audio[(src_offset + j) * 2] |
798 (chunk->audio[(src_offset + j) * 2 + 1] << 8);
802 if(debug) printf("FileScene::render_chunks %d\n", __LINE__);
806 current_sample += chunk->advance_samples;
809 // Erase unused dialog chunks
810 if(debug) printf("FileScene::render_chunks %d\n", __LINE__);
811 for(int i = 0; i < script->total_chunks(); i++)
813 SceneChunk *chunk = script->get_chunk(i);
814 if(!chunk->used && chunk->audio)
816 if(debug) printf("FileScene::render_chunks %d erasing unused audio\n", __LINE__);
817 delete [] chunk->audio;
819 chunk->audio_allocated = 0;
822 if(debug) printf("FileScene::render_chunks %d\n", __LINE__);
829 int FileScene::read_script()
833 if(stat(asset->path, &ostat))
835 printf("FileScene::read_script %d: %s\n", __LINE__, strerror(errno));
842 if(ostat.st_mtime == script->timestamp)
844 if(debug) printf("FileScene::read_script %d: script unchanged\n", __LINE__);
853 if(!script) script = new SceneTokens(this, file->cpus);
854 script->timestamp = ostat.st_mtime;
856 script->read_script(asset->path);
875 SceneChar::SceneChar(SceneTokens *script)
877 this->script = script;
884 sprintf(model, "heroine01");
885 current_camera = CAMERA_WIDE;
892 SceneChar::~SceneChar()
894 mouths.remove_all_objects();
895 eyes.remove_all_objects();
901 void SceneChar::increment_camera()
904 if(current_camera >= CAMERA_TOTAL)
909 int SceneChar::read_model()
911 // Read descriptor file
913 int current_line = 0;
916 int current_order = 0;
917 char path[BCTEXTLEN];
922 script->convert_path(path, model);
923 FILE *fd = fopen(path, "r");
930 char string[BCTEXTLEN];
931 char string2[BCTEXTLEN];
935 char *result = fgets(string, BCTEXTLEN, fd);
939 int len = strlen(string);
943 if(debug) printf("SceneChar::read_model %d: %s\n",
947 for(i = 0; i < len; i++)
949 if(isalnum(string[i]))
953 if(read_parameter(string,
963 if(read_parameter(string,
973 if(read_parameter(string,
982 body = new SceneNode(script->load_image(string2), 1, x, y);
983 body_order = current_order++;
986 if(read_parameter(string,
995 head = new SceneNode(script->load_image(string2), 1, x, y);
996 head_order = current_order++;
999 if(read_parameter(string,
1009 mouths.append(mouth = new SceneNode(script->load_image(string2), 1, x, y));
1010 // Make coordinates relative to head
1013 mouth->x -= head->x;
1014 mouth->y -= head->y;
1018 if(read_parameter(string,
1028 eyes.append(eye = new SceneNode(script->load_image(string2), 1, x, y));
1029 // Make coordinates relative to head
1037 if(read_parameter(string,
1048 if(read_parameter(string,
1071 printf("SceneChar::read_model %d: %s %s\n", __LINE__, path, strerror(errno));
1075 int SceneChar::get_memory_usage()
1078 if(body) total += body->get_memory_usage();
1079 if(head) total += head->get_memory_usage();
1080 for(int i = 0; i < mouths.size(); i++)
1081 total += mouths.get(i)->get_memory_usage();
1085 void SceneChar::dump()
1087 printf("SceneChar::dump %d: %p name=%s voice=%s model=%s body=%p eyes=%d mouths=%d\n",
1096 printf("SceneChar::dump %d: w=%f h=%f\n", __LINE__, w, h);
1099 for(int i = 0; i < mouths.size(); i++)
1101 SceneNode *node = mouths.get(i);
1102 printf(" mouth=%p x=%f y=%f\n", node, node->x, node->y);
1105 for(int i = 0; i < eyes.size(); i++)
1107 SceneNode *node = eyes.get(i);
1108 printf(" eyes=%p x=%f y=%f\n", node, node->x, node->y);
1120 // Dialog from a single character
1121 SceneChunk::SceneChunk(SceneTokens *script)
1127 audio_allocated = 0;
1128 advance_samples = 0;
1131 command = NO_COMMAND;
1132 this->script = script;
1135 SceneChunk::~SceneChunk()
1141 void SceneChunk::dump()
1143 printf("SceneChunk::dump %d: character=%s command=%d text=%s\n",
1148 printf("SceneChunk::dump %d: audio=%p audio_size=%d advance_samples=%d\n",
1155 int SceneChunk::get_memory_usage()
1157 return audio_allocated;
1161 void SceneChunk::append_text(char *new_text)
1163 char string[BCTEXTLEN];
1168 int len = strlen(new_text);
1169 for(int i = 0; i < len; i++)
1171 // if(new_text[i] == '"')
1174 // if(new_text[i] == '\'')
1181 *ptr++ = new_text[i];
1185 int len2 = strlen(string);
1188 int len1 = strlen(text);
1192 // if(len1 > 0 && isalnum(text[len1 - 1]))
1193 if(len1 > 0 && text[len1 - 1] != ' ')
1199 text = (char*)realloc(text, len1 + len2 + len3);
1210 text = new char[len2 + 1];
1214 strcat(text, string);
1220 void SceneChunk::render()
1222 const int debug = 0;
1224 char command_line[BCTEXTLEN];
1225 char string2[MAX_CHARS];
1226 char script_path[BCTEXTLEN];
1228 //int total_args = 0;
1229 if(text) len = strlen(text);
1230 char *text_end = text + len;
1231 char *text_ptr = text;
1237 printf("SceneChunk::render %d: no character defined.\n", __LINE__);
1242 printf("SceneChunk::render %d: text '%s' exceeds festival's maximum line length of %d chars.\n",
1251 case SceneChunk::PAUSE_COMMAND:
1252 audio_allocated = PAUSE_SAMPLES * 2;
1253 audio_size = PAUSE_SAMPLES * 2;
1254 advance_samples = PAUSE_SAMPLES;
1255 audio = (unsigned char*)realloc(audio, audio_allocated);
1256 bzero(audio, audio_size);
1261 while(text && text_ptr < text_end)
1263 // Copy at most MAX_CHARS of data into string2
1264 char *ptr = string2;
1265 for(int i = 0; i < MAX_CHARS && text_ptr < text_end; i++)
1267 *ptr++ = *text_ptr++;
1272 // Rewind to white space if still more text
1273 if(text_ptr < text_end)
1277 while(*text_ptr != ' ' &&
1278 *text_ptr != '\n' &&
1286 // Truncate string2 at white space
1288 // If no white space, abort.
1289 if(text_ptr <= text)
1297 sprintf(script_path, "/tmp/cinelerra.");
1298 uuid_generate(temp_id);
1299 uuid_unparse(temp_id, script_path + strlen(script_path));
1300 FILE *script_fd = fopen(script_path, "w");
1302 sprintf(command_line, "%s%s --libdir %s%s -b %s",
1303 script->file->exe_path,
1305 script->file->exe_path,
1310 // The maximum text length is limited with the command line
1314 "(set! text (Utterance Text \"%s\"))\n"
1316 "(utt.save.wave text \"-\")",
1324 printf("SceneChunk::render %d %s\n",
1328 FILE *script_fd = fopen(script_path, "r");
1329 while(!feof(script_fd))
1330 fputc(fgetc(script_fd), stdout);
1335 // popen only does half duplex
1336 FILE *fd = popen(command_line, "r");
1341 int audio_start = audio_size;
1344 if(debug) printf("SceneChunk::render %d\n",
1348 if(debug) printf("SceneChunk::render %d\n",
1350 if(audio_size + FREAD_SIZE > audio_allocated)
1352 audio_allocated += FREAD_SIZE;
1353 audio = (unsigned char*)realloc(audio, audio_allocated);
1357 if(debug) printf("SceneChunk::render %d audio=%p audio_size=%d\n",
1362 int bytes_read = fread(audio + audio_size, 1, FREAD_SIZE, fd);
1363 if(debug) printf("SceneChunk::render %d bytes_read=%d\n",
1366 audio_size += bytes_read;
1367 if(bytes_read < FREAD_SIZE)
1376 if(debug) printf("SceneChunk::render %d audio=%p audio_size=%d audio_allocated=%d\n",
1384 if(audio_size - audio_start > WAVHEADER)
1386 // for(int i = 0; i < 128; i++)
1388 // printf("%c ", audio[audio_start + i]);
1389 // if(!((i + 1) % 16)) printf("\n");
1392 // Find header after error messages
1393 int header_size = WAVHEADER;
1394 for(int i = audio_start; i < audio_start + audio_size - 4; i++)
1396 if(audio[i] == 'R' &&
1397 audio[i + 1] == 'I' &&
1398 audio[i + 2] == 'F' &&
1399 audio[i + 3] == 'F')
1401 header_size += i - audio_start;
1406 memcpy(audio + audio_start,
1407 audio + audio_start + header_size,
1408 audio_size - audio_start - header_size);
1409 audio_size -= header_size;
1410 if(debug) printf("SceneChunk::render %d: audio_size=%d\n",
1415 advance_samples = audio_size / 2;
1419 printf("SceneChunk::render %d: Couldn't run %s: %s\n",
1425 remove(script_path);
1426 if(debug) printf("SceneChunk::render %d max=%f\n",
1436 text_ptr = text + len - 1;
1437 while(text_ptr > text &&
1438 (*text_ptr == ' ' ||
1441 if(text_ptr > text + 3 &&
1442 *(text_ptr - 0) == '.' &&
1443 *(text_ptr - 1) == '.' &&
1444 *(text_ptr - 2) == '.')
1446 advance_samples -= ADVANCE_SAMPLES;
1447 if(advance_samples < 0) advance_samples = 0;
1450 // Calculate loudest part
1452 for(int i = 0; i < audio_size; i += 2)
1454 int16_t sample = audio[i] |
1455 (audio[i + 1] << 8);
1456 double sample_float = fabs((double)sample / 32768);
1457 if(sample_float > max) max = sample_float;
1474 SceneTokens::SceneTokens(FileScene *file, int cpus)
1477 background_image = 0;
1484 SceneTokens::~SceneTokens()
1486 chunks.remove_all_objects();
1487 characters.remove_all_objects();
1488 delete background_image;
1489 // delete overlayer;
1492 SceneChar* SceneTokens::get_character(char *name)
1494 const int debug = 0;
1495 if(debug) printf("SceneTokens::get_character %d %d\n",
1499 for(int i = 0; i < characters.size(); i++)
1501 if(!strcmp(characters.get(i)->name, name)) return characters.get(i);
1503 if(debug) printf("SceneTokens::get_character %d %d\n",
1507 SceneChar *result = new SceneChar(this);
1508 if(debug) printf("SceneTokens::get_character %d %d this=%p\n",
1513 characters.append(result);
1514 if(debug) printf("SceneTokens::get_character %d %d\n",
1518 strcpy(result->name, name);
1519 if(debug) printf("SceneTokens::get_character %d %d\n",
1523 if(debug) printf("SceneTokens::get_character %d %d\n",
1530 SceneChar* SceneTokens::get_character(int number)
1532 return characters.get(number);
1535 int SceneTokens::get_char_number(SceneChar *ptr)
1537 for(int i = 0; i < characters.size(); i++)
1538 if(ptr == characters.get(i)) return i;
1542 SceneChunk* SceneTokens::new_chunk()
1544 SceneChunk *result = new SceneChunk(this);
1545 chunks.append(result);
1549 int SceneTokens::total_chunks()
1551 return chunks.size();
1554 int SceneTokens::total_characters()
1556 return characters.size();
1559 SceneChunk* SceneTokens::get_chunk(int number)
1561 return chunks.get(number);
1564 int SceneTokens::read_script(char *path)
1566 const int debug = 0;
1568 strcpy(this->path, path);
1570 FILE *fd = fopen(path, "r");
1574 char string[BCTEXTLEN];
1575 // Current character name
1576 char char_name[BCTEXTLEN];
1577 SceneChar *current_char = 0;
1579 SceneChunk *current_chunk = 0;
1580 int current_line = 0;
1585 char *result = fgets(string, BCTEXTLEN, fd);
1590 int len = strlen(string);
1593 if(debug) printf("SceneTokens::read_script %d: %s\n",
1597 // Skip the file ID & empty lines
1598 if(string[0] == 0 ||
1599 !strncmp(string, "TEXT2MOVIE", 10))
1603 for(i = 0; i < len; i++)
1605 if(isalnum(string[i]))
1612 if(!got_it) continue;
1614 // A line all in caps is a character name
1616 for(i = 0; i < len; i++)
1618 if(islower(string[i]))
1627 strcpy(char_name, string);
1629 if(debug) printf("SceneTokens::read_script %d: char_name=%s\n",
1633 current_char = get_character(char_name);
1635 if(debug) printf("SceneTokens::read_script %d current_char=%p\n",
1639 // Reset the current chunk pointer
1646 // Certain words are commands
1649 if(string[i] == '[' || isalnum(string[i]))
1651 char *command = string + i;
1653 STRING_PARAMETER("voice:", 1, current_char->voice)
1655 STRING_PARAMETER("model:", 1, current_char->model)
1657 STRING_PARAMETER("background:", 0, background)
1659 // Default is dialogue
1663 printf("SceneTokens::read_script %d Line %d: dialogue text but no current character\n",
1671 current_chunk = new_chunk();
1672 current_chunk->character = current_char;
1675 // Append dialogue to current chunk
1676 current_chunk->append_text(string + i);
1690 if(debug) printf("SceneTokens::read_script %d total_chunks=%d\n",
1693 // Parse commands in dialogue
1694 for(i = 0; i < total_chunks(); i++)
1696 SceneChunk *chunk = get_chunk(i);
1699 char *ptr = chunk->text;
1700 char *end = chunk->text + strlen(chunk->text);
1702 if(debug) printf("SceneTokens::read_script %d %s\n", __LINE__, chunk->text);
1708 if(debug) printf("SceneTokens::read_script %d [\n", __LINE__);
1712 SceneChunk *new_chunk = new SceneChunk(this);
1713 new_chunk->character = chunk->character;
1714 chunks.insert(new_chunk, i + 1);
1716 // Move text from start of command to new chunk.
1717 new_chunk->append_text(ptr);
1718 // Truncate current chunk
1720 // Advance to next chunk
1721 ptr = new_chunk->text;
1722 end = new_chunk->text + strlen(new_chunk->text);
1726 if(debug) printf("SceneTokens::read_script %d\n", __LINE__);
1730 (*ptr == '[' || *ptr == ' ' || *ptr == '\n'))
1733 if(debug) printf("SceneTokens::read_script %d\n", __LINE__);
1735 char *ptr2 = string;
1736 char *string_end = string + BCTEXTLEN;
1737 while(*ptr != ']' &&
1741 ptr2 < string_end - 1)
1746 if(debug) printf("SceneTokens::read_script %d command=%s\n", __LINE__, string);
1748 // Convert command to code
1749 if(!strcasecmp(string, "pause"))
1751 chunk->command = SceneChunk::PAUSE_COMMAND;
1755 // TODO: line numbers
1756 printf("SceneTokens::read_script %d: Unknown command '%s'\n",
1760 if(debug) printf("SceneTokens::read_script %d\n", __LINE__);
1762 // Search for more text
1764 (*ptr == ']' || *ptr == ' ' || *ptr == '\n'))
1767 // Create new chunk for rest of text
1770 SceneChunk *new_chunk = new SceneChunk(this);
1771 new_chunk->character = chunk->character;
1772 chunks.insert(new_chunk, i + 1);
1773 // Move text from end of command to new chunk.
1774 new_chunk->append_text(ptr);
1775 // Parse next chunk in next iteration
1779 if(debug) printf("SceneTokens::read_script %d\n", __LINE__);
1781 // Truncate current chunk
1785 // Got non whitespace
1802 printf("SceneTokens::read_script %d: %s %s\n", __LINE__, path, strerror(errno));
1806 void SceneTokens::convert_path(char *dst, char *src)
1808 // Absolute path in src
1816 // Try directory of script
1818 fs.extract_dir(dst, path);
1822 if(stat(dst, &ostat))
1824 // Try cinelerra directory
1826 strcat(dst, ASSET_PATH);
1828 //printf("SceneTokens::convert_path %d %s\n", __LINE__, dst);
1833 VFrame* SceneTokens::load_image(char *path)
1836 char complete_path[BCTEXTLEN];
1837 convert_path(complete_path, path);
1839 int64_t size = FileSystem::get_size(complete_path);
1842 printf("SceneTokens::load_image %d: Couldn't open %s\n",
1848 unsigned char *data = new unsigned char[size + 4];
1849 FILE *fd = fopen(complete_path, "r");
1850 (void)fread(data + 4, 1, size, fd);
1851 data[0] = (size >> 24) & 0xff;
1852 data[1] = (size >> 16) & 0xff;
1853 data[2] = (size >> 8) & 0xff;
1854 data[3] = size & 0xff;
1855 result = new VFramePng(data, 1.);
1859 if(!BC_CModels::has_alpha(result->get_color_model()) )
1860 printf("SceneTokens::load_image %d: image %s has no alpha channel\n",
1866 void SceneTokens::render_background(SceneGraph *scene)
1868 // Decompress background image
1869 if(!background_image)
1871 background_image = load_image(background);
1874 if(background_image)
1876 SceneNode *node = new SceneNode("background");
1877 scene->append(node);
1878 node->image = background_image;
1886 int SceneTokens::get_memory_usage()
1889 if(background_image) total += background_image->get_memory_usage();
1890 for(int i = 0; i < total_chunks(); i++)
1892 total += get_chunk(i)->get_memory_usage();
1894 for(int i = 0; i < total_characters(); i++)
1896 total += get_character(i)->get_memory_usage();
1902 void SceneTokens::dump()
1904 printf("SceneTokens::dump %d background=%s\n", __LINE__, background);
1905 for(int i = 0; i < characters.size(); i++)
1907 characters.get(i)->dump();
1911 for(int i = 0; i < chunks.size(); i++)
1913 chunks.get(i)->dump();