Allow negative delays
[vuplus_dvbapp-plugin] / ac3lipsync / src / AC3main.py
1 from AC3utils import AC3, PCM, AC3PCM, lFileDelay, dec2hex, hex2dec
2 from AC3delay import AC3delay
3 from Components.ActionMap import ActionMap, NumberActionMap
4 from Components.Button import Button
5 from Components.ConfigList import ConfigListScreen
6 from Components.Label import Label,MultiColorLabel
7 from Components.ProgressBar import ProgressBar
8 from Components.config import config
9 from enigma import eDVBDB
10 from Screens.ChoiceBox import ChoiceBox
11 from Screens.MessageBox import MessageBox
12 from Screens.Screen import Screen
13 from Screens.InfoBarGenerics import InfoBarAudioSelection
14 from ServiceReference import ServiceReference
15 from __init__ import _
16 import os
17
18 class AC3LipSync(Screen,InfoBarAudioSelection):
19     skin = """
20         <screen position="60,472" size="600,74" title="AC3 Lip Sync" zPosition="1" >
21             <widget name="AudioDelayText" zPosition="2" position="5,0" size="180,21" font="Regular;21" foregroundColors="#ffffff,#ffa323" />
22             <ePixmap pixmap="/usr/lib/enigma2/python/Plugins/Extensions/AC3LipSync/img/AC3LipSyncBarBG.png" zPosition="2" position="190,0" size="370,21" alphatest="on" transparent="1" />
23             <widget name="AudioSlider" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/AC3LipSync/img/AC3LipSyncBar.png" zPosition="3" position="190,0" size="370,21" transparent="1" />
24             <widget name="AudioSliderText" zPosition="4" position="190,0" size="370,21" font="Regular;18" halign="center" valign="center" transparent="1" />
25             <widget name="ServiceInfoText" zPosition="4" position="5,26" size="180,21" font="Regular;18" foregroundColor="#ffffff" />
26             <widget name="ServiceInfo" zPosition="4" position="190,26" size="180,21" font="Regular;18" foregroundColor="#cccccc" />
27             <widget name="AC3DelayInfoText" zPosition="4" position="380,26" size="48,21" font="Regular;18" foregroundColor="#ffffff" />
28             <widget name="AC3DelayInfo" zPosition="4" position="430,26" size="50,21" font="Regular;18" foregroundColor="#cccccc" />
29             <widget name="PCMDelayInfoText" zPosition="4" position="490,26" size="48,21" font="Regular;18" foregroundColor="#ffffff" />
30             <widget name="PCMDelayInfo" zPosition="4" position="540,26" size="50,21" font="Regular;18" foregroundColor="#cccccc" />
31             <ePixmap pixmap="/usr/lib/enigma2/python/Plugins/Extensions/AC3LipSync/img/key-red.png" position="5,52" zPosition="5" size="20,20" transparent="1" alphatest="on" />
32             <ePixmap pixmap="/usr/lib/enigma2/python/Plugins/Extensions/AC3LipSync/img/key-green.png" position="150,52" zPosition="5" size="20,20" transparent="1" alphatest="on" />
33             <ePixmap pixmap="/usr/lib/enigma2/python/Plugins/Extensions/AC3LipSync/img/key-yellow.png" position="295,52" zPosition="5" size="20,20" transparent="1" alphatest="on" />
34             <ePixmap pixmap="/usr/lib/enigma2/python/Plugins/Extensions/AC3LipSync/img/key-blue.png" position="440,52" zPosition="5" size="20,20" transparent="1" alphatest="on" />
35             <widget name="key_red" position="30,52" zPosition="1" size="115,21"
36                 font="Regular;16" valign="center" halign="left" transparent="1"
37                 shadowColor="#000000" shadowOffset="-1,-1" />
38             <widget name="key_green" position="175,52" zPosition="1" size="115,21"
39                 font="Regular;16" valign="center" halign="left" transparent="1"
40                 shadowColor="#000000" shadowOffset="-1,-1" />
41             <widget name="key_yellow" position="320,52" zPosition="1" size="115,21"
42                 font="Regular;16" valign="center" halign="left" transparent="1"
43                 shadowColor="#000000" shadowOffset="-1,-1" />
44             <widget name="key_blue" position="465,52" zPosition="1" size="115,21"
45                 font="Regular;16" valign="center" halign="left" transparent="1"
46             shadowColor="#000000" shadowOffset="-1,-1" />
47         </screen>"""
48
49     def __init__(self, session, args = None):
50         Screen.__init__(self, session)
51         self.onShow.append(self.__onShow)
52
53         #Initialisiere Infobargenerics
54         InfoBarAudioSelection.__init__(self)
55
56         # Configuration values
57         self.upperBound = int(config.plugins.AC3LipSync.outerBounds.getValue())
58         self.lowerBound = -1 * self.upperBound
59         self.arrowStepSize = int(config.plugins.AC3LipSync.arrowStepSize.getValue())
60         self.stepSize = {}
61         self.stepSize["3"] = int(config.plugins.AC3LipSync.stepSize13.getValue())
62         self.stepSize["1"] = -1 * self.stepSize["3"]
63         self.stepSize["6"] = int(config.plugins.AC3LipSync.stepSize46.getValue())
64         self.stepSize["4"] = -1 * self.stepSize["6"]
65         self.stepSize["9"] = int(config.plugins.AC3LipSync.stepSize79.getValue())
66         self.stepSize["7"] = -1 * self.stepSize["9"]
67         self.keyStep = {}
68         self.keyStep["0"] = 0
69         self.keyStep["2"] = int(config.plugins.AC3LipSync.absoluteStep2.getValue()) 
70         self.keyStep["5"] = int(config.plugins.AC3LipSync.absoluteStep5.getValue()) 
71         self.keyStep["8"] = int(config.plugins.AC3LipSync.absoluteStep8.getValue()) 
72
73         # AC3delay instance
74         self.AC3delay = AC3delay(self.session)
75
76         #Screen elements
77
78         #Slider
79
80         for sAudio in AC3PCM:
81             self[sAudio+"Slider"] = ProgressBar()
82             self[sAudio+"SliderText"] = Label(_("%i ms")%0)
83             self[sAudio+"DelayText"] = MultiColorLabel( _("%s delay:")%sAudio)
84             self[sAudio+"DelayInfoText"] = Label( _("%s:")%sAudio)
85             self[sAudio+"DelayInfo"] = Label(_("%i ms")%0)
86
87         self["AudioSlider"] = ProgressBar()
88         self["AudioSliderText"] = Label(_("%i ms")%0)
89         self["AudioDelayText"] = MultiColorLabel( _("%s delay:")%self.AC3delay.whichAudio)
90         
91         #Service Information
92         self["ServiceInfoText"] = Label(_("Channel audio:"))
93         self["ServiceInfo"] = Label()
94         self.setChannelInfoText()
95
96         # Buttons
97         self["key_red"] = Label(_("Cancel"))
98         self["key_green"] = Label(_("OK"))
99         self["key_yellow"] = Label(_("Switch audio"))
100         if self.AC3delay.bIsRecording == True:
101             self["key_blue"] = Label("")
102         else:
103             self["key_blue"] = Label(_("Save"))
104
105         # Last saved values
106         self.savedValue = {}
107         self.savedValue[AC3] = 0
108         self.savedValue[PCM] = 0
109
110         # Current Values
111         self.currentValue = {}
112         self.currentValue[AC3] = 0
113         self.currentValue[PCM] = 0
114
115         # Actions
116         self["actions"] = NumberActionMap(["WizardActions", "NumberActions", "ColorActions", "MenuActions"],
117         {
118             "menu": self.keyMenu,
119             "ok": self.keyOk,
120             "back": self.keyCancel,
121             "left": self.keyLeft,
122             "right": self.keyRight,
123             "up": self.keyUp,
124             "down": self.keyDown,
125             "red": self.keyCancel,
126             "green": self.keyOk,
127             "yellow": self.keyAudioSelection,
128             "blue": self.keySaveToLamedb,
129             "1": self.keyNumberRelative,
130             "3": self.keyNumberRelative,
131             "4": self.keyNumberRelative,
132             "6": self.keyNumberRelative,
133             "7": self.keyNumberRelative,
134             "9": self.keyNumberRelative,
135             "0": self.keyNumberAbsolute,
136             "2": self.keyNumberAbsolute,
137             "5": self.keyNumberAbsolute,
138             "8": self.keyNumberAbsolute
139         }, -1)
140
141     def __onShow(self):
142         for sAudio in lFileDelay.keys():
143             iDelay = self.AC3delay.getFileDelay(sAudio)
144             self[sAudio + "Slider"].setRange([(self.lowerBound), (self.upperBound)])
145             self[sAudio + "Slider"].setValue(iDelay-self.lowerBound)
146             self[sAudio + "SliderText"].setText(_("%i ms") %iDelay)
147             self.savedValue[sAudio] = iDelay
148             self.currentValue[sAudio] = iDelay
149             if sAudio == self.AC3delay.whichAudio: 
150                 self["AudioSlider"].setRange([(self.lowerBound), (self.upperBound)])
151                 self["AudioSlider"].setValue(iDelay-self.lowerBound)
152                 self["AudioSliderText"].setText(_("%i ms")%iDelay)
153
154     def keyUp(self):
155         self.AC3delay.whichAudio = AC3
156         self.setActiveSlider(AC3)
157
158     def keyDown(self):
159         self.AC3delay.whichAudio = PCM
160         self.setActiveSlider(PCM)
161
162     def setActiveSlider(self,sAudio):
163         if self.AC3delay.whichAudio == AC3:
164             self["AC3DelayText"].setForegroundColorNum(1)
165             self["PCMDelayText"].setForegroundColorNum(0)
166         else:
167             self["AC3DelayText"].setForegroundColorNum(0)
168             self["PCMDelayText"].setForegroundColorNum(1)                        
169         iDelay = self[sAudio+"Slider"].getValue()
170         iCurDelay = iDelay + self.lowerBound
171         self["AudioSlider"].setValue(iDelay)
172         self["AudioSliderText"].setText(_("%i ms")%iCurDelay)
173         self["AudioDelayText"].setText(_("%s delay:")%sAudio)
174
175     def keyLeft(self):
176         self.changeSliderValue(-1 * self.arrowStepSize)
177         
178     def keyRight(self):
179         self.changeSliderValue(self.arrowStepSize)
180
181     def keyNumberAbsolute(self, number):
182         sAudio = self.AC3delay.whichAudio
183         sNumber = str(number)
184         iSliderValue = self.keyStep[sNumber]-self.lowerBound
185         self.setSliderInfo(iSliderValue)
186         self.AC3delay.setFileDelay(sAudio, self.currentValue[sAudio], True)
187
188     def keyNumberRelative(self, number):
189         sNumber = str(number)
190         self.changeSliderValue(self.stepSize[sNumber])
191
192     def changeSliderValue(self,iValue):
193         sAudio = self.AC3delay.whichAudio
194         iSliderValue = int(self[sAudio+"Slider"].getValue())
195         iSliderValue += iValue
196         if iSliderValue < 0:
197             iSliderValue = 0
198         elif iSliderValue > (self.upperBound - self.lowerBound):
199             iSliderValue = (self.upperBound - self.lowerBound)
200         self.setSliderInfo(iSliderValue)
201         self.AC3delay.setFileDelay(sAudio, self.currentValue[sAudio], True)        
202
203     def keyAudioSelection(self):
204         self.audioSelection()
205
206     def keyOk(self):
207         self.close()
208
209     def keyCancel(self):
210         for sAudio in lFileDelay.keys():
211             iSliderValue = self.currentValue[sAudio]
212             if iSliderValue <> self.savedValue[sAudio]:
213                 self.AC3delay.whichAudio = sAudio
214                 self.AC3delay.setFileDelay(sAudio, self.savedValue[sAudio], False)
215         self.close()
216
217     def keyMenu(self):
218         sAudio = self.AC3delay.whichAudio
219         iDelay = self[sAudio+"Slider"].getValue()+self.lowerBound
220         keyList = [
221             (_("Save current %(audio)s delay of %(delay)i ms to key") %dict(audio=sAudio , delay=iDelay),"1")
222         ]
223
224         self.session.openWithCallback(self.DoShowMenu,ChoiceBox,_("Menu"),keyList)
225     
226     def DoShowMenu(self, answer):
227         if answer is not None:
228             if answer[1] == "1":
229                 self.menuSaveDelayToKey()
230             else:
231                 sResponse = _("Invalid selection")
232                 iType = MessageBox.TYPE_ERROR
233                 self.session.open(MessageBox, sResponse , iType)
234                 
235     def menuSaveDelayToKey(self):
236         sAudio = self.AC3delay.whichAudio
237         iDelay = self[sAudio+"Slider"].getValue()+self.lowerBound
238
239         AC3SetCustomValue(self.session,iDelay,self.keyStep)
240         
241     def keySaveToLamedb(self):
242         if self.AC3delay.bIsRecording == False:
243             keyList = [
244                 (_("Save %s delay")%AC3,"1"),
245                 (_("Save %s delay")%PCM,"2"),
246                 (_("Save both delays"),"3")
247             ]
248
249             self.session.openWithCallback(self.DoSaveLamedb,ChoiceBox,_("Which delays do you want to set"),keyList)
250
251     def DoSaveLamedb(self, answer):
252         sNewLine = ""
253         sResponse = ""
254         bOk = True
255         iType = MessageBox.TYPE_INFO
256         aSetAudio = []
257         if answer is not None:
258             if answer[1] in ("1","2","3"):
259                 bSetAC3 = False
260                 bSetPCM = False
261                 self.AC3delay.initAudio()
262                 if self.AC3delay.iAudioDelay is not None:
263                     if answer[1] in ("1","3"):
264                         iDelay = int( self.AC3delay.getLamedbDelay(AC3) )
265                         aSetAudio.append((AC3,iDelay))
266                         bSetAC3 = True
267                     if answer[1] in ("2","3"):
268                         iDelay = int( self.AC3delay.getLamedbDelay(PCM) )
269                         aSetAudio.append((PCM,iDelay))
270                         bSetPCM = True
271                     for vAudio in aSetAudio:
272                         sAudio = vAudio[0]
273                         iChannelDelay = int(vAudio[1])
274                         iCurDelay = self.currentValue[sAudio]
275                         iNewDelay = iCurDelay
276                         if sAudio == AC3:
277                             self.AC3delay.iAudioDelay.setAC3Delay(iNewDelay)
278                         else:
279                             self.AC3delay.iAudioDelay.setPCMDelay(iNewDelay)
280                         self.AC3delay.lamedbDelay[sAudio] = iNewDelay
281                         sResponse = sResponse + sNewLine + _("Saved %(audio)s value: %(delay)i ms") %dict(audio=sAudio,delay=iNewDelay)
282                         sNewLine = "\n"
283                 self.AC3delay.deleteAudio()
284             else:
285                 sResponse = _("Invalid selection")
286                 iType = MessageBox.TYPE_ERROR
287             if bOk == True:
288                 self.session.open(MessageBox, sResponse , iType)
289         self.setChannelInfoText()
290
291     def setSliderInfo(self, iDelay):
292         sAudio = self.AC3delay.whichAudio
293         self.currentValue[sAudio] = iDelay + self.lowerBound
294         iCurDelay = self.currentValue[sAudio]
295         self[sAudio+"Slider"].setValue(iDelay)
296         self[sAudio+"SliderText"].setText(_("%i ms")%iCurDelay)
297         self["AudioSlider"].setValue(iDelay)
298         self["AudioSliderText"].setText(_("%i ms")%iCurDelay)
299
300     def setChannelInfoText(self):
301         sActiveAudio = str(self.AC3delay.selectedAudioInfo[0])
302         sBitstreamDelay = _("%i ms") %self.AC3delay.lamedbDelay[AC3]
303         sPCMDelay = _("%i ms") %self.AC3delay.lamedbDelay[PCM]
304
305         self["ServiceInfo"].setText(sActiveAudio)
306         self["AC3DelayInfo"].setText(sBitstreamDelay)
307         self["PCMDelayInfo"].setText(sPCMDelay)
308
309     def audioSelected(self, audio):
310         InfoBarAudioSelection.audioSelected(self, audio)
311         if audio is not None:
312             self.AC3delay.getAudioInformation()
313             self.setChannelInfoText()
314             self.setActiveSlider(self.AC3delay.whichAudio)
315             
316 class AC3SetCustomValue:
317     def __init__(self, session, iDelay, keyStep):
318         self.keyStep = keyStep
319         self.session = session
320         self.iDelay = iDelay
321         self.session.openWithCallback(self.DoSetCustomValue,ChoiceBox,_("Select the key you want to set to %i ms") %(iDelay),self.getKeyList())
322
323     def getKeyList(self):
324         keyList = []
325         for i,iValue in self.keyStep.iteritems():
326             if i != "0":
327                 keyList.append((_("Key %(key)s (current value: %(value)i ms)") %dict(key=i, value=iValue),i))
328         return keyList
329
330     def DoSetCustomValue(self,answer):
331         if answer is None:
332             self.session.open(MessageBox,_("Setting key canceled"), MessageBox.TYPE_INFO)
333         elif answer[1] in ("2" , "5" , "8"):
334             if answer[1] == "2":
335                 config.plugins.AC3LipSync.absoluteStep2.setValue(self.iDelay)
336                 config.plugins.AC3LipSync.absoluteStep2.save()
337             elif  answer[1] == "5":
338                 config.plugins.AC3LipSync.absoluteStep5.setValue(self.iDelay)
339                 config.plugins.AC3LipSync.absoluteStep5.save()
340             elif  answer[1] == "8":
341                 config.plugins.AC3LipSync.absoluteStep8.setValue(self.iDelay)
342                 config.plugins.AC3LipSync.absoluteStep8.save()
343             self.keyStep[answer[1]] = self.iDelay
344             self.session.open(MessageBox,_("Key %(Key)s successfully set to %(delay)i ms") %dict(Key=answer[1],delay=self.iDelay), MessageBox.TYPE_INFO, 5)
345         else:
346             self.session.open(MessageBox,_("Invalid selection"), MessageBox.TYPE_ERROR, 5)