| /******************************************************************************* |
| * Copyright (c) 2012 IBM Corporation and Others |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Kentarou FUKUDA - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.actf.ai.scripteditor.util; |
| |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.OutputStreamWriter; |
| import java.io.PrintWriter; |
| import java.util.List; |
| |
| import org.eclipse.actf.ai.internal.ui.scripteditor.event.TimerEvent; |
| import org.eclipse.actf.ai.scripteditor.data.IScriptData; |
| import org.eclipse.actf.ai.scripteditor.data.ScriptDataManager; |
| import org.eclipse.actf.util.FileUtils; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.widgets.Display; |
| |
| public class TTMLUtil { |
| |
| private static ScriptDataManager scriptDataMgr = ScriptDataManager.getInstance(); |
| |
| /** |
| * Export AudioDescription data in TTML format |
| */ |
| public static void exportTTML(String ttmlPathname, boolean warnOverwrite) { |
| exportTTML(ttmlPathname, false, null, null, null, warnOverwrite); |
| } |
| |
| /** |
| * Export AudioDescription data in TTML format and pre-recorded |
| * AudioDescription(AD) WAV files |
| */ |
| public static void exportTTMLandWAV(String ttmlPathname, String adWavDirpath, String adWavFilename, |
| String adUrlBase, boolean warnOverwrite) { |
| exportTTML(ttmlPathname, true, adWavDirpath, adWavFilename, adUrlBase, warnOverwrite); |
| } |
| |
| /** |
| * Export AudioDescription data in TTML format and pre-recorded |
| * AudioDescription(AD) WAV files |
| */ |
| private static void exportTTML(String ttmlPathname, boolean isPrerecorded, String adWavDirpath, |
| String adWavFilename, String adUrlBase, boolean warnOverwrite) { |
| PrintWriter writer = null; |
| |
| final VoicePlayerFactory voice = VoicePlayerFactory.getInstance(); |
| |
| try { |
| File file = new File(ttmlPathname); |
| |
| if (warnOverwrite && file.exists()) { |
| XMLFileMessageBox warningExistFile = new XMLFileMessageBox(XMLFileMessageBox.MB_STYLE_OVERWR, |
| ttmlPathname); |
| int ret = warningExistFile.open(); |
| if (ret != SWT.YES) |
| return; |
| } |
| |
| writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(ttmlPathname), "UTF-8")); |
| |
| String LINE_SEP = FileUtils.LINE_SEP; |
| |
| writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); |
| writer.println("<?xml-stylesheet href=\"ttml.css\" type=\"text/css\"?>"); |
| writer.println("<?access-control allow=\"*\"?>"); |
| writer.println("<tt ttp:profile='http://www.w3.org/ns/ttml/profile/dfxp-full'" + LINE_SEP |
| + " xmlns='http://www.w3.org/ns/ttml'" + LINE_SEP |
| + " xmlns:ttm='http://www.w3.org/ns/ttml#metadata'" + LINE_SEP |
| + " xmlns:tts='http://www.w3.org/ns/ttml#styling'" + LINE_SEP |
| + " xmlns:ttp='http://www.w3.org/ns/ttml#parameter'" + LINE_SEP |
| + " xmlns:tvd='http://www.eclipse.org/actf/ai/tvd'>"); |
| writer.println(" <head>"); |
| writer.println(" <metadata>"); |
| writer.println(" <ttm:title>TextTrack (Audio Description)</ttm:title>");// TODO |
| writer.println(" </metadata>"); |
| |
| writer.println(" <styling>" + LINE_SEP + " <style xml:id=\"style1\"/>" + LINE_SEP + " </styling>" |
| + LINE_SEP + " <layout>" + LINE_SEP + " <region xml:id=\"region1\" style=\"style1\"/>" + LINE_SEP |
| + " </layout>" + LINE_SEP + |
| // |
| " </head>" + LINE_SEP + " <body>" + LINE_SEP + " <div role=\"narration\" region=\"region1\">"); |
| |
| if (isPrerecorded) { |
| File readmeFile = new File(adWavDirpath + "1st_Readme.txt"); |
| try { |
| PrintWriter pw = new PrintWriter(readmeFile, "UTF-8"); |
| if (voice.canSpeakToFile()) { |
| pw.println("Please convert wav files into wma/oga/m4a formats."); |
| pw.println(" wma: for IE8 or older"); |
| pw.println(" oga: for Chrome, Firefox, Opera"); |
| pw.println(" m4a: for IE9 or later, Safari"); |
| pw.println(); |
| pw.println("After converting files, please deploy these files to your Web server,"); |
| pw.println("and adjust URLs of \"tvd:external\" attribute in " + file.getName()); |
| pw.flush(); |
| pw.close(); |
| } else { |
| pw.println("This TTS engine can't create wav files."); |
| pw.println("Please prepare audio descriptions in wma/oga/m4a formats."); |
| pw.println(" wma: for IE8 or older"); |
| pw.println(" oga: for Chrome, Firefox, Opera"); |
| pw.println(" m4a: for IE9 or later, Safari"); |
| pw.println(); |
| pw.println("After preparing files, please deploy these files to your Web server,"); |
| pw.println("and adjust URLs of \"tvd:external\" attribute in " + file.getName()); |
| pw.flush(); |
| pw.close(); |
| } |
| } catch (Exception e) { |
| } |
| } |
| |
| // Write all ScriptData |
| List<IScriptData> scriptList = scriptDataMgr.getDataList(); |
| int i = 0; |
| for (IScriptData scriptData : scriptList) { |
| if (scriptData.getType() != IScriptData.TYPE_AUDIO) { |
| continue; |
| } |
| int startTime = scriptData.getStartTime(); |
| int frame = (startTime % 1000) / (1000 / 30); |
| String frameS = (frame > 9) ? Integer.toString(frame) : "0" + frame; |
| |
| String strStartTime = TimeFormatUtil.makeFormatHHMMSS_short(startTime / 1000) + ":" + frameS; |
| int endTime = scriptData.getEndTime(); |
| |
| int duration = endTime - startTime; |
| frame = (endTime % 1000) / (1000 / 30); |
| frameS = (frame > 9) ? Integer.toString(frame) : "0" + frame; |
| |
| String StrEndTime = TimeFormatUtil.makeFormatHHMMSS_short(endTime / 1000) + ":" + frameS; |
| |
| frame = (duration % 1000) / (1000 / 30); |
| frameS = (frame > 9) ? Integer.toString(frame) : "0" + frame; |
| |
| String strDuration = TimeFormatUtil.makeFormatHHMMSS_short(duration / 1000) + ":" + frameS; |
| |
| String strDesc = scriptData.getDescription(); |
| |
| // TODO diff duration with next item |
| writer.print(" <p xml:id=\"description" + i + "\" begin=\"" + strStartTime); |
| if (scriptData.isExtended()) { |
| writer.print("\" tvd:extended=\"true\" dur=\"" + strDuration + "\""); |
| } else { |
| writer.print("\" tvd:extended=\"false\" end=\"" + StrEndTime + "\""); |
| } |
| |
| if (isPrerecorded) { |
| int number = i + 1; |
| String ad_file; |
| if (number < 10) { |
| ad_file = adWavFilename + "_0000" + number; |
| } else if (number < 100) { |
| ad_file = adWavFilename + "_000" + number; |
| } else if (number < 1000) { |
| ad_file = adWavFilename + "_00" + number; |
| } else if (number < 10000) { |
| ad_file = adWavFilename + "_0" + number; |
| } else { |
| ad_file = adWavFilename + number; |
| } |
| if (adUrlBase == null || adUrlBase.isEmpty()) { |
| writer.print(" tvd:external=\"file://" + adWavDirpath + ad_file + ".*\""); |
| } else { |
| writer.print(" tvd:external=\"" + adUrlBase + ad_file + ".*\""); |
| } |
| if (voice.canSpeakToFile()) { |
| String strGender = scriptData.getVgGender() ? "male" : "female"; |
| voice.setGender(strGender); |
| |
| // TODO need convert |
| voice.setSpeed(scriptData.getVgPlaySpeed()); |
| voice.speakToFile(strDesc, new File(adWavDirpath + ad_file + ".wav")); |
| } else { // Temporally implementation |
| final IScriptData target = scriptData; |
| System.out.println("bbb: " + voice.getPlayVoiceStatus()); |
| if (!voice.getPlayVoiceStatus()) { |
| final SoundMixer mixer = SoundMixer.getInstance(); |
| mixer.startCaptureSound(SoundMixer.SM_PMODE_FSAVE); |
| voice.speak(target); |
| voice.setPlayVoiceStatus(1); |
| |
| Runnable finishCheck = new Runnable(){ |
| public void run(){ |
| System.out.println("aaa:" + voice.getPlayVoiceStatus()); |
| if(voice.getPlayVoiceStatus()){ |
| Display display = Display.getCurrent(); |
| if(!display.isDisposed()){ |
| display.timerExec(100, this); |
| } |
| }else{ |
| mixer.stopCaptureSound(); |
| } |
| } |
| }; |
| Display.getCurrent().timerExec(100, finishCheck); |
| } |
| } |
| } |
| writer.println(">" + canonicalize(strDesc) + "</p>"); |
| i++; |
| } |
| |
| writer.println(" </div>" + LINE_SEP + " </body>" + LINE_SEP + "</tt>"); |
| |
| } catch (IOException e) { |
| e.printStackTrace(); |
| } finally { |
| if (writer != null) { |
| try { |
| writer.flush(); |
| writer.close(); |
| } catch (Exception e) { |
| } |
| } |
| } |
| } |
| |
| private static String canonicalize(String targetS) { |
| return (targetS.replaceAll("\\p{Cntrl}", "").replaceAll("&", "&").replaceAll("<", "<") |
| .replaceAll(">", ">").replaceAll("\"", """).replaceAll("\'", "'")); |
| } |
| |
| } |