-- ************************************************** -- Provide Moho with the name of this script object -- ************************************************** ScriptName = "AE_Lipsync" -- ************************************************** -- General information about this script -- ************************************************** AE_Lipsync = {} function AE_Lipsync:Name() return 'Lipsync tool' end function AE_Lipsync:Version() return '1.16' end function AE_Lipsync:UILabel() return 'Lipsync tool' end function AE_Lipsync:Creator() return 'Alexandra Evseeva' end function AE_Lipsync:Description() return 'Apply lipsync prepared in "lipsync" action with Names set by markers and filters set by red and orange labled keys.' end function AE_Lipsync:OnMouseDown(moho, mouseEvent) -- need for tool instead of button end -- ************************************************** -- Is Relevant / Is Enabled -- ************************************************** function AE_Lipsync:IsRelevant(moho) return true end function AE_Lipsync:IsEnabled(moho) return true end function AE_Lipsync:LoadPrefs(prefs) self.accuracy = prefs:GetFloat("AE_Lipsync.accuracy", 0.1) self.numButtons = prefs:GetInt("AE_Lipsync.numButtons", 6) self.buttonSize = prefs:GetInt("AE_Lipsync.buttonSize", 3) end function AE_Lipsync:SavePrefs(prefs) prefs:SetFloat("AE_Lipsync.accuracy", self.accuracy) prefs:SetInt("AE_Lipsync.numButtons", self.numButtons) prefs:SetInt("AE_Lipsync.buttonSize", self.buttonSize) end function AE_Lipsync:ResetPrefs() AE_Lipsync.currentAction = AE_Lipsync.defaultAction AE_Lipsync.numButtons = 6 AE_Lipsync.buttonSize = 3 AE_Lipsync.accuracy = 0.1 end -- ************************************************** -- Keyboard/Mouse Control -- ************************************************** -- ************************************************** -- Tool Panel Layout -- ************************************************** AE_Lipsync.defaultAction = "lipsync" AE_Lipsync.currentAction = AE_Lipsync.defaultAction AE_Lipsync.numButtons = 6 AE_Lipsync.buttonSize = 3 AE_Lipsync.accuracy = 0.1 --AE_Lipsync.lastLayer = nil AE_Lipsync.DEFAULT_BUTTON = MOHO.MSG_BASE + 100 AE_Lipsync.ALTER_BUTTON = MOHO.MSG_BASE + 150 AE_Lipsync.DEFAULT_MENU = MOHO.MSG_BASE + 50 AE_Lipsync.ADD2CURRENT = MOHO.MSG_BASE + 1 AE_Lipsync.ADD2NEW = MOHO.MSG_BASE + 2 AE_Lipsync.REMOVE_BUTTON = MOHO.MSG_BASE + 3 AE_Lipsync.AUTOMAP_BUTTON = MOHO.MSG_BASE + 4 AE_Lipsync.CURRENT_BUTTON = MOHO.MSG_BASE + 5 local settingsDialog = {} local newActionDialog = {} function AE_Lipsync:DoLayout(moho, layout) self.dlog = settingsDialog:new() self.settingsPopup = LM.GUI.PopupDialog('settings...', false, 0) self.settingsPopup:SetDialog(self.dlog) layout:AddChild(self.settingsPopup, LM.GUI.ALIGN_LEFT, 0) --TODO: uncomment for enabling add new label to current or new action --[[ self.addButton = LM.GUI.Button('add to:', self.ADD2CURRENT) layout:AddChild(self.addButton, LM.GUI.ALIGN_LEFT, 0) self.addButton:SetAlternateMessage(self.ADD2NEW) --]] self.actionMenu = LM.GUI.Menu('action for apply') self.actionMenu_popup = LM.GUI.PopupMenu(120, true) self.actionMenu_popup:SetMenu(self.actionMenu) layout:AddChild(self.actionMenu_popup, LM.GUI.ALIGN_LEFT, 0) self.defaultButton = LM.GUI.Button('default', self.DEFAULT_BUTTON) layout:AddChild(self.defaultButton, LM.GUI.ALIGN_LEFT, 0) self.currentButton = LM.GUI.Button('current', self.CURRENT_BUTTON) layout:AddChild(self.currentButton, LM.GUI.ALIGN_LEFT, 0) self.buttons = {} local defaultText = "" for i=1, self.buttonSize do defaultText = defaultText .. "." end for i=1, self.numButtons do local nextButton = LM.GUI.Button(defaultText, self.DEFAULT_BUTTON + i) layout:AddChild(nextButton, LM.GUI.ALIGN_LEFT, 0) table.insert(self.buttons, {["button"] = nextButton, ["text"] = "..."}) nextButton:SetAlternateMessage(self.ALTER_BUTTON + i) end self.removeButton = LM.GUI.Button('remove', self.REMOVE_BUTTON) layout:AddChild(self.removeButton, LM.GUI.ALIGN_LEFT, 0) self.removeButton:SetToolTip("Remove current set keys from current frame") self.automapButton = LM.GUI.Button('auto map', self.AUTOMAP_BUTTON) layout:AddChild(self.automapButton, LM.GUI.ALIGN_LEFT, 0) self.automapButton:SetToolTip("Set keys for selected labels interval") end function AE_Lipsync:UpdateWidgets(moho) --if moho.layer ~= self.lastLayer then self:PopulateActionList(moho) self:PrepareAction(moho, self.currentAction) --self.lastLayer = moho.layer --end end function AE_Lipsync:PopulateActionList(moho) -- find all the actions for active layer, its children or parents, which have marker channel inside it local actionNames = {} for i, layer in AE_Utilities:IterateAllLayers(moho) do if layer == moho.layer or AE_Utilities:IsAncestor(layer, moho.layer) or AE_Utilities:IsAncestor(moho.layer, layer) then local markerChannel = layer.fTimelineMarkers for a=0, markerChannel:CountActions()-1 do local nextName = markerChannel:ActionName(a) local allways_added = false for k,v in pairs(actionNames) do if v == nextName then allways_added = true break end end if not allways_added then table.insert(actionNames, nextName) end end end end self.actionMenu:RemoveAllItems() for k, v in pairs(actionNames) do local m = self.DEFAULT_MENU + k self.actionMenu:AddItem(v, 0, m) if v == self.currentAction then self.actionMenu:SetChecked(m, true) end end if self.actionMenu:FirstChecked() < 0 and self.actionMenu:CountItems() > 0 then self.actionMenu:SetChecked(self.DEFAULT_MENU + 1, true) self.currentAction = actionNames[1] end end function AE_Lipsync:HandleMessage(moho, view, msg) if msg > self.DEFAULT_MENU and msg < self.DEFAULT_BUTTON then self.currentAction = self.actionMenu:FirstCheckedLabel() self:PrepareAction(moho, self.currentAction) elseif msg == self.DEFAULT_BUTTON then moho.document:SetDirty() moho.document:PrepUndo() self:ApplyAction(moho, self.currentAction) elseif msg == self.CURRENT_BUTTON then moho.document:SetDirty() moho.document:PrepUndo() self:ApplyAction(moho, self.currentAction, nil, true) elseif msg == self.REMOVE_BUTTON then moho.document:SetDirty() moho.document:PrepUndo() self:RemoveActions(moho, self.currentAction) elseif msg == self.AUTOMAP_BUTTON then moho.document:SetDirty() moho.document:PrepUndo() self:AutoMapActions(moho, self.currentAction) elseif msg >= self.DEFAULT_BUTTON and msg < self.ALTER_BUTTON then moho.document:SetDirty() moho.document:PrepUndo() local theButton = self.buttons[msg - self.DEFAULT_BUTTON] if theButton.text == '...' then local newLabel = self:AddAction(moho, self.currentAction) if newLabel then moho:UpdateUI() end else self:ApplyAction(moho, self.currentAction, theButton.text) end elseif msg >= self.ALTER_BUTTON then moho.document:SetDirty() moho.document:PrepUndo() local theButton = self.buttons[msg - self.ALTER_BUTTON] if theButton.text == '...' then local newLabel = self:AddAction(moho, self.currentAction) if newLabel then moho:UpdateUI() end else self:FixAction(moho, self.currentAction, theButton.text) end end end function AE_Lipsync:FindActionMarkersChannel(moho, actionName) for i, layer in AE_Utilities:IterateAllLayers(moho) do if layer == moho.layer or AE_Utilities:IsAncestor(layer, moho.layer) or AE_Utilities:IsAncestor(moho.layer, layer) then local actionChannel = layer.fTimelineMarkers:ActionByName(actionName) if actionChannel and actionChannel:Duration() > 0 then return moho:ChannelAsAnimString(actionChannel) end end end end function AE_Lipsync:PrepareAction(moho, actionName) local markerChannel = self:FindActionMarkersChannel(moho, actionName) local buttonCounter = 1 if markerChannel then for k=1, markerChannel:CountKeys()-1 do local nextText = markerChannel:GetValueByID(k) local alsoFound = false for i=1, buttonCounter-1 do if self.buttons[i].text == nextText then alsoFound = true break end end if nextText == "default" then alsoFound = true end if not alsoFound then self.buttons[buttonCounter].text = nextText self.buttons[buttonCounter].button:SetLabel(nextText, false) self.buttons[buttonCounter].button:Enable(true) buttonCounter = buttonCounter + 1 if buttonCounter > self.numButtons then break end end end end if buttonCounter > self.numButtons then return end self.buttons[buttonCounter].button:SetLabel("...", false) self.buttons[buttonCounter].text = "..." for i = buttonCounter + 1, self.numButtons do self.buttons[i].button:SetLabel(".", false) self.buttons[i].button:Enable(false) end end function AE_Lipsync:GetFilteringChannels(moho, actionName) local redChannels = {} local orangeChannels = {} local interp = MOHO.InterpSetting:new_local() for i, layer in AE_Utilities:IterateAllLayers(moho) do if layer == moho.layer or AE_Utilities:IsAncestor(layer, moho.layer) or AE_Utilities:IsAncestor(moho.layer, layer) then for j, i, channel, chInfo in AE_Utilities:IterateAllChannels(moho, layer) do local actionChannel = channel:ActionByName(actionName) if actionChannel then for k=1, actionChannel:CountKeys()-1 do actionChannel:GetKeyInterpByID(k, interp) if interp.tags == 1 then table.insert(redChannels, {["channel"] = channel, ["layer"]=layer}) --print(i, " ", j, " ", chInfo.name:Buffer()) break elseif interp.tags == 2 then table.insert(orangeChannels, {["channel"] = channel, ["layer"]=layer}) break end end end end end end return redChannels, orangeChannels end function AE_Lipsync:FindLabeledFrame(moho, actionName, label, filterFrame, redChannels, orangeChannels) if not redChannels and not orangeChannels then redChannels, orangeChannels = self:GetFilteringChannels(moho, actionName) end --print("Found ", #redChannels, " red and ", #orangeChannels, " orange channels") --for i,c in pairs(redChannels) do print(tostring(c.channel)) end --for i,c in pairs(orangeChannels) do print(tostring(c.channel)) end local markerChannel = self:FindActionMarkersChannel(moho, actionName) actionFrame = nil local isFliped = false for k=1, markerChannel:CountKeys()-1 do if markerChannel:GetValueByID(k) == label then local t = markerChannel:GetKeyWhen(k) --print("checking key ", k, " at frame ", t) local filtered = true for i,v in pairs(orangeChannels) do local channel = AE_Utilities:GetDerivedChannel(moho, v.channel) local curValue = channel:GetValue(filterFrame + v.layer:TotalTimingOffset()) local actChannel = AE_Utilities:GetDerivedChannel(moho, v.channel:ActionByName(actionName)) local actValue = actChannel:GetValue(t) --print("orange ", 180*curValue/math.pi, " ", 180*actValue/math.pi) if not AE_Utilities:IsEqualValues(channel, curValue, actValue, self.accuracy) then filtered = false break else --print("not equal") end end if filtered then for i,v in pairs(redChannels) do local channel = AE_Utilities:GetDerivedChannel(moho, v.channel) local zeroValue = channel:GetValue(0) local curValue = channel:GetValue(filterFrame + v.layer:TotalTimingOffset()) --print("first: ", curValue/math.pi*180, " (frame ", filterFrame + v.layer:TotalTimingOffset(), " )") curValue = curValue + AE_Utilities:SumActionInfluences(moho, filterFrame + v.layer:TotalTimingOffset(), channel, v.layer) --print("second: ", curValue/math.pi*180) local actChannel = AE_Utilities:GetDerivedChannel(moho, v.channel:ActionByName(actionName)) local actValue = actChannel:GetValue(t) --print("red ", 180*curValue/math.pi, " ", 180*actValue/math.pi) if math.abs(math.abs(curValue-zeroValue) - math.abs(actValue-zeroValue)) > self.accuracy then filtered = false break else if math.abs((curValue-zeroValue) - (actValue-zeroValue)) > self.accuracy then isFliped = true end end end end if filtered then return t, isFliped end end end return actionFrame end function AE_Lipsync:SearchForOpposite(moho, layer) local currentLayer = layer local parents = {} while not (string.sub(currentLayer:Name(),-1) == "R" or string.sub(currentLayer:Name(),-1) == "L") do if not currentLayer:Parent() then return nil end table.insert(parents, currentLayer:Name()) currentLayer = currentLayer:Parent() end local sourceName = currentLayer:Name() local targetName = string.sub(sourceName, 1, -2) if string.sub(sourceName,-1) == "R" then targetName = targetName .. "L" elseif string.sub(sourceName,-1) == "L" then targetName = targetName .. "R" else return nil end local layersHolder = moho.document if currentLayer:Parent() then layersHolder = currentLayer:Parent() end local oppositeLayer = nil for i=0, layersHolder:CountLayers()-1 do local nextLayer = layersHolder:Layer(i) if nextLayer:Name() == targetName then oppositeLayer = nextLayer break end end if not oppositeLayer then return nil end local nextParent = oppositeLayer local nextChild = nil if #parents == 0 then return oppositeLayer end for i = #parents, 1, -1 do nextParent = moho:LayerAsGroup(nextParent) nextChild = nil if not nextParent then return nil end for j=0, nextParent:CountLayers()-1 do if nextParent:Layer(j):Name() == parents[i] then nextChild = nextParent:Layer(j) break end end if not nextChild then return nil end nextParent = nextChild end if nextChild:Name() == layer:Name() then return nextChild end return nil end function AE_Lipsync:IterateActionValueChannels(moho, actionName, redChannels, orangeChannels, isFliped) if not redChannels and not orangeChannels then redChannels, orangeChannels = self:GetFilteringChannels(moho, actionName) end local channels2iterate = {} for i, layer in AE_Utilities:IterateAllLayers(moho) do if layer == moho.layer or AE_Utilities:IsAncestor(moho.layer, layer) then local oppositeLayer = nil if isFliped then oppositeLayer = self:SearchForOpposite(moho, layer) end for subID, ID, channel, chInfo in AE_Utilities:IterateAllChannels(moho, layer) do local isFiltering = false for j,v in pairs(redChannels) do if v.channel == channel then isFiltering = true break end end if not isFiltering then for j,v in pairs(orangeChannels) do if v.channel == channel then isFiltering = true break end end end if not isFiltering then local actChannel = channel:ActionByName(actionName) if oppositeLayer then local oppInfo = MOHO.MohoLayerChannel:new_local() oppositeLayer:GetChannelInfo(ID, oppInfo) if oppInfo.subChannelCount >= chInfo.subChannelCount then local oppositeChannel = oppositeLayer:Channel(ID, subID, moho.document) actChannel = oppositeChannel and oppositeChannel:ActionByName(actionName) else actChannel = nil end end if actChannel and actChannel:Duration() > 0 then local curChannel = AE_Utilities:GetDerivedChannel(moho, channel) actChannel = AE_Utilities:GetDerivedChannel(moho, actChannel) local item2insert = {["channel"] = curChannel, ["actChannel"] = actChannel, ["layer"] = layer, ["chInfo"]=chInfo} table.insert(channels2iterate, item2insert) end end end end end return pairs(channels2iterate) end function AE_Lipsync:ApplyAction(moho, actionName, label, setCurrent) if setCurrent then for i, layer in AE_Utilities:IterateAllLayers(moho) do for subID, ID, channel, chInfo in AE_Utilities:IterateAllChannels(moho, layer) do for k = 0, channel:CountKeys() - 1 do channel:SetKeySelectedByID(k, false) end end layer:SetShownOnTimeline(false) end end -- find filtering channels storing them into two arrays local actionFrame = 0 local isFilped = false local redChannels, orangeChannels = self:GetFilteringChannels(moho, actionName) -- if label then find action frame corresponding to filters if label then actionFrame, isFliped = self:FindLabeledFrame(moho, actionName, label, moho.frame, redChannels, orangeChannels) --print("found at ", actionFrame, " flip is ", tostring(isFilped)) if not actionFrame then return LM.GUI.Alert(LM.GUI.ALERT_WARNING, "No label " .. label .. " meet current filters in " .. actionName) end end -- iterate action channels wich is not filtering ones and apply values from actionFrame for k,v in self:IterateActionValueChannels(moho, actionName, redChannels, orangeChannels, isFliped) do local layerFrame = moho.frame + v.layer:TotalTimingOffset() if setCurrent then v.channel:SetValue(layerFrame, v.channel:GetValue(layerFrame)) v.layer:SetShownOnTimeline(true) v.channel:SetKeySelected(layerFrame, true) else v.channel:SetValue(layerFrame, v.actChannel:GetValue(actionFrame)) end -- if lipsync closest key is STEP then set step for this and previous keys if v.actChannel:GetKeyInterpModeByID(v.actChannel:GetClosestKeyID(actionFrame)) == MOHO.INTERP_STEP then local interp = MOHO.InterpSetting:new_local() v.channel:GetKeyInterp(layerFrame, interp) interp.interpMode = MOHO.INTERP_STEP v.channel:SetKeyInterp(layerFrame, interp) local prevKey = v.channel:GetClosestKeyID(layerFrame) - 1 if prevKey > 0 then v.channel:GetKeyInterpByID(prevKey, interp) interp.interpMode = MOHO.INTERP_STEP v.channel:SetKeyInterpByID(prevKey, interp) end end v.layer:UpdateCurFrame() end moho:UpdateSelectedChannels() moho:UpdateUI() end function AE_Lipsync:RemoveActions(moho, actionName) -- iterate current action channels but not filtering ones -- and remove current frame key if exist for k,v in self:IterateActionValueChannels(moho, actionName) do v.channel:DeleteKey(moho.frame) v.layer:UpdateCurFrame() end moho:UpdateSelectedChannels() moho:UpdateUI() end function AE_Lipsync:AutoMapActions(moho, actionName) -- collect selected markers and get min and max frames local mainMarkerChannel = nil local minFrame = 10000 local maxFrame = -10000 for i, layer in AE_Utilities:IterateAllLayers(moho) do if layer == moho.layer or AE_Utilities:IsAncestor(layer, moho.layer) or AE_Utilities:IsAncestor(moho.layer, layer) then local nextMarkerChannel = layer.fTimelineMarkers for k=1, nextMarkerChannel:CountKeys()-1 do if nextMarkerChannel:IsKeySelectedByID(k) then local fr = nextMarkerChannel:GetKeyWhen(k) if minFrame > fr then minFrame = fr end if maxFrame < fr then maxFrame = fr end end end if maxFrame > -10000 then mainMarkerChannel = nextMarkerChannel if minFrame >= 10000 then minFrame = 1 end break end end end -- from min to max frame -- iterate channels local redChannels, orangeChannels = self:GetFilteringChannels(moho, actionName) for f=minFrame, maxFrame do local actionFrame = nil if mainMarkerChannel:HasKey(f) then local label = mainMarkerChannel:GetValue(f) if label == "" then actionFrame = 0 else actionFrame, isFliped = self:FindLabeledFrame(moho, actionName, label, f, redChannels, orangeChannels) end end for k,v in self:IterateActionValueChannels(moho, actionName, redChannels, orangeChannels, isFliped) do -- set value if marker exists (finding filtered value) if actionFrame then v.channel:SetValue(f, v.actChannel:GetValue(actionFrame)) else --remove keys if no marker v.channel:DeleteKey(f) end end end for k,v in self:IterateActionValueChannels(moho, actionName, redChannels, orangeChannels) do v.layer:UpdateCurFrame() end moho:UpdateSelectedChannels() moho:UpdateUI() end -- ************************************************** -- settingsDialog -- ************************************************** settingsDialog.MSG_BASE = MOHO.MSG_BASE + 500 settingsDialog.ACCURACY = settingsDialog.MSG_BASE settingsDialog.BUTTONS_NUMBER = settingsDialog.MSG_BASE + 1 settingsDialog.BUTTON_SIZE = settingsDialog.MSG_BASE + 2 settingsDialog.FORCE_KEYS = settingsDialog.MSG_BASE + 3 function settingsDialog:new() local d = LM.GUI.SimpleDialog('', settingsDialog) local l = d:GetLayout() d.forceKeysCheck = LM.GUI.CheckBox('Use keyed channels not included in action', d.FORCE_KEYS) l:AddChild(d.forceKeysCheck, LM.GUI.ALIGN_LEFT, 0) d.textControl1Input = LM.GUI.TextControl(0, '5.000', d.ACCURACY, LM.GUI.FIELD_UFLOAT, 'Filtering accuracy:') l:AddChild(d.textControl1Input, LM.GUI.ALIGN_LEFT, 0) d.textControl1Input:SetToolTip('Set 22.5 degrees for all frames in 45 degrees interval') --d.textControl1Input:SetWheelInc(0.0001) d.buttonsNumberInput = LM.GUI.TextControl(0, '6', d.BUTTONS_NUMBER, LM.GUI.FIELD_INT, 'Buttons number:') l:AddChild(d.buttonsNumberInput, LM.GUI.ALIGN_LEFT, 0) d.buttonSizeInput = LM.GUI.TextControl(0, '3', d.BUTTON_SIZE, LM.GUI.FIELD_INT, 'Button size:') l:AddChild(d.buttonSizeInput, LM.GUI.ALIGN_LEFT, 0) d.pressAltCtrlShiftLToUpdateToolText = LM.GUI.DynamicText('Press Alt Ctrl Shift L to update tool', 0) l:AddChild(d.pressAltCtrlShiftLToUpdateToolText, LM.GUI.ALIGN_LEFT, 0) return d end function settingsDialog:UpdateWidgets(moho) self.textControl1Input:SetValue(180 * AE_Lipsync.accuracy/math.pi) self.buttonsNumberInput:SetValue(AE_Lipsync.numButtons) self.buttonSizeInput:SetValue(AE_Lipsync.buttonSize) self.forceKeysCheck:SetValue(AE_Lipsync.forceKeys) end function settingsDialog:OnOK(moho) AE_Lipsync.accuracy = math.pi * self.textControl1Input:FloatValue()/180 AE_Lipsync.numButtons = self.buttonsNumberInput:IntValue() AE_Lipsync.buttonSize = self.buttonSizeInput:IntValue() AE_Lipsync.forceKeys = self.forceKeysCheck:Value() end function settingsDialog:HandleMessage(msg) --[[ if msg == self.ACCURACY then print('Message ACCURACY received') elseif msg == self.BUTTONS_NUMBER then print('Message BUTTONS_NUMBER received') elseif msg == self.BUTTON_SIZE then print('Message BUTTON_SIZE received') else end --]] end -- ************************************************** -- newActionDialog -- ************************************************** newActionDialog.MSG_BASE = MOHO.MSG_BASE + 600 newActionDialog.ACTION = newActionDialog.MSG_BASE + 1 newActionDialog.LABEL = newActionDialog.MSG_BASE + 2 newActionDialog.newAction = false AE_Lipsync.newActionName = "" AE_Lipsync.newLabelName = "" newActionDialog.BONELIST = newActionDialog.MSG_BASE + 10 function newActionDialog:new(moho) local d = LM.GUI.SimpleDialog('Create new pose from current keys', newActionDialog) local l = d:GetLayout() --[[ d.newActionNameControl = LM.GUI.TextControl(200, '', d.ACTION, LM.GUI.FIELD_TEXT, 'New action name:') l:AddChild(d.newActionNameControl, LM.GUI.ALIGN_LEFT, 0) --]] d.newLabelControl = LM.GUI.TextControl(100, '', d.LABEL, LM.GUI.FIELD_TEXT, 'New pose label:') l:AddChild(d.newLabelControl, LM.GUI.ALIGN_LEFT, 0) --[[ self.bonelistMenu = LM.GUI.Menu('Filtering smartbones') self.bonelistMenu_popup = LM.GUI.PopupMenu(120, false) self.bonelistMenu_popup:SetMenu(self.actionMenu) layout:AddChild(self.bonelistMenu_popup, LM.GUI.ALIGN_LEFT, 0) --]] return d end function newActionDialog:UpdateWidgets(moho) --self.newActionNameControl:Enable(self.newAction) --self.bonelistMenu_popup:Enable(self.newAction) --TODO: populate self.bonelistMenu with active layer or its skeleton parent layer's smartbones, --TODO: checking thouse having keys in current frame end function newActionDialog:OnOK(moho) --AE_Lipsync.newActionName = self.newActionNameControl:Value() AE_Lipsync.newLabelName = self.newLabelControl:Value() --TODO: and something about selected smartbones end function AE_Lipsync:AddFilterValue(moho, actionName, actionFrame, channel, layer, colorTag) local layerFrame = moho.frame + layer:TotalTimingOffset() channel = AE_Utilities:GetDerivedChannel(moho, channel) local actionChannel = channel:ActionByName(actionName) actionChannel = AE_Utilities:GetDerivedChannel(moho, actionChannel) actionChannel:SetValue(actionFrame, channel:GetValue(layerFrame)) local interp = MOHO.InterpSetting:new_local() actionChannel:GetKeyInterp(actionFrame, interp) interp.tags = colorTag actionChannel:SetKeyInterp(actionFrame, interp) end function AE_Lipsync:AddAction(moho, actionName) local dlog = newActionDialog:new(moho) --TODO: set newActionDialog.newAction if (dlog:DoModal() == LM.GUI.MSG_CANCEL) then return nil end moho.document:SetDirty() moho.document:PrepUndo(nil) --TODO: if newAction - create it with filters and all current frame keys for layer and its children --TODO: if not -- add labeled key to currently active action (what to do with filters?..) local newName = self.newLabelName local nextFrame = moho.layer:ActionDuration(actionName) + 1 local markerChannel = self:FindActionMarkersChannel(moho, actionName) markerChannel:SetValue(nextFrame, newName) local redChannels, orangeChannels = self:GetFilteringChannels(moho, actionName) for i, v in pairs(redChannels) do self:AddFilterValue(moho, actionName, nextFrame, v.channel, v.layer, 1) end for i, v in pairs(orangeChannels) do self:AddFilterValue(moho, actionName, nextFrame, v.channel, v.layer, 2) end self:FixAction(moho, actionName, newName) markerChannel:SetValue(nextFrame, newName) return newName end function AE_Lipsync:FixAction(moho, actionName, label) --get action frame (using filtering) local redChannels, orangeChannels = self:GetFilteringChannels(moho, actionName) -- if label then find action frame corresponding to filters if label then actionFrame, isFliped = self:FindLabeledFrame(moho, actionName, label, moho.frame, redChannels, orangeChannels) --print("found at ", actionFrame, " flip is ", tostring(isFilped)) if not actionFrame then return LM.GUI.Alert(LM.GUI.ALERT_WARNING, "No label " .. label .. " meet current filters in " .. actionName) end end local markerChannel = self:FindActionMarkersChannel(moho, actionName) --iterate existing action channels and fix their values for k,v in self:IterateActionValueChannels(moho, actionName, redChannels, orangeChannels, isFliped) do if v.actChannel ~= markerChannel then local layerFrame = moho.frame + v.layer:TotalTimingOffset() v.actChannel:SetValue(actionFrame, v.channel:GetValue(layerFrame)) end end local newChannels = {} if moho.layer:LayerType() == MOHO.LT_VECTOR then local mesh = moho:Mesh() for i = 0, mesh:CountPoints() - 1 do if mesh:Point(i).fSelected then local point = mesh:Point(i) table.insert(newChannels, {channel=point.fAnimPos, layer=moho.layer}) for c = 0, point:CountCurves() - 1 do local where = -1 local curve, where = point:Curve (id, where) local curvatureChannel = AE_Utilities:GetCurvatureChannel(moho, moho.layer, curve, where) if curvatureChannel then table.insert(newChannels, {channel=curvatureChannel, layer=moho.layer}) end for _, channelType in pairs({'GetWeightChannel', 'GetOffsetChannel'}) do for _, handleType in pairs({true, false}) do local nextChannel = AE_Utilities[channelType](AE_Utilities, moho, moho.layer, curve, where, handleType) if nextChannel then table.insert(newChannels, {channel=nextChannel, layer=moho.layer}) end end end end end end end if self.forceKeys then for i, layer in AE_Utilities:IterateAllLayers(moho) do if layer:IsAncestorSelected() or layer == moho.layer then local layerFrame = moho.frame + layer:TotalTimingOffset() for k, j, channel, chInfo in AE_Utilities:IterateAllChannels(moho, moho.layer) do if channel:HasKey(layerFrame) then table.insert(newChannels, {channel=channel, layer=layer}) end end end end end for i, entry in pairs(newChannels) do local channel = entry.channel if not channel:ActionByName(actionName) then channel = AE_Utilities:GetDerivedChannel(moho, channel) local layerFrame = moho.frame + entry.layer:TotalTimingOffset() local curValue = channel:GetValue(layerFrame) channel:ActivateAction(actionName) actChannel = channel:ActionByName(actionName) actChannel = AE_Utilities:GetDerivedChannel(moho, actChannel) actChannel:SetValue(actionFrame, curValue) if actionFrame > 1 then actChannel:SetValue(actionFrame - 1, actChannel:GetValue(0)) end --if actionFrame < moho.layer:ActionDuration(actionName) then actChannel:SetValue(actionFrame + 1, actChannel:GetValue(0)) --end channel:ActivateAction("") end end moho:UpdateSelectedChannels() moho:UpdateUI() end
Morph-Lipsync
Listed
Author: A.Evseeva
View Script
Script type: Tool
Uploaded: Jun 26 2022, 14:08
Last modified: Jul 19 2022, 03:54
Apply marked frames of actions to main timeline with buttons
Mainly used for lipsync. Draft presentation in video:
Final presentation is coming... not soon.
This script, and all other scripts on this site are distributed as free software under the GNU General Public License 3.0 or later.
Downloads count: 104

Morph-Lipsync
Listed
Author: A.Evseeva
View Script
Script type: Tool
Uploaded: Jun 26 2022, 14:08
Last modified: Jul 19 2022, 03:54
Apply marked frames of actions to main timeline with buttons
Mainly used for lipsync. Draft presentation in video:
Final presentation is coming... not soon.
Final presentation is coming... not soon.
This script, and all other scripts on this site are distributed as free software under the GNU General Public License 3.0 or later.
Downloads count: 104