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"
31 #include "scenegraph.h"
47 // Paths relative to the exe path
48 #define FESTIVAL_PATH "/festival"
49 #define FESTIVAL_LIB_PATH "/lib/"
50 #define ASSET_PATH "/models/"
51 #define FREAD_SIZE 0x10000
53 #define FESTIVAL_SAMPLERATE 16000
54 #define PAUSE_SAMPLES FESTIVAL_SAMPLERATE
55 // Amount to truncate if ...
56 #define ADVANCE_SAMPLES FESTIVAL_SAMPLERATE
58 // Maximum characters in a line of dialog is limited by festival
59 #define MAX_CHARS 65536
61 #define STRIP_LINE(string) \
62 /* Strip linefeeds */ \
63 while(len > 0 && (string[len - 1] == '\n' || \
64 string[len - 1] == ' ')) \
66 string[len - 1] = 0; \
70 /* Strip comments */ \
71 for(i = 0; i < len; i++) \
73 if(string[i] == '#') \
83 #define STRING_PARAMETER(title, need_char, dst) \
84 if(!strncmp(command, title, strlen(title))) \
86 /* advance to argument */ \
88 while(string[i] != 0 && string[i] == ' ') \
91 if(current_char || !need_char) \
93 /* printf("STRING_PARAMETER %s %s %p\n", title, string + i, dst); */ \
94 strcpy(dst, string + i); \
98 printf("FileScene::read_script %d Line %d: %s but no current character\n", \
107 static int read_parameter(char *string,
115 char *command = string + *i;
118 if(!strncmp(command, title, strlen(title)))
122 for(int j = 0; j < 4; j++)
124 /* skip to start of argument */
125 while(string[*i] != 0 && string[*i] == ' ')
130 arg_text[j] = string + *i;
131 while(string[*i] != 0 && string[*i] != ' ')
140 // printf("read_parameter %d %s %s %s %s\n",
151 char *ptr1 = dst_string;
152 char *ptr2 = arg_text[0];
153 while(*ptr2 != 0 && *ptr2 != ' ')
160 *dst_float0 = atof(arg_text[0]);
168 *dst_float1 = atof(arg_text[1]);
176 *dst_float2 = atof(arg_text[2]);
198 FileScene::FileScene(Asset *asset, File *file)
199 : FileBase(asset, file)
202 get_exe_path(exe_path);
206 FileScene::~FileScene()
213 int FileScene::open_file(int rd, int wr)
215 // Load the script to get character count
221 asset->format = FILE_SCENE;
222 asset->video_data = 1;
223 // Should be set in the scene file
227 // Dictated by character animations
228 asset->frame_rate = (double)30000 / 1001;
229 // Some arbitrary default length.
230 // Hard to calculate without rendering it.
231 asset->video_length = -1;
235 asset->audio_data = 1;
236 // The speech synthesizer outputs different samplerates depending on the speaker.
237 // The heroine voices are all 16khz
238 asset->sample_rate = FESTIVAL_SAMPLERATE;
239 // Mono voice placement for now
240 // Maybe a different track for each voice in the future or 3D positioning
241 asset->channels = script->total_characters();
242 asset->audio_length = -1;
248 int FileScene::close_file()
251 delete [] audio_temp;
254 FileBase::close_file();
259 int FileScene::check_sig(Asset *asset, char *test)
261 if(!strncmp(test, "TEXT2MOVIE", 10)) return 1;
268 int FileScene::set_video_position(int64_t x)
274 int FileScene::set_audio_position(int64_t x)
280 int FileScene::read_frame(VFrame *frame)
282 // Everything is timed based on speech, so render the audio for this frame.
286 frame->clear_frame();
287 int64_t audio_position1 = (int64_t)(file->current_frame *
290 int64_t audio_position2 = (int64_t)(audio_position1 +
294 if(debug) printf("FileScene::read_frame %d frame=" _LD
295 " frame_rate=%f sample_rate=%d audio_position1=" _LD
296 " audio_position2=" _LD "\n", __LINE__,
297 file->current_frame, asset->frame_rate,
298 asset->sample_rate, audio_position1,
301 render_chunks(audio_position1,
302 audio_position2 - audio_position1,
304 if(!script) return 1;
305 if(debug) printf("FileScene::read_frame %d\n", __LINE__);
310 // Determine lip position from amplitude
312 for(int i = 0; i < audio_position2 - audio_position1; i++)
314 double sample_float = fabs((double)audio_temp[i] / 32768);
315 if(sample_float > accum) accum = sample_float;
317 if(debug) printf("FileScene::read_frame %d accum=%f\n", __LINE__, accum);
320 for(int i = 0; i < script->total_characters(); i++)
322 SceneChar *character = script->get_character(i);
323 character->current_camera = SceneChar::CAMERA_WIDE;
324 character->is_speeking = 0;
328 // Now determine most recent character which is speaking from the sample times.
329 int64_t current_sample = 0;
330 SceneChar *speeking_character = 0;
331 // Sample relative to start of chunk
332 int64_t chunk_sample = 0;
334 i < script->total_chunks() && current_sample < audio_position2;
337 SceneChunk *chunk = script->get_chunk(i);
338 int samples = chunk->audio_size / 2;
341 if(audio_position1 >= current_sample &&
342 audio_position1 < current_sample + samples)
344 speeking_character = chunk->character;
345 speeking_character->max = chunk->max;
346 chunk->character->is_speeking = 1;
347 chunk_sample = audio_position1 - current_sample;
351 if(!chunk->character->is_speeking)
353 chunk->character->increment_camera();
356 current_sample += chunk->advance_samples;
361 if(debug) printf("FileScene::read_frame %d\n", __LINE__);
364 // Store component placement in a scene graph.
366 //SceneNode *speeking_node = 0;
368 // Scale for the entire scene
369 SceneCamera *camera = new SceneCamera;
370 scene.append_camera(camera);
375 if(script->background[0])
377 script->render_background(&scene);
380 if(debug) printf("FileScene::read_frame %d\n", __LINE__);
383 for(int i = 0; i < script->total_characters(); i++)
385 SceneChar *character = script->get_character(i);
387 character->read_model();
389 // Nodes for the character
390 SceneNode *character_node = new SceneNode(character->name);
391 scene.append(character_node);
392 character_node->sx = character_node->sy = character->scale;
394 SceneNode *head_node = new SceneNode("head");
396 SceneNode *body_node = new SceneNode("body");
398 // Render in the order listed in the file
399 if(debug) printf("FileScene::read_frame %d\n", __LINE__);
400 for(int j = 0; j < 2; j++)
402 if(debug) printf("FileScene::read_frame %d j=%d head_order=%d body_order=%d\n",
405 character->head_order,
406 character->body_order);
407 if(j == character->head_order) character_node->append(head_node);
409 if(j == character->body_order) character_node->append(body_node);
412 SceneNode *eye_node = 0;
413 if(character->eyes.size())
415 eye_node = new SceneNode("eyes");
416 head_node->append(eye_node);
419 SceneNode *mouth_node = new SceneNode("mouth");
420 head_node->append(mouth_node);
422 // Logical character placement
423 switch(script->total_characters())
426 if(speeking_character == character &&
427 speeking_character->current_camera == SceneChar::CAMERA_CU)
429 camera->at_x = asset->width / 4;
432 character_node->x = (int)(asset->width / 2 -
433 character->w * character->scale / 2);
434 character_node->y = (int)(asset->height -
435 character->h * character->scale);
441 character_node->x = 0;
442 character_node->y = (int)(asset->height -
443 character->h * character->scale);
445 if(speeking_character == character &&
446 speeking_character->current_camera == SceneChar::CAMERA_CU)
448 camera->at_y = character_node->y;
449 camera->at_x = character_node->x +
450 (character->head->x + character->head->image->get_w() / 2) * character->scale -
452 CLAMP(camera->at_x, 0, asset->width / 2);
453 CLAMP(camera->at_y, 0, asset->height);
454 //printf("FileScene::read_frame %d camera->at_x=%f camera->at_y=%f\n", __LINE__, camera->at_x, camera->at_y);
457 if(character->faces_left)
459 character_node->flip = 1;
460 character_node->x = asset->width -
461 character->w * character->scale;
467 character_node->x = (int)(asset->width -
468 character->w * character->scale);
469 character_node->y = (int)(asset->height -
470 character->h * character->scale);
472 if(speeking_character == character &&
473 speeking_character->current_camera == SceneChar::CAMERA_CU)
475 camera->at_x = character_node->x +
476 character->head->x * character->scale -
478 CLAMP(camera->at_x, 0, asset->width / 2);
481 if(!character->faces_left)
483 character_node->flip = 1;
484 character_node->x = 0;
492 character_node->x = 0;
493 character_node->y = (int)(asset->height -
494 character->h * character->scale);
495 if(character->faces_left)
497 character_node->flip = 1;
503 if(speeking_character == character &&
504 speeking_character->current_camera == SceneChar::CAMERA_CU)
506 camera->at_x = asset->width / 4;
508 character_node->x = (int)(asset->width / 2 -
509 character->w * character->scale / 2);
510 character_node->y = (int)(asset->height -
511 character->h * character->scale);
512 if(character->faces_left)
514 character_node->flip = 1;
519 if(speeking_character == character &&
520 speeking_character->current_camera == SceneChar::CAMERA_CU)
522 camera->at_x = asset->width / 2;
524 character_node->x = (int)(asset->width -
525 character->w * character->scale);
526 character_node->y = (int)(asset->height -
527 character->h * character->scale);
528 if(!character->faces_left)
530 character_node->flip = 1;
531 character_node->x = 0;
538 if(character_node->y < 0) character_node->y = 0;
540 // Add remaining parts
541 body_node->copy_ref(character->body);
542 head_node->copy_ref(character->head);
544 // Speeker head rotation
545 if(speeking_character == character)
547 //speeking_node = character_node;
549 int head_time = (chunk_sample / asset->sample_rate / 2) % 2;
554 double anim_position = modf((double)chunk_sample / asset->sample_rate / 2, &temp);
555 double anim_length = 0.1;
556 // printf("FileScene::read_frame %d %d %f\n",
561 if(anim_position < anim_length)
562 head_node->ry = -5 * anim_position / anim_length;
564 if(anim_position > 1.0 - anim_length)
565 head_node->ry = -5 * (1.0 - anim_position) / anim_length;
571 //head_node->ry = -5;
575 if(character->eyes.size())
577 if(modf((file->current_frame / asset->frame_rate + script->get_char_number(character)) / 5, &intpart) <=
579 file->current_frame / asset->frame_rate > 1)
581 eye_node->copy_ref(character->eyes.get(0));
584 eye_node->copy_ref(character->eyes.get(1));
587 // Compute the mouth image
589 if(character->is_speeking && character->max > 0)
591 fraction = (int)(accum * character->mouths.size() / character->max);
592 if(fraction >= character->mouths.size())
593 fraction = character->mouths.size() - 1;
596 mouth_node->copy_ref(character->mouths.get(fraction));
599 // camera->scale = 2;
600 // camera->at_x = asset->width / 2;
604 if(speeking_character == character &&
605 speeking_character->current_camera == SceneChar::CAMERA_CU)
607 // If closeup, increase scene scale
615 if(debug) printf("FileScene::read_frame %d\n", __LINE__);
619 // Render scene graph
620 scene.render(frame, file->cpus);
624 if(debug) printf("FileScene::read_frame %d\n", __LINE__);
631 int FileScene::read_samples(double *buffer, int64_t len)
634 // Everything is timed based on speech, so we have to do this for video, too.
635 render_chunks(file->current_sample, len, 0);
640 // Convert temp to output
641 for(int i = 0; i < len; i++)
643 buffer[i] = (double)audio_temp[i] / 32768;
650 int64_t FileScene::get_memory_usage()
653 int total = 0x100000;
656 total += script->get_memory_usage();
665 int FileScene::get_best_colormodel(Asset *asset, int driver)
671 int FileScene::colormodel_supported(int colormodel)
677 int FileScene::can_copy_from(Asset *asset, int64_t position)
683 int FileScene::reset_parameters_derived()
695 void FileScene::render_chunks(int64_t start_position,
699 int64_t end_position = start_position + len;
703 if(debug) printf("FileScene::render_chunks %d start_position="
704 _LD " len=" _LD "\n", __LINE__, start_position, len);
711 if(debug) PRINT_TRACE
713 // Reallocate temp buffer
714 if(len > temp_allocated)
716 delete [] audio_temp;
717 audio_temp = new int16_t[len];
718 temp_allocated = len;
720 bzero(audio_temp, sizeof(int16_t) * len);
722 if(debug) PRINT_TRACE
727 // Find start_position in script output.
728 // Must know length of every chunk before end of buffer
729 int64_t current_sample = 0;
730 for(int i = 0; i < script->total_chunks() &&
731 current_sample < end_position; i++)
733 SceneChunk *chunk = script->get_chunk(i);
735 if(debug) printf("FileScene::render_chunks %d\n", __LINE__);
737 // If extent of audio output hasn't been calculated, render it
738 if(!chunk->audio_size)
740 if(debug) printf("FileScene::render_chunks %d i=%d\n", __LINE__, i);
744 // Dialog chunk is inside output buffer
745 if(current_sample + chunk->audio_size / 2 > start_position &&
746 current_sample < end_position)
748 if(debug) printf("FileScene::render_chunks %d\n", __LINE__);
750 // If no audio output exists, render it
753 if(debug) printf("FileScene::render_chunks %d rerendering audio\n", __LINE__);
757 if(debug) printf("FileScene::render_chunks %d: Using \"%s\" samples=%d\n",
760 chunk->audio_size / 2);
761 if(debug) printf("FileScene::render_chunks %d: start_position="
762 _LD " current_sample=" _LD "\n", __LINE__,
763 start_position, current_sample);
766 // TODO: allow characters to talk simultaneously
767 int64_t src_offset = start_position - current_sample;
768 int64_t dst_offset = 0;
769 int64_t src_len = chunk->audio_size / 2 - src_offset;
771 if(debug) printf("FileScene::render_chunks %d: src_offset="
772 _LD " dst_offset=" _LD " src_len=" _LD "\n", __LINE__,
773 src_offset, dst_offset, src_len);
777 dst_offset -= src_offset;
778 src_len += src_offset;
782 if(dst_offset + src_len > len)
784 src_len = len - dst_offset;
787 if(debug) printf("FileScene::render_chunks %d: src_offset="
788 _LD " dst_offset=" _LD " src_len=" _LD "\n", __LINE__,
789 src_offset, dst_offset, src_len);
791 // Transfer if right channel
793 file->current_channel == script->get_char_number(chunk->character))
795 for(int j = 0; j < src_len; j++)
797 audio_temp[dst_offset + j] =
798 chunk->audio[(src_offset + j) * 2] |
799 (chunk->audio[(src_offset + j) * 2 + 1] << 8);
803 if(debug) printf("FileScene::render_chunks %d\n", __LINE__);
807 current_sample += chunk->advance_samples;
810 // Erase unused dialog chunks
811 if(debug) printf("FileScene::render_chunks %d\n", __LINE__);
812 for(int i = 0; i < script->total_chunks(); i++)
814 SceneChunk *chunk = script->get_chunk(i);
815 if(!chunk->used && chunk->audio)
817 if(debug) printf("FileScene::render_chunks %d erasing unused audio\n", __LINE__);
818 delete [] chunk->audio;
820 chunk->audio_allocated = 0;
823 if(debug) printf("FileScene::render_chunks %d\n", __LINE__);
830 int FileScene::read_script()
834 if(stat(asset->path, &ostat))
836 printf("FileScene::read_script %d: %s\n", __LINE__, strerror(errno));
843 if(ostat.st_mtime == script->timestamp)
845 if(debug) printf("FileScene::read_script %d: script unchanged\n", __LINE__);
854 if(!script) script = new SceneTokens(this, file->cpus);
855 script->timestamp = ostat.st_mtime;
857 script->read_script(asset->path);
876 SceneChar::SceneChar(SceneTokens *script)
878 this->script = script;
885 sprintf(model, "heroine01");
886 current_camera = CAMERA_WIDE;
893 SceneChar::~SceneChar()
895 mouths.remove_all_objects();
896 eyes.remove_all_objects();
902 void SceneChar::increment_camera()
905 if(current_camera >= CAMERA_TOTAL)
910 int SceneChar::read_model()
912 // Read descriptor file
914 int current_line = 0;
917 int current_order = 0;
918 char path[BCTEXTLEN];
923 script->convert_path(path, model);
924 FILE *fd = fopen(path, "r");
931 char string[BCTEXTLEN];
932 char string2[BCTEXTLEN];
936 char *result = fgets(string, BCTEXTLEN, fd);
940 int len = strlen(string);
944 if(debug) printf("SceneChar::read_model %d: %s\n",
948 for(i = 0; i < len; i++)
950 if(isalnum(string[i]))
954 if(read_parameter(string,
964 if(read_parameter(string,
974 if(read_parameter(string,
983 body = new SceneNode(script->load_image(string2), 1, x, y);
984 body_order = current_order++;
987 if(read_parameter(string,
996 head = new SceneNode(script->load_image(string2), 1, x, y);
997 head_order = current_order++;
1000 if(read_parameter(string,
1010 mouths.append(mouth = new SceneNode(script->load_image(string2), 1, x, y));
1011 // Make coordinates relative to head
1014 mouth->x -= head->x;
1015 mouth->y -= head->y;
1019 if(read_parameter(string,
1029 eyes.append(eye = new SceneNode(script->load_image(string2), 1, x, y));
1030 // Make coordinates relative to head
1038 if(read_parameter(string,
1049 if(read_parameter(string,
1072 printf("SceneChar::read_model %d: %s %s\n", __LINE__, path, strerror(errno));
1076 int SceneChar::get_memory_usage()
1079 if(body) total += body->get_memory_usage();
1080 if(head) total += head->get_memory_usage();
1081 for(int i = 0; i < mouths.size(); i++)
1082 total += mouths.get(i)->get_memory_usage();
1086 void SceneChar::dump()
1088 printf("SceneChar::dump %d: %p name=%s voice=%s model=%s body=%p eyes=%d mouths=%d\n",
1097 printf("SceneChar::dump %d: w=%f h=%f\n", __LINE__, w, h);
1100 for(int i = 0; i < mouths.size(); i++)
1102 SceneNode *node = mouths.get(i);
1103 printf(" mouth=%p x=%f y=%f\n", node, node->x, node->y);
1106 for(int i = 0; i < eyes.size(); i++)
1108 SceneNode *node = eyes.get(i);
1109 printf(" eyes=%p x=%f y=%f\n", node, node->x, node->y);
1121 // Dialog from a single character
1122 SceneChunk::SceneChunk(SceneTokens *script)
1128 audio_allocated = 0;
1129 advance_samples = 0;
1132 command = NO_COMMAND;
1133 this->script = script;
1136 SceneChunk::~SceneChunk()
1142 void SceneChunk::dump()
1144 printf("SceneChunk::dump %d: character=%s command=%d text=%s\n",
1149 printf("SceneChunk::dump %d: audio=%p audio_size=%d advance_samples=%d\n",
1156 int SceneChunk::get_memory_usage()
1158 return audio_allocated;
1162 void SceneChunk::append_text(char *new_text)
1164 char string[BCTEXTLEN];
1169 int len = strlen(new_text);
1170 for(int i = 0; i < len; i++)
1172 // if(new_text[i] == '"')
1175 // if(new_text[i] == '\'')
1182 *ptr++ = new_text[i];
1186 int len2 = strlen(string);
1189 int len1 = strlen(text);
1193 // if(len1 > 0 && isalnum(text[len1 - 1]))
1194 if(len1 > 0 && text[len1 - 1] != ' ')
1200 text = (char*)realloc(text, len1 + len2 + len3);
1211 text = new char[len2 + 1];
1215 strcat(text, string);
1221 void SceneChunk::render()
1223 const int debug = 0;
1225 char command_line[BCTEXTLEN];
1226 char string2[MAX_CHARS];
1227 char script_path[BCTEXTLEN];
1229 //int total_args = 0;
1230 if(text) len = strlen(text);
1231 char *text_end = text + len;
1232 char *text_ptr = text;
1238 printf("SceneChunk::render %d: no character defined.\n", __LINE__);
1243 printf("SceneChunk::render %d: text '%s' exceeds festival's maximum line length of %d chars.\n",
1252 case SceneChunk::PAUSE_COMMAND:
1253 audio_allocated = PAUSE_SAMPLES * 2;
1254 audio_size = PAUSE_SAMPLES * 2;
1255 advance_samples = PAUSE_SAMPLES;
1256 audio = (unsigned char*)realloc(audio, audio_allocated);
1257 bzero(audio, audio_size);
1262 while(text && text_ptr < text_end)
1264 // Copy at most MAX_CHARS of data into string2
1265 char *ptr = string2;
1266 for(int i = 0; i < MAX_CHARS && text_ptr < text_end; i++)
1268 *ptr++ = *text_ptr++;
1273 // Rewind to white space if still more text
1274 if(text_ptr < text_end)
1278 while(*text_ptr != ' ' &&
1279 *text_ptr != '\n' &&
1287 // Truncate string2 at white space
1289 // If no white space, abort.
1290 if(text_ptr <= text)
1298 sprintf(script_path, "/tmp/cinelerra.");
1299 uuid_generate(temp_id);
1300 uuid_unparse(temp_id, script_path + strlen(script_path));
1301 FILE *script_fd = fopen(script_path, "w");
1303 sprintf(command_line, "%s%s --libdir %s%s -b %s",
1304 script->file->exe_path,
1306 script->file->exe_path,
1311 // The maximum text length is limited with the command line
1315 "(set! text (Utterance Text \"%s\"))\n"
1317 "(utt.save.wave text \"-\")",
1325 printf("SceneChunk::render %d %s\n",
1329 FILE *script_fd = fopen(script_path, "r");
1330 while(!feof(script_fd))
1331 fputc(fgetc(script_fd), stdout);
1336 // popen only does half duplex
1337 FILE *fd = popen(command_line, "r");
1342 int audio_start = audio_size;
1345 if(debug) printf("SceneChunk::render %d\n",
1349 if(debug) printf("SceneChunk::render %d\n",
1351 if(audio_size + FREAD_SIZE > audio_allocated)
1353 audio_allocated += FREAD_SIZE;
1354 audio = (unsigned char*)realloc(audio, audio_allocated);
1358 if(debug) printf("SceneChunk::render %d audio=%p audio_size=%d\n",
1363 int bytes_read = fread(audio + audio_size, 1, FREAD_SIZE, fd);
1364 if(debug) printf("SceneChunk::render %d bytes_read=%d\n",
1367 audio_size += bytes_read;
1368 if(bytes_read < FREAD_SIZE)
1377 if(debug) printf("SceneChunk::render %d audio=%p audio_size=%d audio_allocated=%d\n",
1385 if(audio_size - audio_start > WAVHEADER)
1387 // for(int i = 0; i < 128; i++)
1389 // printf("%c ", audio[audio_start + i]);
1390 // if(!((i + 1) % 16)) printf("\n");
1393 // Find header after error messages
1394 int header_size = WAVHEADER;
1395 for(int i = audio_start; i < audio_start + audio_size - 4; i++)
1397 if(audio[i] == 'R' &&
1398 audio[i + 1] == 'I' &&
1399 audio[i + 2] == 'F' &&
1400 audio[i + 3] == 'F')
1402 header_size += i - audio_start;
1407 memcpy(audio + audio_start,
1408 audio + audio_start + header_size,
1409 audio_size - audio_start - header_size);
1410 audio_size -= header_size;
1411 if(debug) printf("SceneChunk::render %d: audio_size=%d\n",
1416 advance_samples = audio_size / 2;
1420 printf("SceneChunk::render %d: Couldn't run %s: %s\n",
1426 remove(script_path);
1427 if(debug) printf("SceneChunk::render %d max=%f\n",
1437 text_ptr = text + len - 1;
1438 while(text_ptr > text &&
1439 (*text_ptr == ' ' ||
1442 if(text_ptr > text + 3 &&
1443 *(text_ptr - 0) == '.' &&
1444 *(text_ptr - 1) == '.' &&
1445 *(text_ptr - 2) == '.')
1447 advance_samples -= ADVANCE_SAMPLES;
1448 if(advance_samples < 0) advance_samples = 0;
1451 // Calculate loudest part
1453 for(int i = 0; i < audio_size; i += 2)
1455 int16_t sample = audio[i] |
1456 (audio[i + 1] << 8);
1457 double sample_float = fabs((double)sample / 32768);
1458 if(sample_float > max) max = sample_float;
1475 SceneTokens::SceneTokens(FileScene *file, int cpus)
1478 background_image = 0;
1485 SceneTokens::~SceneTokens()
1487 chunks.remove_all_objects();
1488 characters.remove_all_objects();
1489 delete background_image;
1490 // delete overlayer;
1493 SceneChar* SceneTokens::get_character(char *name)
1495 const int debug = 0;
1496 if(debug) printf("SceneTokens::get_character %d %d\n",
1500 for(int i = 0; i < characters.size(); i++)
1502 if(!strcmp(characters.get(i)->name, name)) return characters.get(i);
1504 if(debug) printf("SceneTokens::get_character %d %d\n",
1508 SceneChar *result = new SceneChar(this);
1509 if(debug) printf("SceneTokens::get_character %d %d this=%p\n",
1514 characters.append(result);
1515 if(debug) printf("SceneTokens::get_character %d %d\n",
1519 strcpy(result->name, name);
1520 if(debug) printf("SceneTokens::get_character %d %d\n",
1524 if(debug) printf("SceneTokens::get_character %d %d\n",
1531 SceneChar* SceneTokens::get_character(int number)
1533 return characters.get(number);
1536 int SceneTokens::get_char_number(SceneChar *ptr)
1538 for(int i = 0; i < characters.size(); i++)
1539 if(ptr == characters.get(i)) return i;
1543 SceneChunk* SceneTokens::new_chunk()
1545 SceneChunk *result = new SceneChunk(this);
1546 chunks.append(result);
1550 int SceneTokens::total_chunks()
1552 return chunks.size();
1555 int SceneTokens::total_characters()
1557 return characters.size();
1560 SceneChunk* SceneTokens::get_chunk(int number)
1562 return chunks.get(number);
1565 int SceneTokens::read_script(char *path)
1567 const int debug = 0;
1569 strcpy(this->path, path);
1571 FILE *fd = fopen(path, "r");
1575 char string[BCTEXTLEN];
1576 // Current character name
1577 char char_name[BCTEXTLEN];
1578 SceneChar *current_char = 0;
1580 SceneChunk *current_chunk = 0;
1581 int current_line = 0;
1586 char *result = fgets(string, BCTEXTLEN, fd);
1591 int len = strlen(string);
1594 if(debug) printf("SceneTokens::read_script %d: %s\n",
1598 // Skip the file ID & empty lines
1599 if(string[0] == 0 ||
1600 !strncmp(string, "TEXT2MOVIE", 10))
1604 for(i = 0; i < len; i++)
1606 if(isalnum(string[i]))
1613 if(!got_it) continue;
1615 // A line all in caps is a character name
1617 for(i = 0; i < len; i++)
1619 if(islower(string[i]))
1628 strcpy(char_name, string);
1630 if(debug) printf("SceneTokens::read_script %d: char_name=%s\n",
1634 current_char = get_character(char_name);
1636 if(debug) printf("SceneTokens::read_script %d current_char=%p\n",
1640 // Reset the current chunk pointer
1647 // Certain words are commands
1650 if(string[i] == '[' || isalnum(string[i]))
1652 char *command = string + i;
1654 STRING_PARAMETER("voice:", 1, current_char->voice)
1656 STRING_PARAMETER("model:", 1, current_char->model)
1658 STRING_PARAMETER("background:", 0, background)
1660 // Default is dialogue
1664 printf("SceneTokens::read_script %d Line %d: dialogue text but no current character\n",
1672 current_chunk = new_chunk();
1673 current_chunk->character = current_char;
1676 // Append dialogue to current chunk
1677 current_chunk->append_text(string + i);
1691 if(debug) printf("SceneTokens::read_script %d total_chunks=%d\n",
1694 // Parse commands in dialogue
1695 for(i = 0; i < total_chunks(); i++)
1697 SceneChunk *chunk = get_chunk(i);
1700 char *ptr = chunk->text;
1701 char *end = chunk->text + strlen(chunk->text);
1703 if(debug) printf("SceneTokens::read_script %d %s\n", __LINE__, chunk->text);
1709 if(debug) printf("SceneTokens::read_script %d [\n", __LINE__);
1713 SceneChunk *new_chunk = new SceneChunk(this);
1714 new_chunk->character = chunk->character;
1715 chunks.insert(new_chunk, i + 1);
1717 // Move text from start of command to new chunk.
1718 new_chunk->append_text(ptr);
1719 // Truncate current chunk
1721 // Advance to next chunk
1722 ptr = new_chunk->text;
1723 end = new_chunk->text + strlen(new_chunk->text);
1727 if(debug) printf("SceneTokens::read_script %d\n", __LINE__);
1731 (*ptr == '[' || *ptr == ' ' || *ptr == '\n'))
1734 if(debug) printf("SceneTokens::read_script %d\n", __LINE__);
1736 char *ptr2 = string;
1737 char *string_end = string + BCTEXTLEN;
1738 while(*ptr != ']' &&
1742 ptr2 < string_end - 1)
1747 if(debug) printf("SceneTokens::read_script %d command=%s\n", __LINE__, string);
1749 // Convert command to code
1750 if(!strcasecmp(string, "pause"))
1752 chunk->command = SceneChunk::PAUSE_COMMAND;
1756 // TODO: line numbers
1757 printf("SceneTokens::read_script %d: Unknown command '%s'\n",
1761 if(debug) printf("SceneTokens::read_script %d\n", __LINE__);
1763 // Search for more text
1765 (*ptr == ']' || *ptr == ' ' || *ptr == '\n'))
1768 // Create new chunk for rest of text
1771 SceneChunk *new_chunk = new SceneChunk(this);
1772 new_chunk->character = chunk->character;
1773 chunks.insert(new_chunk, i + 1);
1774 // Move text from end of command to new chunk.
1775 new_chunk->append_text(ptr);
1776 // Parse next chunk in next iteration
1780 if(debug) printf("SceneTokens::read_script %d\n", __LINE__);
1782 // Truncate current chunk
1786 // Got non whitespace
1803 printf("SceneTokens::read_script %d: %s %s\n", __LINE__, path, strerror(errno));
1807 void SceneTokens::convert_path(char *dst, char *src)
1809 // Absolute path in src
1817 // Try directory of script
1819 fs.extract_dir(dst, path);
1823 if(stat(dst, &ostat))
1825 // Try cinelerra directory
1827 strcat(dst, ASSET_PATH);
1829 //printf("SceneTokens::convert_path %d %s\n", __LINE__, dst);
1834 VFrame* SceneTokens::load_image(char *path)
1837 char complete_path[BCTEXTLEN];
1838 convert_path(complete_path, path);
1840 int64_t size = FileSystem::get_size(complete_path);
1843 printf("SceneTokens::load_image %d: Couldn't open %s\n",
1849 unsigned char *data = new unsigned char[size + 4];
1850 FILE *fd = fopen(complete_path, "r");
1851 (void)fread(data + 4, 1, size, fd);
1852 data[0] = (size >> 24) & 0xff;
1853 data[1] = (size >> 16) & 0xff;
1854 data[2] = (size >> 8) & 0xff;
1855 data[3] = size & 0xff;
1856 result = new VFramePng(data, 1.);
1860 if(!BC_CModels::has_alpha(result->get_color_model()) )
1861 printf("SceneTokens::load_image %d: image %s has no alpha channel\n",
1867 void SceneTokens::render_background(SceneGraph *scene)
1869 // Decompress background image
1870 if(!background_image)
1872 background_image = load_image(background);
1875 if(background_image)
1877 SceneNode *node = new SceneNode("background");
1878 scene->append(node);
1879 node->image = background_image;
1887 int SceneTokens::get_memory_usage()
1890 if(background_image) total += background_image->get_memory_usage();
1891 for(int i = 0; i < total_chunks(); i++)
1893 total += get_chunk(i)->get_memory_usage();
1895 for(int i = 0; i < total_characters(); i++)
1897 total += get_character(i)->get_memory_usage();
1903 void SceneTokens::dump()
1905 printf("SceneTokens::dump %d background=%s\n", __LINE__, background);
1906 for(int i = 0; i < characters.size(); i++)
1908 characters.get(i)->dump();
1912 for(int i = 0; i < chunks.size(); i++)
1914 chunks.get(i)->dump();