Yesterday’s Media Mix Play Audio Video Mix Emoji Tutorial gave us a basis for ongoing improved aesthetics, but to end this “Voiceover Ideas” project we go back to …
- the local web server (and also just macOS) idea of the command line “say” voiceover idea … with, today, adding more “grunt” to the voiceover ideas …
- the local web server (and our macOS one, because we installed ffmpeg there (but, alas, not on the RJM Programming domain web server)) idea of the incredible “ffmpeg” command line tool to facilitate …
- concatenation of media (remember Concatenating Video on Command Line Tutorial)
- voiceover (audio) applied to video (as [V+A] “same shortest length” voiceover result, or -V+A- voiceover at start result)
… to bookend our “Voiceover Ideas” at each end with a local web server set of concepts, integrated with two PHP code snippets as per …
<?php
// Checking if ffmpeg there and if so set up some variables ...
// ffmpeg work via PHP exec conduit to command line ...
$ffmpegcommand="";
$ffmpegselect="";
$ffmpegform="";
if (file_exists("/usr/local/bin/ffmpeg")) {
$ffmpegcommand="/usr/local/bin/ffmpeg ";
$ffmpegselect=" <select style=display:none;height:30px; id=fmsel onchange=fmselit(this.value);><option value=''>V/A++? V+A?</option><option value='+='>[V+A] 🗣</option><option value='+='>-V+A- <span title='Animated Emoji' style='opacity: 0.4; font-size: 32px;'>🎥</span><span style='margin-left: -32px; opacity: 0.4; font-size: 32px;'>🗣</span></option><option value=''>V/A++? V+A?</option><option value='+=90'>[V+A] 🗣 +90</option><option value='+=90'>-V+A- <span title='Animated Emoji' style='opacity: 0.4; font-size: 32px;'>🎥</span><span style='margin-left: -32px; opacity: 0.4; font-size: 32px;'>🗣</span> +90</option><option value=''>V/A++? V+A?</option><option value='+=180'>[V+A] 🗣 +180</option><option value='+=180'>-V+A- <span title='Animated Emoji' style='opacity: 0.4; font-size: 32px;'>🎥</span><span style='margin-left: -32px; opacity: 0.4; font-size: 32px;'>🗣</span> +180</option><option value=''>V/A++? V+A?</option><option value='+=270'>[V+A] 🗣 +270</option><option value='+=270'>-V+A- <span title='Animated Emoji' style='opacity: 0.4; font-size: 32px;'>🎥</span><span style='margin-left: -32px; opacity: 0.4; font-size: 32px;'>🗣</span> +270</option><option value='++'>V/A+V/A 🎥+🎥</option></select>";
$ffmpegform="<form target=dothework style=display:none; action=./macos_say_record.php method=POST><div><input style=display:none; type=hidden id='eangle' name='eangle' value=''></input><input style=display:none; type=hidden id='m1' name='m1' value=''></input><input style=display:none; type=hidden id='m2' name='m2' value=''></input><input style=display:none; type=hidden name='actionis' id='actionis' value='+='></input></div><input name=fprefix value='" . $ffmpegcommand . "'></input><input style=display:none; type=submit id='fmpg'></input></form>";
} else if (file_exists("/usr/bin/ffmpeg")) {
$ffmpegcommand="/usr/bin/ffmpeg ";
$ffmpegselect=" <select style=display:none;height:30px; id=fmsel onchange=fmselit(this.value);><option value=''>V/A++? V+A?</option><option value='+='>[V+A] 🗣</option><option value='+='>-V+A- <span title='Animated Emoji' style='opacity: 0.4; font-size: 32px;'>🎥</span><span style='margin-left: -32px; opacity: 0.4; font-size: 32px;'>🗣</span></option><option value=''>V/A++? V+A?</option><option value='+=90'>[V+A] 🗣 +90</option><option value='+=90'>-V+A- <span title='Animated Emoji' style='opacity: 0.4; font-size: 32px;'>🎥</span><span style='margin-left: -32px; opacity: 0.4; font-size: 32px;'>🗣</span> +90</option><option value=''>V/A++? V+A?</option><option value='+=180'>[V+A] 🗣 +180</option><option value='+=180'>-V+A- <span title='Animated Emoji' style='opacity: 0.4; font-size: 32px;'>🎥</span><span style='margin-left: -32px; opacity: 0.4; font-size: 32px;'>🗣</span> +180</option><option value=''>V/A++? V+A?</option><option value='+=270'>[V+A] 🗣 +270</option><option value='+=270'>-V+A- <span title='Animated Emoji' style='opacity: 0.4; font-size: 32px;'>🎥</span><span style='margin-left: -32px; opacity: 0.4; font-size: 32px;'>🗣</span> +270</option><option value='++'>V/A+V/A 🎥+🎥</option></select>";
$ffmpegform="<form target=dothework style=display:none; action=./macos_say_record.php method=POST><div><input style=display:none; type=hidden id='eangle' name='eangle' value=''></input><input style=display:none; type=hidden id='m1' name='m1' value=''></input><input style=display:none; type=hidden id='m2' name='m2' value=''></input><input style=display:none; type=hidden name='actionis' id='actionis' value='+='></input></div><input name=fprefix value='" . $ffmpegcommand . "'></input><input style=display:none; type=submit id='fmpg'></input></form>";
} else {
shell_exec("ffmpeg -codecs > " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "ffmhuhpeg.huh");
if (file_exists(dirname(__FILE__) . DIRECTORY_SEPARATOR . "ffmhuhpeg.huh")) {
$retblurb=file_get_contents(dirname(__FILE__) . DIRECTORY_SEPARATOR . "ffmhuhpeg.huh");
unlink(dirname(__FILE__) . DIRECTORY_SEPARATOR . "ffmhuhpeg.huh");
if (strpos($retblurb, "odecs") !== false) {
$ffmpegcommand="ffmpeg ";
$ffmpegselect=" <select style=display:none;height:30px; id=fmsel onchange=fmselit(this.value);><option value=''>V/A++? V+A?</option><option value='+='>[V+A] 🗣</option><option value='+='>-V+A- <span title='Animated Emoji' style='opacity: 0.4; font-size: 32px;'>🎥</span><span style='margin-left: -32px; opacity: 0.4; font-size: 32px;'>🗣</span></option><option value=''>V/A++? V+A?</option><option value='+=90'>[V+A] 🗣 +90</option><option value='+=90'>-V+A- <span title='Animated Emoji' style='opacity: 0.4; font-size: 32px;'>🎥</span><span style='margin-left: -32px; opacity: 0.4; font-size: 32px;'>🗣</span> +90</option><option value=''>V/A++? V+A?</option><option value='+=180'>[V+A] 🗣 +180</option><option value='+=180'>-V+A- <span title='Animated Emoji' style='opacity: 0.4; font-size: 32px;'>🎥</span><span style='margin-left: -32px; opacity: 0.4; font-size: 32px;'>🗣</span> +180</option><option value=''>V/A++? V+A?</option><option value='+=270'>[V+A] 🗣 +270</option><option value='+=270'>-V+A- <span title='Animated Emoji' style='opacity: 0.4; font-size: 32px;'>🎥</span><span style='margin-left: -32px; opacity: 0.4; font-size: 32px;'>🗣</span> +270</option><option value='++'>V/A+V/A 🎥+🎥</option></select>";
$ffmpegform="<form target=dothework style=display:none; action=./macos_say_record.php method=POST><div><input style=display:none; type=hidden id='eangle' name='eangle' value=''></input><input style=display:none; type=hidden id='m1' name='m1' value=''></input><input style=display:none; type=hidden id='m2' name='m2' value=''></input><input style=display:none; type=hidden name='actionis' id='actionis' value='+='></input></div><input name=fprefix value='" . $ffmpegcommand . "'></input><input style=display:none; type=submit id='fmpg'></input></form>";
}
} else if (file_exists("/usr/local/bin/ffmpeg")) {
$ffmpegcommand="/usr/local/bin/ffmpeg ";
$ffmpegselect=" <select style=display:none;height:30px; id=fmsel onchange=fmselit(this.value);><option value=''>V/A++? V+A?</option><option value='+='>[V+A] 🗣</option><option value='+='>-V+A- <span title='Animated Emoji' style='opacity: 0.4; font-size: 32px;'>🎥</span><span style='margin-left: -32px; opacity: 0.4; font-size: 32px;'>🗣</span></option><option value=''>V/A++? V+A?</option><option value='+=90'>[V+A] 🗣 +90</option><option value='+=90'>-V+A- <span title='Animated Emoji' style='opacity: 0.4; font-size: 32px;'>🎥</span><span style='margin-left: -32px; opacity: 0.4; font-size: 32px;'>🗣</span> +90</option><option value=''>V/A++? V+A?</option><option value='+=180'>[V+A] 🗣 +180</option><option value='+=180'>-V+A- <span title='Animated Emoji' style='opacity: 0.4; font-size: 32px;'>🎥</span><span style='margin-left: -32px; opacity: 0.4; font-size: 32px;'>🗣</span> +180</option><option value=''>V/A++? V+A?</option><option value='+=270'>[V+A] 🗣 +270</option><option value='+=270'>-V+A- <span title='Animated Emoji' style='opacity: 0.4; font-size: 32px;'>🎥</span><span style='margin-left: -32px; opacity: 0.4; font-size: 32px;'>🗣</span> +270</option><option value='++'>V/A+V/A 🎥+🎥</option></select>";
$ffmpegform="<form target=dothework style=display:none; action=./macos_say_record.php method=POST><div><input style=display:none; type=hidden id='eangle' name='eangle' value=''></input><input style=display:none; type=hidden id='m1' name='m1' value=''></input><input style=display:none; type=hidden id='m2' name='m2' value=''></input><input style=display:none; type=hidden name='actionis' id='actionis' value='+='></input></div><input name=fprefix value='" . $ffmpegcommand . "'></input><input style=display:none; type=submit id='fmpg'></input></form>";
} else if (file_exists("/usr/bin/ffmpeg")) {
$ffmpegcommand="/usr/bin/ffmpeg ";
$ffmpegselect=" <select style=display:none;height:30px; id=fmsel onchange=fmselit(this.value);><option value=''>V/A++? V+A?</option><option value='+='>[V+A] 🗣</option><option value='+='>-V+A- <span title='Animated Emoji' style='opacity: 0.4; font-size: 32px;'>🎥</span><span style='margin-left: -32px; opacity: 0.4; font-size: 32px;'>🗣</span></option><option value=''>V/A++? V+A?</option><option value='+=90'>[V+A] 🗣 +90</option><option value='+=90'>-V+A- <span title='Animated Emoji' style='opacity: 0.4; font-size: 32px;'>🎥</span><span style='margin-left: -32px; opacity: 0.4; font-size: 32px;'>🗣</span> +90</option><option value=''>V/A++? V+A?</option><option value='+=180'>[V+A] 🗣 +180</option><option value='+=180'>-V+A- <span title='Animated Emoji' style='opacity: 0.4; font-size: 32px;'>🎥</span><span style='margin-left: -32px; opacity: 0.4; font-size: 32px;'>🗣</span> +180</option><option value=''>V/A++? V+A?</option><option value='+=270'>[V+A] 🗣 +270</option><option value='+=270'>-V+A- <span title='Animated Emoji' style='opacity: 0.4; font-size: 32px;'>🎥</span><span style='margin-left: -32px; opacity: 0.4; font-size: 32px;'>🗣</span> +270</option><option value='++'>V/A+V/A 🎥+🎥</option></select>";
$ffmpegform="<form target=dothework style=display:none; action=./macos_say_record.php method=POST><div><input style=display:none; type=hidden id='eangle' name='eangle' value=''></input><input style=display:none; type=hidden id='m1' name='m1' value=''></input><input style=display:none; type=hidden id='m2' name='m2' value=''></input><input style=display:none; type=hidden name='actionis' id='actionis' value='+='></input></div><input name=fprefix value='" . $ffmpegcommand . "'></input><input style=display:none; type=submit id='fmpg'></input></form>";
}
}
?>
… and …
<?php
// ffmpeg work via PHP exec conduit to command line ...
// Thanks to https://superuser.com/questions/277642/how-to-merge-audio-and-video-file-in-ffmpeg and https://trac.ffmpeg.org/wiki/Concatenate
if (isset($_GET['actionis']) || isset($_POST['actionis'])) { // fmpeg ideas with actionis +=/+/++ and m1 and m2
$inmimetype="video/mp4";
$inext="mp4";
$immimetype="video/mp4";
$imext="mp4";
$actc="";
$extraswitch="";
$cmdpref="";
$interimext=$inext;
$i1=" -i " . dirname(__FILE__) . DIRECTORY_SEPARATOR;
$i2=" -i " . dirname(__FILE__) . DIRECTORY_SEPARATOR;
if (isset($_GET['fprefix'])) {
$cmdpref=str_replace("+"," ",urldecode($_GET['fprefix']));
} else if (isset($_POST['fprefix'])) {
$cmdpref=str_replace("+"," ",urldecode($_POST['fprefix']));
}
if (isset($_GET['actionis'])) {
$actc=str_replace(" ","+",urldecode($_GET['actionis']));
} else if (isset($_POST['actionis'])) {
$actc=str_replace(" ","+",urldecode($_POST['actionis']));
}
if ($actc == "+=") {
$extraswitch=" -shortest ";
} else if ($actc == "++") {
$interimext="ts";
}
$interimname=" -c copy " . $extraswitch . dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio__capture.";
if (isset($_GET['m1'])) {
$inmimetype=str_replace("video/quicktime","video/mp4",explode(";", explode("ata:", urldecode($_GET['m1']))[1])[0]);
$inext=str_replace("mov","mp4",str_replace("x-","",explode("/", $inmimetype)[1]));
file_put_contents("audio_capture." . $inext, base64_decode(explode(explode(";", explode("ata:", urldecode($_GET['m1']))[1])[0] . ";base64,",str_replace(" ","+",urldecode($_GET['m1'])))[1] ));
$ort="";
if (function_exists('exif_read_data')) {
$exif = exif_read_data(dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio_capture." . $inext);
if (isset($exif['Orientation'])) {
$ort = $exif['Orientation'];
}
}
$i1.="audio_capture." . $inext;
$interimext=$inext;
if (file_exists(dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio__capture." . $interimext)) {
unlink(dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio__capture." . $interimext);
}
$outputname="; " . $cmdpref . " -i " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio__capture." . $interimext . " " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "audiocapture.";
} else if (isset($_POST['m1'])) {
$inmimetype=str_replace("video/quicktime","video/mp4",explode(";", explode("ata:", urldecode($_POST['m1']))[1])[0]);
$inext=str_replace("mov","mp4",str_replace("x-","",explode("/", $inmimetype)[1]));
file_put_contents("audio_capture." . $inext, base64_decode(explode(explode(";", explode("ata:", urldecode($_POST['m1']))[1])[0] . ";base64,",str_replace(" ","+",urldecode($_POST['m1'])))[1] ));
$ort="";
if (function_exists('exif_read_data')) {
$exif = exif_read_data(dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio_capture." . $inext);
if (isset($exif['Orientation'])) {
$ort = $exif['Orientation'];
}
}
$i1.="audio_capture." . $inext;
$interimext=$inext;
if (file_exists(dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio__capture." . $interimext)) {
unlink(dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio__capture." . $interimext);
}
$outputname="; " . $cmdpref . " -i " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio__capture." . $interimext . " " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "audiocapture.";
}
if (isset($_GET['m2'])) {
$immimetype=str_replace("video/quicktime","video/mp4",explode(";", explode("ata:", urldecode($_GET['m2']))[1])[0]);
$imext=str_replace("mov","mp4",str_replace("x-","",explode("/", $immimetype)[1]));
file_put_contents("audio__capture." . $imext, base64_decode(explode(explode(";", explode("ata:", urldecode($_GET['m2']))[1])[0] . ";base64,",str_replace(" ","+",urldecode($_GET['m2'])))[1] ));
$i2.="audio__capture." . $imext;
$interimext="ts";
if (strpos($inmimetype, "video/") !== false && strpos($immimetype, "audio/") !== false) {
$interimext="mkv";
} else if (strpos($immimetype, "video/") !== false && strpos($inmimetype, "audio/") !== false) {
$interimext="mkv";
}
if (file_exists(dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio__capture." . $interimext)) {
unlink(dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio__capture." . $interimext);
}
$outputname="; " . $cmdpref . " -i " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio__capture." . $interimext . " " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "audiocapture.";
} else if (isset($_POST['m2'])) {
$immimetype=str_replace("video/quicktime","video/mp4",explode(";", explode("ata:", urldecode($_POST['m2']))[1])[0]);
$imext=str_replace("mov","mp4",str_replace("x-","",explode("/", $immimetype)[1]));
file_put_contents("xx.xx", "audio__capture." . $imext . ' ' . strlen(str_replace(" ","+",urldecode($_POST['m2']))));
file_put_contents("audio__capture." . $imext, base64_decode(explode(explode(";", explode("ata:", urldecode($_POST['m2']))[1])[0] . ";base64,",str_replace(" ","+",urldecode($_POST['m2'])))[1] ));
$i2.="audio__capture." . $imext;
$interimext="ts";
if (strpos($inmimetype, "video/") !== false && strpos($immimetype, "audio/") !== false) {
$interimext="mkv";
} else if (strpos($immimetype, "video/") !== false && strpos($inmimetype, "audio/") !== false) {
$interimext="mkv";
}
if (file_exists(dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio__capture." . $interimext)) {
unlink(dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio__capture." . $interimext);
}
$outputname="; " . $cmdpref . " -i " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio__capture." . $interimext . " " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "audiocapture.";
}
$omimetype=str_replace("video/quicktime","video/mp4",$inmimetype);
$oext=str_replace("mov","mp4",$inext);
$ort="";
if (isset($_GET['fprefix']) || isset($_POST['fprefix'])) {
if ($actc == "++") {
if (file_exists(dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio1capture.ts")) {
unlink(dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio1capture.ts");
}
if (file_exists(dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio2capture.ts")) {
unlink(dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio2capture.ts");
}
if (file_exists(dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio_capture.ts")) {
unlink(dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio_capture.ts");
}
// ffmpeg -i air_drop_messages_live_0photo.mov air_drop_messages_live_0photo.ts
// ffmpeg -i air_drop_messages_live_photo.mov air_drop_messages_live_photo.ts
$xexec=($cmdpref . $i1 . " " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio1capture.ts");
$xexec.="; " . ($cmdpref . $i2 . " " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio2capture.ts");
// ffmpeg -i "concat:air_drop_messages_live_0photo.ts|air_drop_messages_live_photo.ts" -c copy air_drop_messages_live_photo_more.ts
$xexec.="; " . ($cmdpref . " -i \"concat:" . dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio1capture.ts|" . dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio2capture.ts\" -c copy " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio_capture.ts");
// ffmpeg -i air_drop_messages_live_photo_more.ts air_drop_messages_live_photo_more.mp4
//file_put_contents("x.x", $xexec);
exec($xexec);
if (file_exists(dirname(__FILE__) . DIRECTORY_SEPARATOR . "audiocapture." . $oext)) {
unlink(dirname(__FILE__) . DIRECTORY_SEPARATOR . "audiocapture." . $oext);
}
exec($cmdpref . " -i " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "audio_capture.ts " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "audiocapture." . $oext);
} else { // eg. ffmpeg -i video.mp4 -i audio.wav -c copy output.mkv
//file_put_contents("x.x", $cmdpref . $i1 . $i2 . $interimname . $interimext . "\n\n\n" . trim(substr($outputname,1) . $oext));
exec($cmdpref . $i1 . $i2 . $interimname . $interimext);
if (file_exists(dirname(__FILE__) . DIRECTORY_SEPARATOR . "audiocapture." . $oext)) {
unlink(dirname(__FILE__) . DIRECTORY_SEPARATOR . "audiocapture." . $oext);
}
exec(trim(substr($outputname,1) . $oext));
}
}
echo "<html><body onload=\" parent.document.getElementById('audioname').value='audiocapture." . $oext . "'; parent.document.getElementById('result').innerHTML='data:" . $omimetype . ";base64," . base64_encode(file_get_contents(dirname(__FILE__) . DIRECTORY_SEPARATOR . "audiocapture." . $oext)) . "'; if (('" . $omimetype . "').indexOf('video/') == 0 && '" . $actc . "' != '++' && parent.document.getElementById('vsource')) { var xaud=parent.document.getElementById('dvaudio'); if (xaud) { xaud.innerHTML=''; } var auds=parent.document.getElementsByTagName('audio'); for (var iauds=0; iauds<auds.length; iauds++) { auds[iauds].style.display='none'; } if (1 == 1) { var vsi=parent.document.getElementById('vsource').src; parent.document.getElementById('topleftx').innerHTML=parent.document.getElementById('topleftx').innerHTML.replace(vsi, 'data:" . $omimetype . ";base64," . base64_encode(file_get_contents(dirname(__FILE__) . DIRECTORY_SEPARATOR . "audiocapture." . $oext)) . "'); } else { parent.document.getElementById('vsource').value='data:" . $omimetype . ";base64," . base64_encode(file_get_contents(dirname(__FILE__) . DIRECTORY_SEPARATOR . "audiocapture." . $oext)) . "'; } } else { parent.document.getElementById('topleftx').innerHTML='<br><div id=after>" . "<" . explode('/',$omimetype)[0] . "' + parent.cvis + ' id=thataudio controls autoplay><source id=vsource type=" . $omimetype . " src=" . "data:" . $omimetype . ";base64," . base64_encode(file_get_contents(dirname(__FILE__) . DIRECTORY_SEPARATOR . "audiocapture." . $oext)) . "></source></" . explode('/',$omimetype)[0] . ">" . "</div>'; } \"></body></html>";
exit;
}
?>
We used an image frame from today’s tutorial picture‘s featured video when we presented Apple Pages Word Processor Primer Tutorial (as you might recall), that video taken with an iPhone’s Camera (in Video mode) mobile application not containing any meaningful audio content. That tutorial picture shows a user created video (with an equal length voiceover audio) derived via …
- user local file browses for the original video (with no soundtrack)
- user clicks Play
- user local file browses for the voiceover audio
- user clicks Play
- user selects [V+A] 🗣 (as below)
- getting “ffmpeg” to do the hard work … then …
- playing new video with soundtrack (but iPhone orientation matters resulted in upside down result)
- user selects [V+A] 🗣 +180 (as below)
- existant HTML video element is tweaked … so as …
- playing new video with soundtrack (is the right way up now … and email shareable)
So, today, we use this as a starting scenario to add to our new (showing if ffmpeg is installed) …
The “Voiceover Ideas” web application …
- the changed macos_say_record.php … which also …
- calls the HTML/Javascript the changed client_browsing.htm child web application
Pretty exciting possibilities here, making the download of this to a suitable local web server (eg. MAMP) a great idea for you to consider, and try out?!
Previous relevant Media Mix Play Audio Video Mix Emoji Tutorial is shown below.
The new word in the blog posting title today (relative to yesterday’s Media Mix Play Audio Video Mix Share Tutorial and before) is …
- emoji … but we could easily have picked word(s) like …
- aesthetics
- CSS
- styling
- internationalization (phase 2)
- email creation user control
- “swish”ness (as far as we go on this, that is)
- bits and pieces
- “pretty it up”
… representing, for us, that decision we make near the end of a project about whether we go to some effort to make our current web application more aesthetically pleasing. We decided “yes” on this current “Voiceover Ideas” one. And when we start such a work day, we anticipate a day of CSS (styling) discovery, and this is true for today’s work, but it is remarkable how in achieving that, sometimes involving decisions that are “pixel perfect”, Javascript and PHP get involved anyway. For Javascript, that is because Javascript DOM can do just about anything CSS can do. For PHP it can write out the CSS and/or the Javascript so it gets the first go at the “trough”, that is.
In this phase of our work we are big fans of emojis regarding their …
- “text meets image” talents … filling in for …
- “graphically challenged” webpage coders … but at the same (and more serious) time …
- adds to the “internationalization” (feeling and understanding) nature of your web applications … and is …
- free … yay!!!!!
Today, we include three instances of …
- our inhouse “span twin” …
- emoji …
- dynamically animated …
- content (and/or clickable “button”) controlled by Javascript (as far as animation goes) …
function throbbingspans() {
var isps, jsps;
if (tgsps.length == 0) {
var sps=document.getElementsByTagName('span');
for (isps=0; isps<sps.length; isps++) {
if (('' + sps[isps].style.opacity) != '') {
if (eval('' + sps[isps].style.opacity) < 1.0) {
tgsps.push(sps[isps]);
tgspsop.push(eval('' + sps[isps].style.opacity));
tgspsopwhat.push(eval('0.10'));
}
}
}
}
if (tgsps.length != 0) {
for (jsps=0; jsps<tgsps.length; jsps+=2) {
if (tgspsop[jsps] > 0.12 && tgspsop[jsps] < 0.88 && tgspsop[1 + jsps] > 0.12 && tgspsop[1 + jsps] < 0.88) { // && tgspsop[jsps] >= tgspsop[1 + jsps]) {
tgspsop[jsps]+=tgspsopwhat[jsps];
tgspsop[1 + jsps]-=tgspsopwhat[1 + jsps];
tgsps[jsps].style.opacity='' + tgspsop[jsps];
tgsps[1 + jsps].style.opacity='' + tgspsop[1 + jsps];
} else if (tgspsop[jsps] > 0.12 && tgspsop[jsps] < 0.88 && tgspsop[1 + jsps] > 0.12 && tgspsop[1 + jsps] < 0.88) { // && tgspsop[jsps] <= tgspsop[1 + jsps]) {
tgspsop[jsps]-=tgspsopwhat[jsps];
tgspsop[1 + jsps]+=tgspsopwhat[1 + jsps];
tgsps[jsps].style.opacity='' + tgspsop[jsps];
tgsps[1 + jsps].style.opacity='' + tgspsop[1 + jsps];
} else if (tgspsop[jsps] > 0.88) {
tgspsop[jsps]-=0.1;
tgspsop[1 + jsps]+=0.1;
tgsps[jsps].style.opacity='' + tgspsop[jsps];
tgsps[1 + jsps].style.opacity='' + tgspsop[1 + jsps];
tgspsopwhat[jsps]=-tgspsopwhat[jsps];
tgspsopwhat[1 + jsps]=-tgspsopwhat[1 + jsps];
} else if (tgspsop[1 + jsps] > 0.88) {
tgspsop[jsps]+=0.1;
tgspsop[1 + jsps]-=0.1;
tgsps[jsps].style.opacity='' + tgspsop[jsps];
tgsps[1 + jsps].style.opacity='' + tgspsop[1 + jsps];
tgspsopwhat[jsps]=-tgspsopwhat[jsps];
tgspsopwhat[1 + jsps]=-tgspsopwhat[1 + jsps];
} else if (tgspsop[1 + jsps] < 0.12) {
tgspsop[jsps]-=0.1;
tgspsop[1 + jsps]+=0.1;
tgsps[jsps].style.opacity='' + tgspsop[jsps];
tgsps[1 + jsps].style.opacity='' + tgspsop[1 + jsps];
tgspsopwhat[jsps]=-tgspsopwhat[jsps];
tgspsopwhat[1 + jsps]=-tgspsopwhat[1 + jsps];
} else if (tgspsop[jsps] < 0.12) {
tgspsop[jsps]+=0.1;
tgspsop[1 + jsps]-=0.1;
tgsps[jsps].style.opacity='' + tgspsop[jsps];
tgsps[1 + jsps].style.opacity='' + tgspsop[1 + jsps];
tgspsopwhat[jsps]=-tgspsopwhat[jsps];
tgspsopwhat[1 + jsps]=-tgspsopwhat[1 + jsps];
}
}
setTimeout(throbbingspans, 900);
}
}
… and you can read more about “animated emojis” at Emoji Circuit Quiz Animated Emoji Tutorial
Flag emojis are used to gain more notice for our language dropdown and you can read more about flag emojis at Daylight Saving Time Emoji Country Flag Dropdown Tutorial.
We’ve improved the aesthetics of the “local browsing” interface by asking of the child web application to add to its document.body onload event logic …
if (window.parent != window) {
document.body.style.backgroundColor='transparent';
document.getElementById('files').style.marginTop='-10px';
document.getElementById('files').style.marginLeft='-12px';
document.getElementById('files').style.backgroundColor='#d7d7d7';
document.getElementById('distyle').innerHTML='<style> input { -webkit-appearance: border-bevel !important; border: 0 !important; } </style>'; // thanks to https://forum.webflow.com/t/disable-ios-safari-round-corners-on-form-elements/591
}
… while at the parent we change the aesthetics of the nesting of that child as per …
<div style='display:inline-block;width:96px;height:30px;overflow:hidden;vertical-align:text-bottom;'><iframe frameborder=0 id=cbi data-style='border-top:1px solid black;border-bottom:1px solid black;border-left:2px solid yellow;border-right:1px solid yellow;' style='width:173px;height:228px;margin-top:-194px;' onmouseover="vsres=document.getElementById('result').innerHTML; document.getElementById('result').style.cursor=fvsres('progress');" src='HTMLCSS/client_browsing.htm?d=" . rand(0,18765432) . "'></iframe></div>
For macOS localhost (eg. MAMP) users who have been downloading the PHP and HTML code we allow a user using the email functionality a mechanism (via them appending spaces to their emailee Javascript prompt answer) to say that it would be better to …
- send the emailee an HTML Attachment Email … rather than the default …
- send the emailee an Inline HTML Email … allowing the user to forsake the latter’s “cuteness” for the former’s additional chance to be accepted by more email client applications out there … which at the PHP’s email helper side looks like …
<?php
$smt="";
if (isset($_GET['sliceminusten'])) { $smt=' (' . str_replace(" ","+",urldecode($_GET['sliceminusten'])) . ')'; }
$honesmt="Paste to lightgreen here (already copied from lightgreen there (but recopy and repaste yourself if last characters" . $smt . " do not match) and click yellow button to Email off this Audio player ...";
if (strlen($smt) == 13 && strpos(str_replace("+"," ",('' . urldecode($_GET['to']))),"@") !== false && str_replace("+"," ",('' . urldecode($_GET['subj']))) != '') {
$inlineis="<input type=hidden name=inline value=''></input>";
if (isset($_GET['attachment']) || isset($_POST['attachment'])) { $inlineis=""; }
echo "<html><head><script type='text/javascript'>
var smt=('" . $smt . "').substring(2).substring(0,10), smts='';
function onsm() {
var wpr=null;
var wp=window.parent;
if (wp) { wpr=parent.document.getElementById('result'); }
if ((window.opener && window.opener !== window) || (wp && wpr)) {
if (5 == 5) { // window.opener.document.getElementById('result')) {
document.getElementById('divplace').innerHTML='Email sent' + smts + '.';
return true;
} else {
document.getElementById('divplace').innerHTML='Other green textbox not detected.';
return false;
}
} else {
document.getElementById('divplace').innerHTML='Not a popup window.';
return false;
}
}
function fixta() {
if (document.getElementById('taready').value.indexOf('#') == -1 && ((document.getElementById('taready').value.indexOf('data:audio/') == 0 || document.getElementById('taready').value.indexOf('data:video/') == 0) || document.getElementById('taready').value == '')) {
if (document.getElementById('taready').value == '' || (' ' + document.getElementById('taready').value).slice(-10) == smt) {
if (document.getElementById('taready').value != '') {
var midbit=document.getElementById('taready').value.split('data:')[1].split(';')[0] + ' src=' + \"'\";
document.getElementById('taready').value='<body><' + midbit.substring(0,5) + ' id=thisaudio controls><source type=' + midbit + document.getElementById('taready').value.replace(/\ /g,'+') + \"'\" + '></source></' + midbit.substring(0,5) + '></body>';
} else {
document.getElementById('taready').value='<body><p></p></body>';
smts=' with the subject only';
}
return true;
} else {
document.getElementById('divplace').innerHTML='Copy failed because paste does not match copy.';
return false;
}
} else {
document.getElementById('divplace').innerHTML='Incorrect data';
return false;
}
}
</script></head><body onload=\"document.getElementById('taready').focus(); if (wpr) { document.getElementById('status').innerHTML='Copy and Paste Done Below ...'; } \"><h1 id=status>" . $honesmt . "</h1>
<form target=ifplace onsubmit=\"if (fixta()) { return onsm(); } else { return false; }\" action=./emailhtml.php method=POST>
" . $inlineis . "
To: <input style=width:80%; type=text name=to value='" . str_replace("+"," ",urldecode($_GET['to'])) . "'></input><br>
Subject: <input style=width:80%; type=text name=subj value='" . str_replace("+"," ",urldecode($_GET['subj'])) . "'></input><br>
<textarea style=width:100%;background-color:lightgreen; cols=80 rows=10 name=tdhuhta id=taready></textarea><br><br>
<input id=sub type=submit style=background-color:yellow; value='Email'></input></form><br>
<iframe style=display:none; name=ifplace id=ifplace src=./emailhtml.php></iframe>
<div id=divplace></div>
</body></html>";
} else {
echo "<html><body><p>Incorrect usage.</p></body></html>";
}
exit;
?>
Also, today, quite a bit of tweaking of our usual CSS “favoured tweakers” (on top of first ever “text-decoration-color:transparent;” and “-webkit-appearance: border-bevel;” and “vertical-align: text-bottom;”) such as …
- background-color
- background:[linearGradient1,]URL([backgroundImageURL1),[linearGradient2,]URL([backgroundImageURL2) // for the Flash Player link background
- margin and/or padding
- width and/or height
- border and/or border-radius
- color
… we’ll leave you to explore among the workings of the “Voiceover Ideas” web application …
- the changed macos_say_record.php … which also …
- calls the HTML/Javascript the changed client_browsing.htm child web application to handle this HTML input capture usage
Previous relevant Media Mix Play Audio Video Mix Share Tutorial is shown below.
Yesterday’s Media Mix Play Audio Video Mix Tutorial mixed things up okay but kept its business to itself, and hereabouts we like to share … so …
- we created an interim 📧 email emoji button (📧) to snapshot one of these “mixed media user creations” so that you can share your work as an email HTML file attachment downloadable by emailee (given data that isn’t too big, that is) … in a favoured Ajax/FormData (floating in midair kind of) way …
if (document.getElementById('topleftx')) { // see the "textarea" discussion below as well
zhr = new XMLHttpRequest();
zform=new FormData();
zform.append('to', tois);
if (altsubject != '') {
zform.append('subj', altsubject);
} else {
zform.append('subj', 'My Media Mix ... at [date] ...');
}
zform.append('tdhuhta', encodeURIComponent('<html><body>' + document.getElementById('topleftx').outerHTML + '</body></html>'));
zhr.open('post', '//www.rjmprogramming.com.au/HTMLCSS/emailhtml.php', true);
zhr.onreadystatechange = showStuff; // not much happens here ( just usually alert('Email sent.'); )
zhr.send(zform);
}
… and along the way to doing this realized we also needed “tweaks” … - allow for “No Words” as an option for slideshow annotation(s)
- allow the user to pick a mode for “mixed media” involving audio elements (via a new select “dropdown” element) …
- separate audio element at bottom of any background imagery
- preserve the aspect ratio of background imagery (and perhaps causing overlap of content in the mixed media)
Another interesting thing happened here, at least with the Safari web browser. Supposing you have a “td” (id=topleft) (HTML table) cell with a nested “textarea” and that “textarea” (id=thewords) contains text (or is blank, actually), and there comes a time when you want to place HTML below the uppermost “textarea” (id=thewords), we found we needed to do the non-intuitive codelines below (only while HTML div id=topleftx was non-existant but no bother when from then on we are updating just HTML div id=topleftx) …
var waswords='', waswordsih='';
waswordsih=document.getElementById('thewords').innerHTML;
waswords=document.getElementById('thewords').value;
document.getElementById('topleft').innerHTML+='<div id=topleftx><br><div id=after>' + lastasaved + '</div></div>';
document.getElementById('thewords').innerHTML=waswordsih;
document.getElementById('thewords').value=waswords;
… otherwise the “textarea” (id=thewords) could have been changed from the value it had before the “td” (id=topleft) appendages are applied, that is … curious, huh?! Have a feeling the nub of the issue lies with the “textarea”‘s interesting interplay between both its innerHTML and value properties. Most of the time this is a joy. PHP or passed arguments in Javascript (or its document.write) can have a field day initializing textarea elements via their innerHTML (magically filling in its value, as you next look at this!) Of course this is great design, allowing line feeds to be handled in a relatively intuitive way, and we need HTML elements that “think vertically” like the “textarea” element. So, please, don’t take our Kodachrometextarea away!
Today’s work was all with a changed macos_say_record.php live run link.
Previous relevant Media Mix Play Audio Video Mix Tutorial is shown below.
On top of yesterday’s Media Mix Play Animated GIF Tutorial we want to consolidate, today, the code response to …
- input type=file property multiple …
<input type=file accept="video/*,audio/*" capture multiple></input>
… facilitating attempts at synchronizations of audio to audio (the inaccuracy for us leading to interesting “reverb” effects if you play the same audio twice, for example) or audio to video or audio to animated GIF (or image) or video to animated GIF (or image) … as well as … - add into the “modus operandi” mix a way for the user to define media sources via a media URL in a textbox … calling on the recursive PHP code snippet (largely concerned with the file extension relationship to mime types in data URIs) …
$types = ["audio/x-m4r","audio/wav","audio/x-wav","audio/x-pn-realaudio","audio/x-mpegurl","audio/x-aiff","audio/mpeg","audio/mid",
"audio/basic","audio/ogg","video/x-sgi-movie","video/x-msvideo","video/quicktime","audio/mp3","video/mp4","video/mpeg",
"video/x-la-asf","video/ogg","video/webm","audio/mp4", "image/jpeg", "image/jpeg", "image/png", "image/gif", "image/bmp", "image/tif",
"text/html", "text/html", "text/html", "text/javascript", "text/css", "text/plain", "text/xml", "text/csv",
"application/vnd.ms-word", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/x-php", "application/pdf",
"application/vnd.openxmlformats-officedocument.presentationml.presentation", "application/vnd.ms-powerpoint",
"application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"];
$exts = [".m4r",".wav",".wav",".ram",".m3u",".aiff",".mp3",".rmi",
".snd",".ogg",".movie",".avi",".mov",".mp3",".m4v",".mpeg",
".lsx",".ogv",".webm",".m4a", ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".tif",
".htm", ".html", ".htmls", ".js", ".css", ".txt", ".xml", ".csv",
".doc", ".docx", ".php", ".pdf",
".pptx", ".ppt",
".xls", ".xlsx"];
if (isset($_GET['getme'])) {
$om="image/gif";
$ugg=explode("?",explode("#",str_replace("+"," ",urldecode($_GET['getme'])))[0])[0];
$qourext=explode(".",$ugg)[-1 + sizeof(explode(".",$ugg))];
for ($xib=0; $xib<sizeof($exts); $xib++) {
if (strtolower("." . $qourext) == strtolower($exts[$xib])) $om=$types[$xib];
}
echo "<html><body onload=\"parent.document.getElementById('urli').value='';\"><p>data:" . $om . ";base64," . base64_encode(file_get_contents(str_replace("+"," ",urldecode($_GET['getme'])))) . "</p></body></html>";
exit;
}
- add a bit of CSS style=cursor:progress; as a way to indicate to the user that media processing is proceeding
To make these changes to today’s live run link, the same files as for yesterday changed as per …
- we changed macos_say_record.php … which also …
- calls the HTML/Javascript the changed client_browsing.htm child web application to handle this HTML input capture usage … which in turn …
- calls recently changed tutorial_to_animated_gif.php animated GIF creator
Previous relevant Media Mix Play Animated GIF Tutorial is shown below.
We come at progress on top of that of yesterday’s Media Mix Play Tutorial from three quite different ideas today …
- the first one is one you the user who has not downlaoded the code down to a local web server is not going to confront, but we discovered, and that is that data-URI animated GIF creation off a local browse could be quite slow, but with a local web server, many of the files selected could be expressed as (exemplified for our MAMP local web server) …
HTTP://localhost:8888/localDir/localFileName.jpg
… as we mainly browse off the Document Root folder anyway … but the File API does not help out with paths and we resort to Linux/macOS “find” command and the File API supplied file size and short file name …
<?php
if (isset($_GET['vsfs']) && isset($_GET['vsfn']) && isset($_GET['vsfi']) && isset($_GET['vsfu'])) {
$docroot=dirname(__FILE__);
if (file_exists("lookup_" . str_replace(")","",str_replace("(","",str_replace("+"," ",urldecode($_GET['vsfn'])))))) {
unlink("lookup_" . str_replace(")","",str_replace("(","",str_replace("+"," ",urldecode($_GET['vsfn'])))));
}
exec("find " . $_SERVER['DOCUMENT_ROOT'] . " -name '" . str_replace(")","*",str_replace("(","*",str_replace("+"," ",urldecode($_GET['vsfn'])))) . "' -exec ls -l {} \\; 2> /dev/null > lookup_" . str_replace(")","",str_replace("(","",str_replace("+"," ",urldecode($_GET['vsfn'])))));
if (file_exists("lookup_" . str_replace(")","",str_replace("(","",str_replace("+"," ",urldecode($_GET['vsfn'])))))) {
$infois=file_get_contents(("lookup_" . str_replace(")","",str_replace("(","",str_replace("+"," ",urldecode($_GET['vsfn']))))));
$lines=explode("\n", $infois);
for ($il=0; $il<sizeof($lines); $il++) {
$lines[$il]=str_replace("\r","",$lines[$il]);
if (strpos($lines[$il], " " . $_GET['vsfs'] . " ") !== false) {
//file_put_contents("look_" . str_replace(")","",str_replace("(","",str_replace("+"," ",urldecode($_GET['vsfn'])))), "thisplace=" . $docroot . "\n" . "rootplace=" . $_SERVER['DOCUMENT_ROOT'] . "\n" . "origplace=" . str_replace("+"," ",urldecode($_GET['vsfu'])) . "\n" . "foundplace=" . explode(" ", $lines[$il])[-1 + sizeof( explode(" ", $lines[$il]))] . "\n" . '<html><body onload=" parent.document.getElementById(' . "'" . str_replace("+"," ",urldecode($_GET['vsfi'])) . "'" . ").value='" . str_replace($_SERVER['DOCUMENT_ROOT'],explode("localhost",str_replace("+"," ",urldecode($_GET['vsfu'])))[0] . "localhost" . explode("/",explode("localhost",str_replace("+"," ",urldecode($_GET['vsfu'])))[1])[0] . "",explode(" ", $lines[$il])[-1 + sizeof( explode(" ", $lines[$il]))]) . "'; " . '"></body></html>');
if (strpos(explode(" ", $lines[$il])[-1 + sizeof( explode(" ", $lines[$il]))], $_SERVER['DOCUMENT_ROOT']) !== false) {
echo '<html><body onload=" parent.document.getElementById(' . "'" . str_replace("+"," ",urldecode($_GET['vsfi'])) . "'" . ").value='" . str_replace($_SERVER['DOCUMENT_ROOT'],explode("localhost",str_replace("+"," ",urldecode($_GET['vsfu'])))[0] . "localhost" . explode("/",explode("localhost",str_replace("+"," ",urldecode($_GET['vsfu'])))[1])[0] . "",explode(" ", $lines[$il])[-1 + sizeof( explode(" ", $lines[$il]))]) . "'; " . '"></body></html>';
}
unlink("lookup_" . str_replace(")","",str_replace("(","",str_replace("+"," ",urldecode($_GET['vsfn'])))));
} else {
unlink("lookup_" . str_replace(")","",str_replace("(","",str_replace("+"," ",urldecode($_GET['vsfn'])))));
}
}
}
exit;
}
?>
… to match in PHP (the result being a lot faster, and a big relief for our unit testing) … - we set up animated GIF “watermark” type annotating of slides via location.hash retention and recall across web applications … eg. …
function dolhsh(force) {
if (('' + window.location.hash).replace('#','') != '') {
document.getElementById('lhsh').innerHTML=window.location.hash.substring(1);
document.getElementById('cbi').src=document.getElementById('cbi').src + '0' + window.location.hash.replace(/\ /g,'%20');
} else if (document.getElementById('thewords').value != '' && (force != 0 || document.getElementById('cbi').src.indexOf('#') == -1)) {
var hlines=document.getElementById('thewords').value.split(String.fromCharCode(10));
var hsuff='';
for (var ihsuff=0; ihsuff<hlines.length; ihsuff++) {
hsuff+='#' + encodeURIComponent(hlines[ihsuff]);
}
if (hsuff != '') { document.getElementById('cbi').src=document.getElementById('cbi').src.split('#')[0].replace('?','?gfn=" . $giffilename . "&') + '0' + hsuff; }
}
}
… for onload and textarea onblur event purposes … meaning the animated GIF created can hashtag (#) delimit such annotations for each or any animated GIF image “slides” - as part of our new “media mix” “foreground audio or video with a background image” arrangements we can play we can …
- dynamically create an animated GIF from its locally browsed “image slide” parts
- we can give a meaning to …
<input type=file accept="video/*,audio/*" capture multiple></input>
… we left out of the discussion from below … and no doubt we’ll find more “meanings” for this property as we progress in day(s) to come
To make these changes to today’s live run link …
- we changed macos_say_record.php … which also …
- calls the HTML/Javascript the changed client_browsing.htm child web application to handle this HTML input capture usage … which in turn …
- calls recently changed tutorial_to_animated_gif.php animated GIF creator
Previous relevant Media Mix Play Tutorial is shown below.
Guess what you’d call what we’ve been keen on lately with …
foreground audio or video with a background image (perhaps an animated GIF)
… a “media mix”. Today, after progress of yesterday’s Haiku Multimedia via Media Record Capture Tutorial, we wanted to provide a “play” of these “media mix” as a possibility for the user doing “local browsing” selection of audio or video file first, followed by “local browsing” selection of image file.
We turn on the audio or video properties …
- autoplay
- loop
… though they will certainly not get applied on all platforms. The “autoplay” we are keen on for media synchronization purposes (and possibilities). The “loop” property may be good for a similar reason especially if the image is an animated GIF whose cycle has the same duration as the audio or video content duration, our “dream scenario” for your best “voiceover” situation!
To make these changes today’s live run link with our focus …
- is a changed macos_say_record.php … which also …
- calls the HTML/Javascript the changed client_browsing.htm child web application to handle this HTML input capture usage
Previous relevant Haiku Multimedia via Media Record Capture Tutorial is shown below.
Let’s semi-drop the “macOS” on our “media capture” functionality we’re developing currently, because over the last two days it has jumped out of this restrictive thought pattern, either through the “voiceover” idea of …
- non-mobile Adobe Flash Player plugin audio recording (Speech to Audio) … as well as …
- input type=file capture mobile browsing and/or creating (iOS video) and non-mobile browsing of media with an audio (Speech to Audio) capability … on top of that original …
- macOS or Mac OS X “say” command line command Text to Audio original “voiceover” idea
… onto yesterday’s MacOS and Other Mobile Media Record Tutorial you can join the story with, below.
And way back at Mac OS X Text to English Speech Primer Tutorial we can revisit the “synchronicity of media” ideas we are so keen about. Our conduit idea to get us there has been a revisit of the Haiku creation work of Haiku Animated Gif Creator Tutorial where we allow either a …
- audio data-URI … or …
- video data-URI
… form the “foreground” for an animated GIF (Haiku wording) “background” easy to show the user creating it, and shareable via an email HTML attachment approach, on some email clients (eg. Gmail webmail).
Along the way we repurposed the “dishevelment” of yesterday into more programmatically restrictive web application functionality to come up with …
- today’s changed haiku_animated_gif.html‘s Haiku creation and sharing web application live run link’s Ajax/FormData email sending …
function waitforalatr() { // features Ajax/FormData techniques to send email via inhouse PHP email helper
if (document.getElementById('iurl').value == '') {
setTimeout(waitforalatr, 2000);
} else {
alatr();
altsubject='My Haiku ...';
var tois=prompt('Who do you want to email to? Optionally hashtag (#) separate your own personal subject line to the email (eg. theemail@theemailplace.com#Hello there, it is moi.)', '');
if (tois == null) { tois=''; }
if (tois.indexOf('@') != -1) {
var alts=tois.split('#');
if (alts.length > 1) { altsubject=alts[1]; tois=alts[0]; }
//var text=document.getElementById('result').innerHTML;
//document.getElementById('ifem').innerHTML="<iframe onload=checkz(this); src='//www.rjmprogramming.com.au/HTMLCSS/emailhtml.php?to=" + encodeURIComponent(tois) + '&subj=' + thisencodeURIComponent(altsubject) + ' ... ') + '&sliceminusten=' + encodeURIComponent(text.slice(-10)) + "' style=width:500px;height:600px;></iframe>";
var zhr = new XMLHttpRequest();
var zform=new FormData();
//zform.append('inline', '');
zform.append('to', tois);
zform.append('subj', altsubject + ' ... ');
zform.append('tdhuhta', '<html><body>' + document.getElementById('bpalette').innerHTML.replace('<audio ','<audio loop ').replace('<video ','<video loop ').replace('position:absolute;','').replace('left:','margin-left:0.').replace('top:','margin-top:0.') + '</body></html>');
zhr.open('post', '//www.rjmprogramming.com.au/HTMLCSS/emailhtml.php', true);
zhr.send(zform);
document.getElementById('iurl').value='';
alert('Email sent with downloadable HTML attachment.');
}
}
}
… workings … - calls on a changed macos_say_record.php live run link … and also …
- calls the HTML/Javascript the changed client_browsing.htm child web application to handle this HTML input capture usage and interfacing to (now various) parent.window scenarios … along the way also involving …
- recently changed tutorial_to_animated_gif.php animated GIF creator … and …
- Inhouse HTML Email helper/creator’s key interfacing code now goes …
<?php
$smt="";
if (isset($_GET['sliceminusten'])) { $smt=' (' . str_replace(" ","+",urldecode($_GET['sliceminusten'])) . ')'; }
$honesmt="Paste to lightgreen here (already copied from lightgreen there (but recopy and repaste yourself if last characters" . $smt . " do not match) and click yellow button to Email off this Audio player ...";
if (strlen($smt) == 13 && strpos(str_replace("+"," ",('' . urldecode($_GET['to']))),"@") !== false && str_replace("+"," ",('' . urldecode($_GET['subj']))) != '') {
echo "<html><head><script type='text/javascript'>
var smt=('" . $smt . "').substring(2).substring(0,10), smts='';
function onsm() {
var wpr=null;
var wp=window.parent;
if (wp) { wpr=parent.document.getElementById('result'); }
if ((window.opener && window.opener !== window) || (wp && wpr)) {
if (5 == 5) { // window.opener.document.getElementById('result')) {
document.getElementById('divplace').innerHTML='Email sent' + smts + '.';
//alert(window.opener.document.getElementById('result').slice(-10) + ' vs ' + smt);
return true;
} else {
document.getElementById('divplace').innerHTML='Other green textbox not detected.';
return false;
}
} else {
document.getElementById('divplace').innerHTML='Not a popup window.';
return false;
}
}
function fixta() {
if (document.getElementById('taready').value.indexOf('#') == -1 && ((document.getElementById('taready').value.indexOf('data:audio/') == 0 || document.getElementById('taready').value.indexOf('data:video/') == 0) || document.getElementById('taready').value == '')) {
if (document.getElementById('taready').value == '' || (' ' + document.getElementById('taready').value).slice(-10) == smt) {
if (document.getElementById('taready').value != '') {
var midbit=document.getElementById('taready').value.split('data:')[1].split(';')[0] + ' src=' + \"'\";
document.getElementById('taready').value='<body><' + midbit.substring(0,5) + ' id=thisaudio controls><source type=' + midbit + document.getElementById('taready').value.replace(/\ /g,'+') + \"'\" + '></source></' + midbit.substring(0,5) + '></body>';
} else {
document.getElementById('taready').value='<body><p></p></body>';
smts=' with the subject only';
}
return true;
} else {
//document.getElementById('divplace').innerHTML='Copy failed because ' + (' ' + document.getElementById('taready').value).slice(-10) + ' paste does not match ' + smt + ' copy.';
document.getElementById('divplace').innerHTML='Copy failed because paste does not match copy.';
return false;
}
} else {
document.getElementById('divplace').innerHTML='Incorrect data';
return false;
}
}
</script></head><body onload=\"document.getElementById('taready').focus(); if (wpr) { document.getElementById('status').innerHTML='Copy and Paste Done Below ...'; } \"><h1 id=status>" . $honesmt . "</h1>
<form target=ifplace onsubmit=\"if (fixta()) { return onsm(); } else { return false; }\" action=./emailhtml.php method=POST>
<input type=hidden name=inline value=''></input>
To: <input style=width:80%; type=text name=to value='" . str_replace("+"," ",urldecode($_GET['to'])) . "'></input><br>
Subject: <input style=width:80%; type=text name=subj value='" . str_replace("+"," ",urldecode($_GET['subj'])) . "'></input><br>
<textarea style=width:100%;background-color:lightgreen; cols=80 rows=10 name=tdhuhta id=taready></textarea><br><br>
<input id=sub type=submit style=background-color:yellow; value='Email'></input></form><br>
<iframe style=display:none; name=ifplace id=ifplace src=./emailhtml.php></iframe>
<div id=divplace></div>
</body></html>";
} else {
echo "<html><body><p>Incorrect usage.</p></body></html>";
}
exit;
?>
… to pull all this together in that tighter way (so long Colombo) for you to try yourself.
Previous relevant MacOS and Other Mobile Media Record Tutorial is shown below.
We’re letting a little “dishevelment” continue with today’s work on top of yesterday’s MacOS Speech to Flash Player Audio Record Tutorial.
The reason (to our mind) is that involving mobile functionality into a media web application’s sphere of influence is a big step with more than the usual time needed for testing … well, that’s my excuse, anyway. The major reason for this is that the …
<input type=file accept="video/*,audio/*" capture></input>
… is an incredible recent development (allowing dynamic media creation, with “retake” possibilities, all because of that one “capture” property above) separating the mobile (smart device) platforms from the previous laptop media capture capabilities, and at least doubles the amount of unit testing needed to prove the code workings.
And so, for a little while, some users will be annoyed that they see web application functionality not meant for their platform characteristics.
Sometimes “dishevelment” can work, too, or “stewing for a day”, because it turns out a piece of functionality you thought to be impossible with a particular platform amazingly becomes possible the next day?! Hence the adage … “mulling is amazing”!
Code wise …
- calls (just like Animated GIF Audio or Video Foreground Tutorial did) the HTML/Javascript the changed client_browsing.htm child web application to handle this HTML input capture usage and interfacing to (now various) parent.window scenarios …
- called by a changed macos_say_record.php live run link … that relies on our …
- Inhouse HTML Email helper/creator’s key interfacing code now goes …
<?php
$smt="";
if (isset($_GET['sliceminusten'])) { $smt=' (' . str_replace(" ","+",urldecode($_GET['sliceminusten'])) . ')'; }
if (strlen($smt) == 13 && strpos(str_replace("+"," ",('' . urldecode($_GET['to']))),"@") !== false && str_replace("+"," ",('' . urldecode($_GET['subj']))) != '') {
echo "<html><head><script type='text/javascript'>
var smt=('" . $smt . "').substring(2).substring(0,10), smts='';
function onsm() {
var wpr=null;
var wp=window.parent;
if (wp) { wpr=parent.document.getElementById('result'); }
if ((window.opener && window.opener !== window) || (wp && wpr)) {
if (5 == 5) { // window.opener.document.getElementById('result')) {
document.getElementById('divplace').innerHTML='Email sent' + smts + '.';
//alert(window.opener.document.getElementById('result').slice(-10) + ' vs ' + smt);
return true;
} else {
document.getElementById('divplace').innerHTML='Other green textbox not detected.';
return false;
}
} else {
document.getElementById('divplace').innerHTML='Not a popup window.';
return false;
}
}
function fixta() {
if (document.getElementById('taready').value.indexOf('#') == -1 && ((document.getElementById('taready').value.indexOf('data:audio/') == 0 || document.getElementById('taready').value.indexOf('data:video/') == 0) || document.getElementById('taready').value == '')) {
if (document.getElementById('taready').value == '' || (' ' + document.getElementById('taready').value).slice(-10) == smt) {
if (document.getElementById('taready').value != '') {
var midbit=document.getElementById('taready').value.split('data:')[1].split(';')[0] + ' src=' + \"'\";
document.getElementById('taready').value='<body><' + midbit.substring(0,5) + ' id=thisaudio controls loop><source type=' + midbit + document.getElementById('taready').value.replace(/\ /g,'+') + \"'\" + '></source></' + midbit.substring(0,5) + '></body>';
} else {
document.getElementById('taready').value='<body><p></p></body>';
smts=' with the subject only';
}
return true;
} else {
//document.getElementById('divplace').innerHTML='Copy failed because ' + (' ' + document.getElementById('taready').value).slice(-10) + ' paste does not match ' + smt + ' copy.';
document.getElementById('divplace').innerHTML='Copy failed because paste does not match copy.';
return false;
}
} else {
document.getElementById('divplace').innerHTML='Incorrect data';
return false;
}
}
</script></head><body onload=\"document.getElementById('taready').focus();\"><h1 id=status>Paste to lightgreen here (already copied from lightgreen there (but recopy and repaste yourself if last characters" . $smt . " do not match) and click yellow button to Email off this Audio player ...</h1>
<form target=ifplace onsubmit=\"if (fixta()) { return onsm(); } else { return false; }\" action=./emailhtml.php method=POST>
<input type=hidden name=inline value=''></input>
To: <input style=width:80%; type=text name=to value='" . str_replace("+"," ",urldecode($_GET['to'])) . "'></input><br>
Subject: <input style=width:80%; type=text name=subj value='" . str_replace("+"," ",urldecode($_GET['subj'])) . "'></input><br>
<textarea style=width:100%;background-color:lightgreen; cols=80 rows=10 name=tdhuhta id=taready></textarea><br><br>
<input id=sub type=submit style=background-color:yellow; value='Email'></input></form><br>
<iframe style=display:none; name=ifplace id=ifplace src=./emailhtml.php></iframe>
<div id=divplace></div>
</body></html>";
} else {
echo "<html><body><p>Incorrect usage.</p></body></html>";
}
exit;
?>
Please feel free to try it out yourself, email sharing as you go.
Previous relevant MacOS Speech to Flash Player Audio Record Tutorial is shown below.
Yesterday’s MacOS Text to Audio Share Tutorial involved …
- local web server (over macOS) text to audio (via macOS say) programmatical input source for “voiceover” aims … and today, still on …
- local web server (over macOS) (user) we have speech to audio (via Adobe Flash Player plugin) input source for “voiceover” or “dictation” or “voice memo feeling” aims
… all shareable via email. So these are two non-mobile “voiceover” ideas, and we will present a mobile idea into the future, and thereby open a public domain worthy side to the functionality, then. Rereading here, it just tweaked with us that we can offer this “public domain” aspect even today with a changed macos_say_record.php live run link here, and your Flash Player methodology could work as long as you realize it will be later we hide the inapplicable macOS “say” logics for “public domain” usage.
You’ll see in these changes more interplay among …
- popup window child windows … and
- iframe child windows that listen out for the (next) Flash Player *.wav file creation event via a recursive … HTML …
<?php
<iframe onload=checkff(this); name=checkflash id=checkflash style=display:none; src='./macos_say_record.php?audiosize=y'></iframe>
?>
…
<?php
if (isset($_GET['audiosize'])) {
// if (file_exists('HTTP://www.rjmprogramming.com.au/MarkItUp/html/audio/audio.wav')) {
if (isset($_GET['getmecontent'])) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'HTTP://www.rjmprogramming.com.au/MarkItUp/html/audio/audio.wav');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
curl_close($ch);
echo "<html><body onload=\" parent.document.getElementById('audioname').value='audiocapture.wav'; parent.document.getElementById('daudiolater').innerHTML='<audio id=thataudio controls autoplay loop><source type=audio/x-wav src=" . "data:audio/x-wav;base64," . base64_encode($output) . "></source></audio> <a style=display:inline-block;text-decoration:none;cursor:pointer; onclick=emailit(); title=Email>📧</a>';\"><p>" . strlen($output) . "</p><div>data:audio/x-wav;base64," . base64_encode($output) . "</div></body></html>";
} else {
//$context = stream_context_create(array('http' => array('header'=>'Connection: close\r\n')));
//$ct=file_get_contents('HTTP://www.rjmprogramming.com.au/MarkItUp/html/audio/audio.wav',false,$context);
//file_put_contents("x.x",strlen($ct));
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'HTTP://www.rjmprogramming.com.au/MarkItUp/html/audio/audio.wav');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
curl_close($ch);
echo "<html><body><p>" . strlen($output) . "</p><div></div></body></html>";
}
// } else {
// echo "<html><body><p>-1</p><div></div></body></html>";
// }
exit;
}
?>
… file_get_contents turning out to be so much slower than curl
Without resorting to any passwords we tighten up the interface to the PHP email helper code at the PHP email helper code end by insisting the email only be sent if the user entry into the interim textarea …
- contains no “#” characters
- starts with … data:audio/
- ends with the same 10 characters passed over to the PHP email helper code
… as per …
<?php
$smt="";
if (isset($_GET['sliceminusten'])) { $smt=' (' . str_replace(" ","+",urldecode($_GET['sliceminusten'])) . ')'; }
if (strlen($smt) == 13 && strpos(str_replace("+"," ",('' . urldecode($_GET['to']))),"@") !== false && str_replace("+"," ",('' . urldecode($_GET['subj']))) != '') {
echo "<html><head><script type='text/javascript'>
var smt=('" . $smt . "').substring(2).substring(0,10), smts='';
function onsm() {
if (window.opener && window.opener !== window) {
if (5 == 5) { // window.opener.document.getElementById('result')) {
document.getElementById('divplace').innerHTML='Email sent' + smts + '.';
//alert(window.opener.document.getElementById('result').slice(-10) + ' vs ' + smt);
return true;
} else {
document.getElementById('divplace').innerHTML='Other green textbox not detected.';
return false;
}
} else {
document.getElementById('divplace').innerHTML='Not a popup window.';
return false;
}
}
function fixta() {
if (document.getElementById('taready').value.indexOf('#') == -1 && (document.getElementById('taready').value.indexOf('data:audio/') == 0 || document.getElementById('taready').value == '')) {
if (document.getElementById('taready').value == '' || (' ' + document.getElementById('taready').value).slice(-10) == smt) {
if (document.getElementById('taready').value != '') {
var midbit=document.getElementById('taready').value.split('data:')[1].split(';')[0] + ' src=' + \"'\";
document.getElementById('taready').value='<body><audio id=thisaudio controls loop><source type=' + midbit + document.getElementById('taready').value.replace(/\ /g,'+') + \"'\" + '></source></audio></body>';
} else {
document.getElementById('taready').value='<body><p></p></body>';
smts=' with the subject only';
}
return true;
} else {
//document.getElementById('divplace').innerHTML='Copy failed because ' + (' ' + document.getElementById('taready').value).slice(-10) + ' paste does not match ' + smt + ' copy.';
document.getElementById('divplace').innerHTML='Copy failed because paste does not match copy.';
return false;
}
} else {
document.getElementById('divplace').innerHTML='Incorrect data';
return false;
}
}
</script></head><body onload=\"document.getElementById('taready').focus();\"><h1 id=status>Paste to lightgreen here (already copied from lightgreen there (but recopy and repaste yourself if last characters" . $smt . " do not match) and click yellow button to Email off this Audio player ...</h1>
<form target=ifplace onsubmit=\"if (fixta()) { return onsm(); } else { return false; }\" action=./emailhtml.php method=POST>
<input type=hidden name=inline value=''></input>
To: <input style=width:80%; type=text name=to value='" . str_replace("+"," ",urldecode($_GET['to'])) . "'></input><br>
Subject: <input style=width:80%; type=text name=subj value='" . str_replace("+"," ",urldecode($_GET['subj'])) . "'></input><br>
<textarea style=width:100%;background-color:lightgreen; cols=80 rows=10 name=tdhuhta id=taready></textarea><br><br>
<input id=sub type=submit style=background-color:yellow; value='Email'></input></form><br>
<iframe style=display:none; name=ifplace id=ifplace src=./emailhtml.php></iframe>
<div id=divplace></div>
</body></html>";
} else {
echo "<html><body><p>Incorrect usage.</p></body></html>";
}
exit;
?>
Previous relevant MacOS Text to Audio Share Tutorial is shown below.
In order to share the audio file of yesterday’s MacOS Text to Audio Internationalization Tutorial we cannot use …
- client based “a” “mailto:” link approaches because …
- the size of data is too large
- we need to be able to use HTML within Inline HTML Email if we are not happy leaving around RJM Programming web server audio files (which we are not)
… and so we need to call on …
- server (public, not local) based code (ie. PHP, for us) that can email Inline HTML Email
… and calling on that server (public, not local) based code you can choose to …
- involve CORS in an Ajax FormData call or an HTML Form method=POST … or …
- involve window.PostMessage approach (perhaps involving web server audio files that are temporary) … or, as we decided upon …
- involve popup web server “inhouse” PHP Inline HTML Email creator helper … that …
- codes allowances for the caller situation (that situation having ensured a data-URI “copy” of the audio content in in the web browser buffer ahead of the popup window appearing, all instigated via a new 📧 email emoji button (📧)) …
- sets up the PHP code …
<?php
echo "<html><head><script type='text/javascript'> function fixta() { if (document.getElementById('taready').value.indexOf('data:') == 0) { var midbit=document.getElementById('taready').value.split('data:')[1].split(';')[0] + ' src=' + \"'\"; document.getElementById('taready').value='<body><audio id=thisaudio controls loop><source type=' + midbit + document.getElementById('taready').value.replace(/\ /g,'+') + \"'\" + '></source></audio></body>'; } } </script></head><body onload=\"document.getElementById('taready').focus();\"><h1 id=status>Paste to lightgreen here (already copied from lightgreen there) and click yellow button to Email off ...</h1>
<form onsubmit='fixta(); return true;' action=./emailhtml.php method=POST>
<input type=hidden name=inline value=''></input>
<input type=hidden name=to value='" . str_replace("+"," ",urldecode($_GET['to'])) . "'></input>
<input type=hidden name=subj value='" . str_replace("+"," ",urldecode($_GET['subj'])) . "'></input>
<textarea style=width:100%;background-color:lightgreen; cols=80 rows=10 name=tdhuhta id=taready></textarea><br>
<input id=sub type=submit style=background-color:yellow; value='Email to " . str_replace("+"," ",urldecode($_GET['to'])) . " ... " . str_replace("+"," ",urldecode($_GET['subj'])) . "'></input></form>
</body></html>";
exit;
?> - awaits the user clicking an interim HTML form submit button … that …
- recalls itself and really sends the Inline HTML Email containing HTML that includes an audio tag with data-URI content
… this whole scenario only acceptable in its entirety by iOS Mail apps (but not Gmail Webmail nor macOS Mail (at least with our testing)).
Again, given the same local web server provisions as outlined on the day before yesterday, feel free to try out a changed macos_say_record.php macOS “say” PHP helper with better email sharing functionality.
Previous relevant MacOS Text to Audio Internationalization Tutorial is shown below.
Yesterday’s MacOS Text to Audio Primer Tutorial was very “English”, at least hereabouts. We think it would be good to Internationalize the “say” integration with “-v” voices in other languages to choose from.
That “Internationalization” we have Apple to thank for, because “say” documents …
$ say -v ‘?’
Alex en_US # Most people recognize me by my voice.
Alice it_IT # Salve, mi chiamo Alice e sono una voce italiana.
Alva sv_SE # Hej, jag heter Alva. Jag är en svensk röst.
Amelie fr_CA # Bonjour, je m’appelle Amelie. Je suis une voix canadienne.
Anna de_DE # Hallo, ich heiße Anna und ich bin eine deutsche Stimme.
Carmit he_IL # שלום. קוראים לי כרמית, ואני קול בשפה העברית.
Claire nl_NL # Hallo, mijn naam is Claire. Ik ben een Nederlandse stem.
Damayanti id_ID # Halo, nama saya Damayanti. Saya berbahasa Indonesia.
Daniel en_GB # Hello, my name is Daniel. I am a British-English voice.
Diego es_AR # Hola, me llamo Diego y soy una voz española.
Ellen nl_BE # Hallo, mijn naam is Ellen. Ik ben een Belgische stem.
Fiona en-scotland # Hello, my name is Fiona. I am a Scottish-English voice.
Fred en_US # I sure like being inside this fancy computer
Ioana ro_RO # Bună, mă cheamă Ioana . Sunt o voce românească.
Joana pt_PT # Olá, chamo-me Joana e dou voz ao português falado em Portugal.
Jorge es_ES # Hola, me llamo Jorge y soy una voz española.
Juan es_MX # Hola, me llamo Juan y soy una voz mexicana.
Kanya th_TH # สวัสดีค่ะ ดิฉันชื่อKanya
Karen en_AU # Hello, my name is Karen. I am an Australian-English voice.
Kate en_GB # Hello, my name is Kate. I am a British-English voice.
Kyoko ja_JP # こんにちは、私の名前はKyokoです。日本語の音声をお届けします。
Laura sk_SK # Ahoj. Volám sa Laura . Som hlas v slovenskom jazyku.
Lekha hi_IN # नमस्कार, मेरा नाम लेखा है. मैं हिन्दी में बोलने वाली आवाज़ हूँ.
Luca it_IT # Salve, mi chiamo Luca e sono una voce italiana.
Luciana pt_BR # Olá, o meu nome é Luciana e a minha voz corresponde ao português que é falado no Brasil
Maged ar_SA # مرحبًا اسمي Maged. أنا عربي من السعودية.
Mariska hu_HU # Üdvözlöm! Mariska vagyok. Én vagyok a magyar hang.
Mei-Jia zh_TW # 您好,我叫美佳。我說國語。
Melina el_GR # Γεια σας, ονομάζομαι Melina. Είμαι μια ελληνική φωνή.
Milena ru_RU # Здравствуйте, меня зовут Milena. Я – русский голос системы.
Moira en_IE # Hello, my name is Moira. I am an Irish-English voice.
Monica es_ES # Hola, me llamo Monica y soy una voz española.
Nora nb_NO # Hei, jeg heter Nora. Jeg er en norsk stemme.
Oliver en_GB # Hello, my name is Oliver. I am a British-English voice.
Paulina es_MX # Hola, me llamo Paulina y soy una voz mexicana.
Samantha en_US # Hello, my name is Samantha. I am an American-English voice.
Sara da_DK # Hej, jeg hedder Sara. Jeg er en dansk stemme.
Satu fi_FI # Hei, minun nimeni on Satu. Olen suomalainen ääni.
Serena en_GB # Hello, my name is Serena. I am a British-English voice.
Sin-ji zh_HK # 您好,我叫 Sin-ji。我講廣東話。
Tessa en_ZA # Hello, my name is Tessa. I am a South African-English voice.
Thomas fr_FR # Bonjour, je m’appelle Thomas. Je suis une voix française.
Ting-Ting zh_CN # 您好,我叫Ting-Ting。我讲中文普通话。
Tom en_US # Hello, my name is Tom. I am an American-English voice.
Veena en_IN # Hello, my name is Veena. I am an Indian-English voice.
Victoria en_US # Isn’t it nice to have a computer that will talk to you?
Xander nl_NL # Hallo, mijn naam is Xander. Ik ben een Nederlandse stem.
Yelda tr_TR # Merhaba, benim adım Yelda. Ben Türkçe bir sesim.
Yuna ko_KR # 안녕하세요. 제 이름은 Yuna입니다. 저는 한국어 음성입니다.
Yuri ru_RU # Здравствуйте, меня зовут Yuri. Я – русский голос системы.
Zosia pl_PL # Witaj. Mam na imię Zosia, jestem głosem kobiecym dla języka polskiego.
Zuzana cs_CZ # Dobrý den, jmenuji se Zuzana. Jsem český hlas.… to go on here, as a help for this level of “Internationalization”. Another “level” again would be to translate the webpage and menu wording, but we’ve decided against that here today.
So we add a language dropdown and a voice dropdown to help the user explore this Text to Audio functionality accessing a macOS or Mac OS X operating system.
Also, today, we’ve introduced “.m4a” (audio/mp4) as the default audio file extension to use with the file created via “say” “-o” switch for all but Safari, as this works better for “all but Safari” (absolutely).
Given the same local web server provisions as outlined yesterday feel free to try out a changed macos_say_record.php macOS “say” PHP helper with better Internationalization functionality, thanks in large part to the great ideas from this useful link.
Previous relevant MacOS Text to Audio Primer Tutorial is shown below.
The previous Mac OS X Text to English Speech Primer Tutorial …
- lauded the …
Text to English Speech via Mac OS X’s command line say command
- and today we write some PHP (with its very useful exec conduit to “say”) to make use of the same (macOS) “say” and its Text to Audio talents (via its “-o” switch usage)
… and it’s at times like this we wish that the RJM Programming domain’s web server had a macOS operating system. Alas, “say” is a macOS and Mac OS X application, but not a Linux one.
None the less, we integrated …
- today’s changed haiku_animated_gif.html‘s Haiku creation and sharing web application live run link’s workings (last talked about at Haiku Animated Gif Creator Tutorial) with …
- macos_say_record.php macOS “say” PHP helper
… so that if you had a MAMP local Apache/PHP/MySql web server going, and you …
- downloaded tutorial_to_animated_gif.php to same MAMP subdirectory as …
- downloaded haiku_animated_gif.html to same MAMP place (which can be the same MAMP document root place as talked about below, in which case HTTP://localhost:8888/haiku_animated_gif.html is what you’d type into the web browser address bar to try this for yourself on a macOS or Mac OS X system) … and …
- downloaded macos_say_record.php to MAMP document root (for us, equating to URL HTTP://localhost:8888/macos_say_record.php)
… then you would be in the position to see a Haiku creation scenario (where we used the Safari web browser) like with today’s tutorial picture, interesting, in our view, regarding the integration “tactics” …
- parent Haiku window opens …
- child (popup) PHP “say” helper web application … which …
- passes back to parent …
window.opener.document.getElementById('aurl').value=document.getElementById('result').value;
window.opener.atab(window.opener.document.getElementById('aurl'));
… achieving functionality we often ask HTML iframe elements achieve for our code. HTML iframe does have a role today, though. It uses a favoured “client pre-emptive iframe” approach to determine whether we even try to open that popup window above via …
- HTML …
<div id=dif></div>
- Javascript …
var mampok=false, mampprefix='';
if (document.URL.indexOf('/localhost') != -1) {
mampprefix="http://localhost" + document.URL.split('/localhost')[1].split('/')[0] + "/";
document.getElementById('dif').innerHTML="<iframe onload='oicheck(this);' style='display:none;' src='http://localhost" + document.URL.split('/localhost')[1].split('/')[0] + "/'></iframe>";
}
function oicheck(iois) {
mampok=false;
if (iois != null) {
var aconto = (iois.contentWindow || iois.contentDocument);
if (aconto != null) {
if (aconto.document) { aconto = aconto.document; }
if (aconto.body != null) {
if (aconto.body.innerHTML.toLowerCase().indexOf('>not found<') == -1 && aconto.body.innerHTML.toLowerCase().indexOf("our home page for your perusal") == -1) { mampok=true; }
}
}
}
}
// and then later when the textarea has text and its onblur event is triggered ...
if (mampok) {
if (wois) { wois.close(); wois=null; }
wois=window.open(mampprefix + "macos_say_record.php?saythis=" + encodeURIComponent(document.getElementById('myta').value),"_blank","top=460,left=400,width=700,height=400");
}
- Text to English Speech via Mac OS X’s command line say command used by PHP via exec to make say.php (which is useful as a download to a Mac OS X laptop using MAMP) which, today, does not have a live run because the web server of domain rjmprogramming.com.au is a CentOS Linux server … Linux equivalent of Mac OS X’s say? … read here
- Trying to present this brought up the usual movie production problem with iMovie overlaying the audio on top of the video (though you may want to try, and you could start reading with this link) versus QuickTime Player talent to catch both audio and video tracks (and that we ended up using), but not of the “screen goings on”, alas versus MPlayer OSX Extended which can play separately but not two tracks on top and doesn’t do any reconstituting … so …
- Improved on our inhouse Video/Audio synchronizing efforts by allowing audio_video.html supervisor (changed in this way) be able to be called to press one of its preconceived synchronization buttons onload which we do with (the newly added) Macbeth Act 1 Scene 1 … in a small celebration of the Bard … who, am thinking (in that Falstaff way), would have got a huge chuckle out of “anonymous” instead of “anon” during the Three Witches scene … we had to do something to say Happy Birthday
Previous relevant Mac OS X Text to English Speech Primer Tutorial is shown below.
We’ve got a few new ideas today …
Along the way we tried filming the MacBook Pro with the iPad to a YouTube …
… but weren’t happy with the audio quality, alas (too/two).
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.