2 # -*- coding: utf-8 -*-
8 from functools
import partial
10 from PyQt4
.QtCore
import Qt
, QFile
, QIODevice
, QSize
, QTextStream
, QTimer
, SIGNAL
, SLOT
11 from PyQt4
.QtGui
import QDialog
, QDialogButtonBox
, QTableWidgetItem
12 from PyQt4
.QtXml
import QDomDocument
13 from PyKDE4
.kdecore
import i18n
, KUrl
14 from PyKDE4
.kdeui
import KAction
, KIcon
, KMessageBox
, KStandardAction
, KXmlGuiWindow
15 from PyKDE4
.kio
import KFileDialog
16 import shared
, renderw
, tb_main
, tb_apps
, tb_connections
, tb_mixer
, ui_mainw
, ui_dia_studios
20 class KlaudiaMainW(KXmlGuiWindow
, ui_mainw
.Ui_KlaudiaMainW
):
21 def __init__(self
, *args
):
22 KXmlGuiWindow
.__init
__(self
, *args
)
25 # Load a project if an argument is given
26 if (shared
.OpenFolder
):
27 url
= shared
.OpenFolder
28 if (path
.exists(url
+"/project.klaudia")):
31 KMessageBox
.sorry(self
, i18n("The Klaudia project cannot be loaded!"), i18n("Sorry"))
35 if (not shared
.TESTING
):
38 filename
= QFile(shared
.p_folder
+"/project.klaudia")
39 if not filename
.open(QIODevice
.ReadOnly
):
41 if not xml
.setContent(filename
):
45 # Check if project file is not corrupted
46 content
= xml
.documentElement()
47 if (content
.tagName() != "KLAUDIA"):
50 # Get values from XML - the big code
51 node
= content
.firstChild()
52 while not node
.isNull():
53 if (node
.toElement().tagName() == "Properties"):
54 properties
= node
.toElement().firstChild()
55 while not properties
.isNull():
56 name
= properties
.toElement().tagName()
57 text
= properties
.toElement().text()
58 if (name
== "Name"): shared
.p_name
= text
59 elif (name
== "Author"): shared
.p_author
= text
60 elif (name
== "Composer"): shared
.p_composer
= text
61 elif (name
== "Album"): shared
.p_album
= text
62 elif (name
== "Track"): shared
.p_track
= text
63 elif (name
== "BPM"): shared
.p_bpm
= text
64 elif (name
== "Time-Start"): shared
.p_time_start
= text
65 elif (name
== "Time-End"): shared
.p_time_end
= text
66 properties
= properties
.nextSibling()
67 node
= node
.nextSibling()
68 if (node
.toElement().tagName() == "Ladish"):
69 properties
= node
.toElement().firstChild()
70 while not properties
.isNull():
71 name
= properties
.toElement().tagName()
72 text
= properties
.toElement().text()
73 if (name
== "Project-Name"): shared
.ladish_project_name
= text
74 properties
= properties
.nextSibling()
75 node
= node
.nextSibling()
77 if (not shared
.TESTING
):
78 if (str(shared
.ladish_project_name
) != str(shared
.studioBus
.GetName())):
79 print str(shared
.ladish_project_name
)
80 print str(shared
.studioBus
.GetName())
81 shared
.controlBus
.LoadStudio(str(shared
.ladish_project_name
))
82 shared
.jackBus
.StartServer()
83 jack
.attach("Klaudia")
86 self
.spin_bpm
.setValue(float(shared
.p_bpm
))
89 self
.jackTimer
= QTimer()
90 self
.cpuTimer
= QTimer()
91 self
.jackTimer
.start(250)
92 self
.cpuTimer
.start(2000)
95 self
.act_render
= KAction(KIcon("media-record"), i18n("&Render..."), self
)
96 self
.act_export_zip
= KAction(i18n("&Export Project to Zip file..."), self
)
97 self
.act_playpause
= KAction(KIcon("media-playback-start"), i18n("&Play"), self
)
98 self
.act_playpause
.setCheckable(True)
99 self
.act_stop
= KAction(KIcon("media-playback-stop"), i18n("&Stop"), self
)
100 self
.act_backwards
= KAction(KIcon("media-seek-backward"), i18n("&Backwards"), self
)
101 self
.act_forwards
= KAction(KIcon("media-seek-forward"), i18n("&Forwards"), self
)
102 self
.act_bf_16
= KAction(i18n("16"), self
)
103 self
.act_bf_32
= KAction(i18n("32"), self
)
104 self
.act_bf_64
= KAction(i18n("64"), self
)
105 self
.act_bf_128
= KAction(i18n("128"), self
)
106 self
.act_bf_256
= KAction(i18n("256"), self
)
107 self
.act_bf_512
= KAction(i18n("512"), self
)
108 self
.act_bf_1024
= KAction(i18n("1024"), self
)
109 self
.act_bf_2048
= KAction(i18n("2048"), self
)
110 self
.act_bf_4096
= KAction(i18n("4096"), self
)
111 self
.act_import_ladish
= KAction(i18n("Import &Ladish Project..."), self
)
112 self
.act_show_fake_toolbar
= KAction(i18n("Show &Toolbar"), self
)
113 self
.act_show_fake_toolbar
.setCheckable(True)
114 self
.act_show_fake_statusbar
= KAction(i18n("Show St&atusbar"), self
)
115 self
.act_show_fake_statusbar
.setCheckable(True)
117 self
.act_export_zip
.setEnabled(False)
119 self
.act_bf_list
= ( self
.act_bf_16
, self
.act_bf_32
, self
.act_bf_64
, self
.act_bf_128
, self
.act_bf_256
, self
.act_bf_512
,
120 self
.act_bf_1024
, self
.act_bf_2048
, self
.act_bf_4096
)
122 size
= jack
.get_buffer_size()
123 for i
in range(len(self
.act_bf_list
)):
124 self
.act_bf_list
[i
].setCheckable(True)
125 if (self
.act_bf_list
[i
].text().replace("&","") == str(size
)):
126 self
.act_bf_list
[i
].setChecked(True)
129 self
.act_show_fake_toolbar
.setChecked(setting_tbV
)
130 self
.toolbarW
.setVisible(setting_tbV
)
133 self
.act_show_fake_statusbar
.setChecked(setting_sbV
)
134 self
.statusbarW
.setVisible(setting_sbV
)
137 KStandardAction
.open(self
.NIY
, self
.actionCollection())
138 KStandardAction
.openRecent(self
.NIY
, self
.actionCollection())
139 KStandardAction
.save(self
.saveProject
, self
.actionCollection())
140 KStandardAction
.saveAs(self
.saveAs
, self
.actionCollection())
141 KStandardAction
.close(self
.close
, self
.actionCollection())
142 KStandardAction
.preferences(self
.NIY
, self
.actionCollection())
145 self
.actionCollection().addAction("render", self
.act_render
)
146 self
.actionCollection().addAction("export_zip", self
.act_export_zip
)
147 self
.actionCollection().addAction("tr_play", self
.act_playpause
)
148 self
.actionCollection().addAction("tr_stop", self
.act_stop
)
149 self
.actionCollection().addAction("tr_back", self
.act_backwards
)
150 self
.actionCollection().addAction("tr_next", self
.act_forwards
)
151 self
.actionCollection().addAction("bf_16", self
.act_bf_16
)
152 self
.actionCollection().addAction("bf_32", self
.act_bf_32
)
153 self
.actionCollection().addAction("bf_64", self
.act_bf_64
)
154 self
.actionCollection().addAction("bf_128", self
.act_bf_128
)
155 self
.actionCollection().addAction("bf_256", self
.act_bf_256
)
156 self
.actionCollection().addAction("bf_512", self
.act_bf_512
)
157 self
.actionCollection().addAction("bf_1024", self
.act_bf_1024
)
158 self
.actionCollection().addAction("bf_2048", self
.act_bf_2048
)
159 self
.actionCollection().addAction("bf_4096", self
.act_bf_4096
)
160 self
.actionCollection().addAction("import_ladish", self
.act_import_ladish
)
161 self
.actionCollection().addAction("show_fake_toolbar", self
.act_show_fake_toolbar
)
162 self
.actionCollection().addAction("show_fake_statusbar", self
.act_show_fake_statusbar
)
165 self
.b_playpause
.setIcon(KIcon("media-playback-start"))
166 self
.b_stop
.setIcon(KIcon("media-playback-stop"))
167 self
.b_backwards
.setIcon(KIcon("media-seek-backward"))
168 self
.b_forwards
.setIcon(KIcon("media-seek-forward"))
169 self
.b_open
.setIcon(KIcon("document-open"))
170 self
.b_save
.setIcon(KIcon("document-save"))
171 self
.b_save_as
.setIcon(KIcon("document-save-as"))
172 self
.b_render
.setIcon(KIcon("media-record"))
173 self
.b_add_new
.setIcon(KIcon("list-add"))
175 # Interact actions to buttons
176 self
.connect(self
.act_playpause
, SIGNAL("triggered(bool)"), self
.b_playpause
, SLOT("setChecked(bool)"))
177 self
.connect(self
.b_playpause
, SIGNAL("clicked(bool)"), self
.act_playpause
, SLOT("setChecked(bool)"))
179 # Custom toolbar and statusbar
180 self
.connect(self
.act_show_fake_toolbar
, SIGNAL("triggered(bool)"), self
.toolbarW
, SLOT("setVisible(bool)"))
181 self
.connect(self
.act_show_fake_statusbar
, SIGNAL("triggered(bool)"), self
.statusbarW
, SLOT("setVisible(bool)"))
183 # Connect actions to functions
184 self
.connect(self
.act_render
, SIGNAL("triggered()"), self
.renderW
)
185 self
.connect(self
.act_playpause
, SIGNAL("triggered(bool)"), self
.jackPlayPause
)
186 self
.connect(self
.act_stop
, SIGNAL("triggered()"), self
.jackStop
)
187 self
.connect(self
.act_backwards
, SIGNAL("triggered()"), self
.jackBackwards
)
188 self
.connect(self
.act_forwards
, SIGNAL("triggered()"), self
.jackForwards
)
189 self
.connect(self
.act_bf_16
, SIGNAL("triggered()"), partial(self
.setBufferSize
, 16))
190 self
.connect(self
.act_bf_32
, SIGNAL("triggered()"), partial(self
.setBufferSize
, 32))
191 self
.connect(self
.act_bf_64
, SIGNAL("triggered()"), partial(self
.setBufferSize
, 64))
192 self
.connect(self
.act_bf_128
, SIGNAL("triggered()"), partial(self
.setBufferSize
, 128))
193 self
.connect(self
.act_bf_256
, SIGNAL("triggered()"), partial(self
.setBufferSize
, 256))
194 self
.connect(self
.act_bf_512
, SIGNAL("triggered()"), partial(self
.setBufferSize
, 512))
195 self
.connect(self
.act_bf_1024
, SIGNAL("triggered()"), partial(self
.setBufferSize
, 1024))
196 self
.connect(self
.act_bf_2048
, SIGNAL("triggered()"), partial(self
.setBufferSize
, 2048))
197 self
.connect(self
.act_bf_4096
, SIGNAL("triggered()"), partial(self
.setBufferSize
, 4096))
198 self
.connect(self
.act_import_ladish
, SIGNAL("triggered()"), self
.importLadishStudio
)
200 # Connect tab-buttons to pages
201 self
.connect(self
.tb_main
, SIGNAL("clicked()"), partial(self
.changeTabButton
, "main"))
202 self
.connect(self
.tb_apps
, SIGNAL("clicked()"), partial(self
.changeTabButton
, "apps"))
203 self
.connect(self
.tb_connections
, SIGNAL("clicked()"), partial(self
.changeTabButton
, "connections"))
204 self
.connect(self
.tb_mixer
, SIGNAL("clicked()"), partial(self
.changeTabButton
, "mixer"))
206 # Connect buttons to functions
207 self
.connect(self
.b_playpause
, SIGNAL("clicked(bool)"), self
.jackPlayPause
)
208 self
.connect(self
.b_stop
, SIGNAL("clicked()"), self
.jackStop
)
209 self
.connect(self
.b_backwards
, SIGNAL("clicked()"), self
.jackBackwards
)
210 self
.connect(self
.b_forwards
, SIGNAL("clicked()"), self
.jackForwards
)
211 self
.connect(self
.b_open
, SIGNAL("clicked()"), self
.NIY
)
212 self
.connect(self
.b_save
, SIGNAL("clicked()"), self
.saveProject
)
213 self
.connect(self
.b_save_as
, SIGNAL("clicked()"), self
.saveAs
)
214 self
.connect(self
.b_render
, SIGNAL("clicked()"), self
.renderW
)
215 self
.connect(self
.b_add_new
, SIGNAL("clicked()"), self
.addCustom
)
217 # Connect other stuff
218 self
.connect(self
.cpuTimer
, SIGNAL("timeout()"), self
.updateDSPLoad
)
219 self
.connect(self
.jackTimer
, SIGNAL("timeout()"), self
.updateTransport
)
220 self
.connect(self
.transportSlider
, SIGNAL("sliderReleased()"), self
.updateSlider
)
223 # Set-up the GUI (Part 1, create the KDE stuff)
224 self
.setupGUI(QSize(600, 400), KXmlGuiWindow
.Default
, shared
.Path
+"/klaudia.rc")
226 # Set-up the GUI (Part 2, set custom menu, tool-bar and status-bar)
227 self
.menuLayout
.addWidget(self
.menuBar())
228 self
.toolBar().deleteLater()
229 self
.statusBar().setVisible(False)
230 self
.actionCollection().action(u
'options_configure_toolbars').setVisible(False)
231 self
.actionCollection().action(u
'options_show_statusbar').setVisible(False)
232 self
.connect(self
.statusBar(), SIGNAL("messageChanged(QString)"), self
.sbW_msg_label
, SLOT("setText(QString)"))
234 # Set-up the GUI (Part 3, Load pages)
235 self
.w_main
= tb_main
.MainW()
236 self
.w_apps
= tb_apps
.AppsW()
237 self
.w_connections
= tb_connections
.ConnectionsW()
238 self
.w_mixer
= tb_mixer
.MixerW()
239 #self.w_main.setVisible(False)
240 self
.w_apps
.setVisible(False)
241 self
.w_connections
.setVisible(False)
242 self
.w_mixer
.setVisible(False)
244 # Set-up the GUI (Part 4, set default page)
245 self
.w_main
.setVisible(True)
246 self
.centralW
.layout().addWidget(self
.w_main
)
247 self
.tb_main
.setChecked(True)
248 self
.currentTabPage
= "main"
250 # Set-up the GUI (Part 5, update variables)
251 self
.updateJackVars()
253 self
.updateTransport()
257 KMessageBox
.sorry(self
, i18n("NOT IMPLEMENTED YET"), i18n("Sorry"))
260 tb_main
.NewAppW().exec_()
262 def saveProject(self
):
263 url
= shared
.p_folder
264 filename
= QFile(url
+"/project.klaudia")
265 if not filename
.open(QIODevice
.WriteOnly
):
266 KMessageBox
.error(self
, i18n("Cannot write to selected directory - Permission Denied"), i18n("Error"))
269 #raise IOError, unicode(filename.errorString())
270 stream
= QTextStream(filename
)
271 stream
.setCodec("UTF-8")
272 stream
<< ("<?xml version='1.0' encoding='UTF-8'?>\n"
273 "<!DOCTYPE KLAUDIA>\n"
274 "<KLAUDIA VERSION='0.1'>\n"
277 " <Author>%s</Author>\n"
278 " <Composer>%s</Composer>\n"
279 " <Album>%s</Album>\n"
280 " <Track>%s</Track>\n"
282 " <Time-Start>%s</Time-Start>\n"
283 " <Time-End>%s</Time-End>\n"
286 " <Project-Name>%s</Project-Name>\n"
288 "</KLAUDIA>\n" % (shared
.p_name
, shared
.p_author
, shared
.p_composer
,
289 shared
.p_album
, shared
.p_track
, shared
.p_bpm
, shared
.p_time_start
, shared
.p_time_end
, shared
.ladish_project_name
))
290 iconfile
= open(url
+"/.directory", "w")
291 iconfile
.write("[Desktop Entry]\nIcon=%s\n" % shared
.p_icon
)
293 shared
.studioBus
.Save()
296 pUrl
= KFileDialog
.getExistingDirectoryUrl(KUrl(shared
.p_folder
), self
, i18n("Open Klaudia Project Folder"))
297 if not pUrl
.fileName():
299 elif not pUrl
.isLocalFile():
300 KMessageBox
.error(self
, i18n("The Selected folder cannot be used for a Klaudia project!"), i18n("Error"))
302 shared
.p_folder
= str(pUrl
.toLocalFile())
305 def jackPlayPause(self
, play
):
307 jack
.transport_start()
308 self
.act_playpause
.setText("&Pause")
309 self
.act_playpause
.setIcon(KIcon("media-playback-pause"))
310 self
.b_playpause
.setIcon(KIcon("media-playback-pause"))
312 jack
.transport_stop()
313 self
.act_playpause
.setText("&Play")
314 self
.act_playpause
.setIcon(KIcon("media-playback-start"))
315 self
.b_playpause
.setIcon(KIcon("media-playback-start"))
318 self
.jackPlayPause(False)
319 self
.b_playpause
.setChecked(False)
320 jack
.transport_locate(0)
321 #jack.transport_locate(shared.Globals.sliderMinValue*jack.get_sample_rate())
323 def jackBackwards(self
):
324 pos
= int(jack
.get_current_transport_frame()) - 100000
326 jack
.transport_locate(0)
328 jack
.transport_locate(pos
)
330 def jackForwards(self
):
331 jack
.transport_locate(jack
.get_current_transport_frame()+100000)
333 def setBufferSize(self
, size
):
334 jack
.set_buffer_size(size
)
336 for i
in range(len(self
.act_bf_list
)):
337 if (self
.act_bf_list
[i
].text().replace("&","") == str(size
)):
338 self
.act_bf_list
[i
].setChecked(True)
340 self
.act_bf_list
[i
].setChecked(False)
342 def changeTabButton(self
, button
):
343 if (button
!= self
.currentTabPage
):
344 self
.currentTabPage
= button
345 # Remove central widget
346 self
.centralW
.layout().takeAt(0)
347 # Restore all button states
348 self
.tb_main
.setChecked(False)
349 self
.tb_apps
.setChecked(False)
350 self
.tb_connections
.setChecked(False)
351 self
.tb_mixer
.setChecked(False)
352 # Hide all pages (we only need one)
353 self
.w_main
.setVisible(False)
354 self
.w_apps
.setVisible(False)
355 self
.w_connections
.setVisible(False)
356 self
.w_mixer
.setVisible(False)
357 if (button
== "main"):
358 self
.tb_main
.setChecked(True)
359 wToLoad
= self
.w_main
360 elif (button
== "apps"):
361 self
.tb_apps
.setChecked(True)
362 wToLoad
= self
.w_apps
363 elif (button
== "connections"):
364 self
.tb_connections
.setChecked(True)
365 wToLoad
= self
.w_connections
366 elif (button
== "mixer"):
367 self
.tb_mixer
.setChecked(True)
368 wToLoad
= self
.w_mixer
369 self
.centralW
.layout().addWidget(wToLoad
)
370 wToLoad
.setVisible(True)
372 if (button
== "main"): self
.tb_main
.setChecked(True)
373 elif (button
== "apps"): self
.tb_apps
.setChecked(True)
374 elif (button
== "connections"): self
.tb_connections
.setChecked(True)
375 elif (button
== "mixer"): self
.tb_mixer
.setChecked(True)
378 def updateTransport(self
):
379 state
= jack
.get_transport_state()
380 frame
= jack
.get_current_transport_frame()
381 rate
= jack
.get_sample_rate()
385 self
.b_playpause
.setChecked(False)
386 self
.act_playpause
.setText("&Play")
387 self
.act_playpause
.setIcon(KIcon("media-playback-start"))
388 self
.b_playpause
.setIcon(KIcon("media-playback-start"))
389 elif (state
== 1 or state
== 2):
390 self
.b_playpause
.setChecked(True)
391 self
.act_playpause
.setText("&Pause")
392 self
.act_playpause
.setIcon(KIcon("media-playback-pause"))
393 self
.b_playpause
.setIcon(KIcon("media-playback-pause"))
398 mins
= (time
/ 60) % 60
399 hrs
= (time
/ 3600) % 60
400 secH
= minH
= hrsH
= ""
401 if secs
< 10: secH
= "0"
402 if mins
< 10: minH
= "0"
403 if hrs
< 10: hrsH
= "0"
404 self
.l_time
.setText(hrsH
+str(hrs
)+":"+minH
+str(mins
)+":"+secH
+str(secs
))
407 if not self
.transportSlider
.isSliderDown():
408 self
.transportSlider
.setMinimum(shared
.Globals
.sliderMinValue
)
409 self
.transportSlider
.setMaximum(shared
.Globals
.sliderMaxValue
)
410 self
.transportSlider
.setValue(time
)
412 def updateDSPLoad(self
):
413 load
= int(jack
.get_cpu_load())
414 self
.sbW_cpu_bar
.setValue(load
)
416 def updateSlider(self
):
417 value
= self
.transportSlider
.value()
418 jack
.transport_locate(value
*jack
.get_sample_rate())
420 def updateJackVars(self
):
421 self
.sbW_jack_SampleRate
.setText(str(jack
.get_sample_rate())+" Hz")
422 self
.sbW_jack_BufferSize
.setText(str(jack
.get_buffer_size()))
423 if (jack
.is_realtime()):
424 self
.sbW_jack_RT
.setText("RT")
426 self
.sbW_jack_RT
.setText("")
428 def updateSizes(self
):
429 self
.sbW_msg
.setMinimumSize(self
.width()/4, 16)
430 self
.sbW_msg
.setMaximumSize(self
.width()/4, 16)
431 self
.sbW_jack
.setMaximumSize(self
.width()/3, 16)
432 self
.sbW_cpu
.setMaximumSize(self
.width()/4, 16)
433 self
.sbW_drops
.setMaximumSize(self
.width()/8, 16)
435 def resizeEvent(self
, event
):
439 renderw
.KlaudiaRenderW().exec_()
441 def importLadishStudio(self
):
445 class StudiosW(QDialog
, ui_dia_studios
.Ui_StudiosW
):
446 def __init__(self
, *args
):
447 QDialog
.__init
__(self
, *args
)
450 self
.buttonBox
.button(QDialogButtonBox
.Ok
).setEnabled(False)
451 self
.listStudio
.setColumnWidth(0, 200)
453 self
.connect(self
, SIGNAL("accepted()"), self
.Done
)
454 self
.connect(self
.listStudio
, SIGNAL("currentCellChanged(int, int, int, int)"), self
.checkOkButton
)
456 list_of_ladish_studios
= shared
.controlBus
.GetStudioList()
457 for i
in range(len(list_of_ladish_studios
)):
458 name
= QTableWidgetItem(str(list_of_ladish_studios
[i
][0]))
459 time
= QTableWidgetItem(ctime(float(list_of_ladish_studios
[i
][1][u
'Modification Time'])))
460 self
.listStudio
.insertRow(i
)
461 self
.listStudio
.setItem(i
, 0, name
)
462 self
.listStudio
.setItem(i
, 1, time
)
464 self
.listStudio
.sortByColumn(0, Qt
.AscendingOrder
)
468 shared
.controlBus
.LoadStudio(str(self
.listStudio
.item(self
.listStudio
.currentRow(), 0).text()))
469 shared
.jackBus
.StartServer()
470 jack
.attach("Klaudia")
472 def checkOkButton(self
, row
, b
, c
, d
):
474 self
.buttonBox
.button(QDialogButtonBox
.Ok
).setEnabled(False)
476 self
.buttonBox
.button(QDialogButtonBox
.Ok
).setEnabled(True)