/* ----------------------------------------------------------------------------- This source file is part of OpenSpace3D For the latest info, see http://www.openspace3d.com Copyright (c) 2012 I-maginer This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA, or go to http://www.gnu.org/copyleft/lesser.txt ----------------------------------------------------------------------------- */ struct PlugSpeech = [ PS_instance : PInstance, PS_Speech : ObjSpeech, PS_player : AudioPlayer, PS_Rate : I, PS_lVisemes : [[S I] r1], PS_iTick : I, PS_iNextTick : I, PS_iStartTick : I, PS_bFirstFrame : I ]mkPlugSpeech;; fun deleteOb(inst, obstr)= setPluginInstanceCbScenePreRender inst nil; _DSSpeech obstr.PS_Speech; audioPlayerDelete obstr.PS_player; 0;; fun cbControlPreRender(inst, sessionstr, etime, obstr)= let if (obstr.PS_bFirstFrame) then min 66666 etime else etime -> etime in // limits to 15 fps on first frame for minimum moves on first frame, but keep skip on lags if (obstr.PS_lVisemes == nil) then ( set obstr.PS_iNextTick = 0; set obstr.PS_iTick = 0; ) else ( set obstr.PS_bFirstFrame = 0; let if obstr.PS_iStartTick <= 0 then 0 else _tickcount - obstr.PS_iStartTick -> initdiff in set obstr.PS_iTick = obstr.PS_iTick + etime + (initdiff * 1000); set obstr.PS_iStartTick = -1; let obstr.PS_iTick - obstr.PS_iNextTick -> diff in ( if ((obstr.PS_iNextTick == 0) || (obstr.PS_iTick >= obstr.PS_iNextTick)) then let hd obstr.PS_lVisemes -> [viseme duration] in let ftoi ((1.0 /. obstr.PS_player.APL_fPitch) *. (itof (duration * 1000))) -> duration in ( set obstr.PS_lVisemes = tl obstr.PS_lVisemes; //skip if needed if (obstr.PS_iNextTick == 0) then nil else while ((diff >= duration) && (obstr.PS_lVisemes != nil)) do ( let hd obstr.PS_lVisemes -> [nviseme nduration] in ( set viseme = nviseme; set duration = ftoi ((1.0 /. obstr.PS_player.APL_fPitch) *. (itof (nduration * 1000))); set diff = diff - duration; ); set obstr.PS_lVisemes = tl obstr.PS_lVisemes; ); set obstr.PS_iNextTick = obstr.PS_iTick + (duration - diff); SendPluginEvent inst "Viseme" strcatn viseme::" "::(itoa ((duration - diff) / 1000))::nil nil; ) else nil; ); 0; ); 0;; fun cbPlay(inst, from, action, param, reply, obstr)= if ((param == nil) || (!strcmp strtrim param "")) then nil else let sanitizeString param -> text in _SetSpeechText obstr.PS_Speech text; set obstr.PS_lVisemes = nil; set obstr.PS_iNextTick = 0; set obstr.PS_iTick = 0; set obstr.PS_iStartTick = 0; _PlaySpeech obstr.PS_Speech; setPluginInstanceCbScenePreRender inst mkfun4 @cbControlPreRender obstr; audioPlayerPlay obstr.PS_player; 0;; fun cbResume(inst, from, action, param, reply, obstr)= _ResumeSpeech obstr.PS_Speech; audioPlayerPlay obstr.PS_player; setPluginInstanceCbScenePreRender inst mkfun4 @cbControlPreRender obstr; 0;; fun cbPause(inst, from, action, param, reply, obstr)= _PauseSpeech obstr.PS_Speech; audioPlayerPause obstr.PS_player; setPluginInstanceCbScenePreRender inst nil; set obstr.PS_iNextTick = 0; set obstr.PS_iTick = 0; 0;; fun cbStop(inst, from, action, param, reply, obstr)= _StopSpeech obstr.PS_Speech; audioPlayerStop obstr.PS_player; setPluginInstanceCbScenePreRender inst nil; set obstr.PS_lVisemes = nil; set obstr.PS_iNextTick = 0; set obstr.PS_iTick = 0; set obstr.PS_iStartTick = 0; SendPluginEvent inst "Viseme" "rest" nil; 0;; fun cbSetText(inst, from, action, param, reply, obstr)= if param == nil then nil else let sanitizeString param -> text in _SetSpeechText obstr.PS_Speech text; 0;; fun cbAddText(inst, from, action, param, reply, obstr)= if param == nil then nil else let sanitizeString param -> text in _AddSpeechText obstr.PS_Speech text; 0;; fun cbSetVoice(inst, from, action, param, reply, obstr)= if param == nil then nil else _SetSpeechVoice obstr.PS_Speech param; 0;; fun cbSpeechEnd(speech, inst)= SendPluginEvent inst "End" nil nil; 0;; fun cbSpeechStart(speech, inst)= SendPluginEvent inst "Start" nil nil; 0;; fun cbSpeechPhoneme(speech, inst, phoneme)= SendPluginEvent inst "Phoneme" itoa phoneme nil; 0;; fun cbSpeechViseme(speech, obstr, lviseme)= set obstr.PS_lVisemes = lcat obstr.PS_lVisemes lviseme; 0;; fun cbSpeechSentence(speech, obstr, phrase, duration)= let ftoi ((1.0 /. obstr.PS_player.APL_fPitch) *. (itof duration)) -> duration in SendPluginEvent obstr.PS_instance "Sentence" strcatn "["::(itoa duration)::"]"::phrase::nil nil; 0;; fun cbSpeechBuffer(speech, obstr, buff)= audioPlayerUpdateBuffer obstr.PS_player buff; if (obstr.PS_iStartTick != 0) then nil else set obstr.PS_iStartTick = _tickcount; 0;; fun cbSetVolume(inst, from, action, param, reply, obstr)= if (obstr.PS_player == nil || (atoi param) == nil) then nil else audioPlayerSetVolume obstr.PS_player (atoi param); 0;; fun cbSetPitch(inst, from, action, param, reply, obstr)= if (obstr.PS_player == nil || (atof param) == nil) then nil else audioPlayerSetPitch obstr.PS_player (atof param); 0;; fun cbLoaded(inst, p)= let p -> [obstr txt] in cbPlay inst nil nil txt nil obstr; 0;; fun newOb(inst)= let (getPluginInstanceParam inst "text") -> text in let (getPluginInstanceParam inst "voicemodel") -> voicemodel in let (getPluginInstanceParam inst "voiceconfig") -> voiceconfig in let (getPluginInstanceParam inst "voiceid") -> voiceid in let atoi (getPluginInstanceParam inst "rate") -> rate in let atoi (getPluginInstanceParam inst "is3daudio") -> is3daudio in let if is3daudio == nil then 0 else is3daudio -> is3daudio in let (getPluginInstanceParam inst "source") -> objname in let V3DgetObjectByName c3dXsession objname -> object in let atof (getPluginInstanceParam inst "attenuation") -> attenuation in let if attenuation == nil then 1.0 else attenuation -> attenuation in let atoi (getPluginInstanceParam inst "innerangle") -> innerangle in let if innerangle == nil then 360 else innerangle -> innerangle in let atoi (getPluginInstanceParam inst "outerangle") -> outerangle in let if outerangle == nil then 360 else outerangle -> outerangle in let atoi (getPluginInstanceParam inst "outervol") -> outervol in let if outervol == nil then 0 else outervol -> outervol in let atof (getPluginInstanceParam inst "pitch") -> pitch in let if pitch == nil then 1.0 else pitch -> pitch in let atoi (getPluginInstanceParam inst "volume") -> volume in let atoi (getPluginInstanceParam inst "enableeffect") -> enableeffect in let if (enableeffect == nil) then 1 else enableeffect -> enableeffect in let atoi (getPluginInstanceParam inst "enableSpeech") -> initStartSpeech in let if initStartSpeech == nil then 1 else initStartSpeech -> initStartSpeech in let _CRSpeech _channel -> speech in let mkPlugSpeech [inst speech nil rate nil 0 0 0 1] -> obstr in ( //if ((strcmp voicename (_GetSpeechVoice speech))== 0) then nil else //let if (!strcmpi currentLanguage "french") then "fr-fr" else "en-us" -> lang in //let strcatn (getPluginDirectory (getInstancePlugin inst))::"/voices/"::"fr-fr"::"/fr_FR-upmc-medium.onnx"::nil -> binpath in _SetSpeechVoiceModel speech _checkpack voicemodel; _SetSpeechVoice speech voiceid; if (is3daudio) then set obstr.PS_player = audioPlayerCreate3d (getPluginInstanceName inst) 0 enableeffect volume pitch nil object attenuation [innerangle outerangle outervol] else set obstr.PS_player = audioPlayerCreate (getPluginInstanceName inst) 0 enableeffect volume pitch nil; //(mknode @cbEndSound obstr); audioPlayerOpenBuffered obstr.PS_player (_GetSpeechVoiceSampleRate obstr.PS_Speech) AUDIO_16BIT_MONO; /*let _GetSpeechVoices speech nil -> l in while (l != nil) do ( addLogMessage strcat "Avalaible voices : " hd l; set l = tl l; );*/ _CBSpeechStart speech @cbSpeechStart inst; _CBSpeechEnd speech @cbSpeechEnd inst; _CBSpeechPhoneme speech @cbSpeechPhoneme inst; _CBSpeechVisemePreston speech @cbSpeechViseme obstr; _CBSpeechTextExt speech @cbSpeechSentence obstr; _CBSpeechBuffer speech @cbSpeechBuffer obstr; _SetSpeechRate speech rate; //audioPlayerSetVolume obstr.PS_player (atoi param); PluginRegisterAction inst "Play" mkfun6 @cbPlay obstr; PluginRegisterAction inst "Resume" mkfun6 @cbResume obstr; PluginRegisterAction inst "Pause" mkfun6 @cbPause obstr; PluginRegisterAction inst "Stop" mkfun6 @cbStop obstr; PluginRegisterAction inst "Set Text" mkfun6 @cbSetText obstr; PluginRegisterAction inst "Add Text" mkfun6 @cbAddText obstr; PluginRegisterAction inst "Set Voice" mkfun6 @cbSetVoice obstr; PluginRegisterAction inst "Set volume" mkfun6 @cbSetVolume obstr; PluginRegisterAction inst "Set pitch" mkfun6 @cbSetPitch obstr; if !initStartSpeech then nil else if inst.INST_groupstr.GRP_project.PRJ_bPluginsLoaded then ( cbPlay inst nil nil text nil obstr; 0; ) else ( setPluginInstanceCbAllPluginsLoaded inst mkfun2 @cbLoaded [obstr text]; 0; ); setPluginInstanceCbDel inst mkfun2 @deleteOb obstr; ); 0;; fun IniPlug(file)= PlugRegister @newOb nil; setPluginEditor @dynamicedit; 0;;