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 if (not bool(shared
.jackBus
.IsStarted())):
84 shared
.jackBus
.StartServer()
85 jack
.attach("Klaudia")
88 self
.spin_bpm
.setValue(float(shared
.p_bpm
))
91 self
.jackTimer
= QTimer()
92 self
.cpuTimer
= QTimer()
93 self
.jackTimer
.start(250)
94 self
.cpuTimer
.start(2000)
97 self
.act_render
= KAction(KIcon("media-record"), i18n("&Render..."), self
)
98 self
.act_export_zip
= KAction(i18n("&Export Project to Zip file..."), self
)
99 self
.act_playpause
= KAction(KIcon("media-playback-start"), i18n("&Play"), self
)
100 self
.act_playpause
.setCheckable(True)
101 self
.act_stop
= KAction(KIcon("media-playback-stop"), i18n("&Stop"), self
)
102 self
.act_backwards
= KAction(KIcon("media-seek-backward"), i18n("&Backwards"), self
)
103 self
.act_forwards
= KAction(KIcon("media-seek-forward"), i18n("&Forwards"), self
)
104 self
.act_bf_16
= KAction(i18n("16"), self
)
105 self
.act_bf_32
= KAction(i18n("32"), self
)
106 self
.act_bf_64
= KAction(i18n("64"), self
)
107 self
.act_bf_128
= KAction(i18n("128"), self
)
108 self
.act_bf_256
= KAction(i18n("256"), self
)
109 self
.act_bf_512
= KAction(i18n("512"), self
)
110 self
.act_bf_1024
= KAction(i18n("1024"), self
)
111 self
.act_bf_2048
= KAction(i18n("2048"), self
)
112 self
.act_bf_4096
= KAction(i18n("4096"), self
)
113 self
.act_import_ladish
= KAction(i18n("Import &Ladish Project..."), self
)
114 self
.act_show_fake_toolbar
= KAction(i18n("Show &Toolbar"), self
)
115 self
.act_show_fake_toolbar
.setCheckable(True)
116 self
.act_show_fake_statusbar
= KAction(i18n("Show St&atusbar"), self
)
117 self
.act_show_fake_statusbar
.setCheckable(True)
119 self
.act_export_zip
.setEnabled(False)
121 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
,
122 self
.act_bf_1024
, self
.act_bf_2048
, self
.act_bf_4096
)
124 size
= jack
.get_buffer_size()
125 for i
in range(len(self
.act_bf_list
)):
126 self
.act_bf_list
[i
].setCheckable(True)
127 if (self
.act_bf_list
[i
].text().replace("&","") == str(size
)):
128 self
.act_bf_list
[i
].setChecked(True)
131 self
.act_show_fake_toolbar
.setChecked(setting_tbV
)
132 self
.toolbarW
.setVisible(setting_tbV
)
135 self
.act_show_fake_statusbar
.setChecked(setting_sbV
)
136 self
.statusbarW
.setVisible(setting_sbV
)
139 KStandardAction
.open(self
.NIY
, self
.actionCollection())
140 KStandardAction
.openRecent(self
.NIY
, self
.actionCollection())
141 KStandardAction
.save(self
.saveProject
, self
.actionCollection())
142 KStandardAction
.saveAs(self
.saveAs
, self
.actionCollection())
143 KStandardAction
.close(self
.close
, self
.actionCollection())
144 KStandardAction
.preferences(self
.NIY
, self
.actionCollection())
147 self
.actionCollection().addAction("render", self
.act_render
)
148 self
.actionCollection().addAction("export_zip", self
.act_export_zip
)
149 self
.actionCollection().addAction("tr_play", self
.act_playpause
)
150 self
.actionCollection().addAction("tr_stop", self
.act_stop
)
151 self
.actionCollection().addAction("tr_back", self
.act_backwards
)
152 self
.actionCollection().addAction("tr_next", self
.act_forwards
)
153 self
.actionCollection().addAction("bf_16", self
.act_bf_16
)
154 self
.actionCollection().addAction("bf_32", self
.act_bf_32
)
155 self
.actionCollection().addAction("bf_64", self
.act_bf_64
)
156 self
.actionCollection().addAction("bf_128", self
.act_bf_128
)
157 self
.actionCollection().addAction("bf_256", self
.act_bf_256
)
158 self
.actionCollection().addAction("bf_512", self
.act_bf_512
)
159 self
.actionCollection().addAction("bf_1024", self
.act_bf_1024
)
160 self
.actionCollection().addAction("bf_2048", self
.act_bf_2048
)
161 self
.actionCollection().addAction("bf_4096", self
.act_bf_4096
)
162 self
.actionCollection().addAction("import_ladish", self
.act_import_ladish
)
163 self
.actionCollection().addAction("show_fake_toolbar", self
.act_show_fake_toolbar
)
164 self
.actionCollection().addAction("show_fake_statusbar", self
.act_show_fake_statusbar
)
167 self
.b_playpause
.setIcon(KIcon("media-playback-start"))
168 self
.b_stop
.setIcon(KIcon("media-playback-stop"))
169 self
.b_backwards
.setIcon(KIcon("media-seek-backward"))
170 self
.b_forwards
.setIcon(KIcon("media-seek-forward"))
171 self
.b_open
.setIcon(KIcon("document-open"))
172 self
.b_save
.setIcon(KIcon("document-save"))
173 self
.b_save_as
.setIcon(KIcon("document-save-as"))
174 self
.b_render
.setIcon(KIcon("media-record"))
175 self
.b_add_new
.setIcon(KIcon("list-add"))
177 # Interact actions to buttons
178 self
.connect(self
.act_playpause
, SIGNAL("triggered(bool)"), self
.b_playpause
, SLOT("setChecked(bool)"))
179 self
.connect(self
.b_playpause
, SIGNAL("clicked(bool)"), self
.act_playpause
, SLOT("setChecked(bool)"))
181 # Custom toolbar and statusbar
182 self
.connect(self
.act_show_fake_toolbar
, SIGNAL("triggered(bool)"), self
.toolbarW
, SLOT("setVisible(bool)"))
183 self
.connect(self
.act_show_fake_statusbar
, SIGNAL("triggered(bool)"), self
.statusbarW
, SLOT("setVisible(bool)"))
185 # Connect actions to functions
186 self
.connect(self
.act_render
, SIGNAL("triggered()"), self
.renderW
)
187 self
.connect(self
.act_playpause
, SIGNAL("triggered(bool)"), self
.jackPlayPause
)
188 self
.connect(self
.act_stop
, SIGNAL("triggered()"), self
.jackStop
)
189 self
.connect(self
.act_backwards
, SIGNAL("triggered()"), self
.jackBackwards
)
190 self
.connect(self
.act_forwards
, SIGNAL("triggered()"), self
.jackForwards
)
191 self
.connect(self
.act_bf_16
, SIGNAL("triggered()"), partial(self
.setBufferSize
, 16))
192 self
.connect(self
.act_bf_32
, SIGNAL("triggered()"), partial(self
.setBufferSize
, 32))
193 self
.connect(self
.act_bf_64
, SIGNAL("triggered()"), partial(self
.setBufferSize
, 64))
194 self
.connect(self
.act_bf_128
, SIGNAL("triggered()"), partial(self
.setBufferSize
, 128))
195 self
.connect(self
.act_bf_256
, SIGNAL("triggered()"), partial(self
.setBufferSize
, 256))
196 self
.connect(self
.act_bf_512
, SIGNAL("triggered()"), partial(self
.setBufferSize
, 512))
197 self
.connect(self
.act_bf_1024
, SIGNAL("triggered()"), partial(self
.setBufferSize
, 1024))
198 self
.connect(self
.act_bf_2048
, SIGNAL("triggered()"), partial(self
.setBufferSize
, 2048))
199 self
.connect(self
.act_bf_4096
, SIGNAL("triggered()"), partial(self
.setBufferSize
, 4096))
200 self
.connect(self
.act_import_ladish
, SIGNAL("triggered()"), self
.importLadishStudio
)
202 # Connect tab-buttons to pages
203 self
.connect(self
.tb_main
, SIGNAL("clicked()"), partial(self
.changeTabButton
, "main"))
204 self
.connect(self
.tb_apps
, SIGNAL("clicked()"), partial(self
.changeTabButton
, "apps"))
205 self
.connect(self
.tb_connections
, SIGNAL("clicked()"), partial(self
.changeTabButton
, "connections"))
206 self
.connect(self
.tb_mixer
, SIGNAL("clicked()"), partial(self
.changeTabButton
, "mixer"))
208 # Connect buttons to functions
209 self
.connect(self
.b_playpause
, SIGNAL("clicked(bool)"), self
.jackPlayPause
)
210 self
.connect(self
.b_stop
, SIGNAL("clicked()"), self
.jackStop
)
211 self
.connect(self
.b_backwards
, SIGNAL("clicked()"), self
.jackBackwards
)
212 self
.connect(self
.b_forwards
, SIGNAL("clicked()"), self
.jackForwards
)
213 self
.connect(self
.b_open
, SIGNAL("clicked()"), self
.NIY
)
214 self
.connect(self
.b_save
, SIGNAL("clicked()"), self
.saveProject
)
215 self
.connect(self
.b_save_as
, SIGNAL("clicked()"), self
.saveAs
)
216 self
.connect(self
.b_render
, SIGNAL("clicked()"), self
.renderW
)
217 self
.connect(self
.b_add_new
, SIGNAL("clicked()"), self
.addCustom
)
219 # Connect other stuff
220 self
.connect(self
.cpuTimer
, SIGNAL("timeout()"), self
.updateDSPLoad
)
221 self
.connect(self
.jackTimer
, SIGNAL("timeout()"), self
.updateTransport
)
222 self
.connect(self
.transportSlider
, SIGNAL("sliderReleased()"), self
.updateSlider
)
225 # Set-up the GUI (Part 1, create the KDE stuff)
226 self
.setupGUI(QSize(600, 400), KXmlGuiWindow
.Default
, shared
.Path
+"/klaudia.rc")
228 # Set-up the GUI (Part 2, set custom menu, tool-bar and status-bar)
229 self
.menuLayout
.addWidget(self
.menuBar())
230 self
.toolBar().deleteLater()
231 self
.statusBar().setVisible(False)
232 self
.actionCollection().action(u
'options_configure_toolbars').setVisible(False)
233 self
.actionCollection().action(u
'options_show_statusbar').setVisible(False)
234 self
.connect(self
.statusBar(), SIGNAL("messageChanged(QString)"), self
.sbW_msg_label
, SLOT("setText(QString)"))
236 # Set-up the GUI (Part 3, Load pages)
237 self
.w_main
= tb_main
.MainW()
238 self
.w_apps
= tb_apps
.AppsW()
239 self
.w_connections
= tb_connections
.ConnectionsW()
240 self
.w_mixer
= tb_mixer
.MixerW()
241 #self.w_main.setVisible(False)
242 self
.w_apps
.setVisible(False)
243 self
.w_connections
.setVisible(False)
244 self
.w_mixer
.setVisible(False)
246 # Set-up the GUI (Part 4, set default page)
247 self
.w_main
.setVisible(True)
248 self
.centralW
.layout().addWidget(self
.w_main
)
249 self
.tb_main
.setChecked(True)
250 self
.currentTabPage
= "main"
252 # Set-up the GUI (Part 5, update variables)
253 self
.updateJackVars()
255 self
.updateTransport()
259 KMessageBox
.sorry(self
, i18n("NOT IMPLEMENTED YET"), i18n("Sorry"))
262 tb_main
.NewAppW().exec_()
264 def saveProject(self
):
265 url
= shared
.p_folder
266 filename
= QFile(url
+"/project.klaudia")
267 if not filename
.open(QIODevice
.WriteOnly
):
268 KMessageBox
.error(self
, i18n("Cannot write to selected directory - Permission Denied"), i18n("Error"))
271 #raise IOError, unicode(filename.errorString())
272 stream
= QTextStream(filename
)
273 stream
.setCodec("UTF-8")
274 stream
<< ("<?xml version='1.0' encoding='UTF-8'?>\n"
275 "<!DOCTYPE KLAUDIA>\n"
276 "<KLAUDIA VERSION='0.1'>\n"
279 " <Author>%s</Author>\n"
280 " <Composer>%s</Composer>\n"
281 " <Album>%s</Album>\n"
282 " <Track>%s</Track>\n"
284 " <Time-Start>%s</Time-Start>\n"
285 " <Time-End>%s</Time-End>\n"
288 " <Project-Name>%s</Project-Name>\n"
290 "</KLAUDIA>\n" % (shared
.p_name
, shared
.p_author
, shared
.p_composer
,
291 shared
.p_album
, shared
.p_track
, shared
.p_bpm
, shared
.p_time_start
, shared
.p_time_end
, shared
.ladish_project_name
))
292 iconfile
= open(url
+"/.directory", "w")
293 iconfile
.write("[Desktop Entry]\nIcon=%s\n" % shared
.p_icon
)
295 shared
.studioBus
.Save()
298 pUrl
= KFileDialog
.getExistingDirectoryUrl(KUrl(shared
.p_folder
), self
, i18n("Open Klaudia Project Folder"))
299 if not pUrl
.fileName():
301 elif not pUrl
.isLocalFile():
302 KMessageBox
.error(self
, i18n("The Selected folder cannot be used for a Klaudia project!"), i18n("Error"))
304 shared
.p_folder
= str(pUrl
.toLocalFile())
307 def jackPlayPause(self
, play
):
309 jack
.transport_start()
310 self
.act_playpause
.setText("&Pause")
311 self
.act_playpause
.setIcon(KIcon("media-playback-pause"))
312 self
.b_playpause
.setIcon(KIcon("media-playback-pause"))
314 jack
.transport_stop()
315 self
.act_playpause
.setText("&Play")
316 self
.act_playpause
.setIcon(KIcon("media-playback-start"))
317 self
.b_playpause
.setIcon(KIcon("media-playback-start"))
320 self
.jackPlayPause(False)
321 self
.b_playpause
.setChecked(False)
322 jack
.transport_locate(0)
323 #jack.transport_locate(shared.Globals.sliderMinValue*jack.get_sample_rate())
325 def jackBackwards(self
):
326 pos
= int(jack
.get_current_transport_frame()) - 100000
328 jack
.transport_locate(0)
330 jack
.transport_locate(pos
)
332 def jackForwards(self
):
333 jack
.transport_locate(jack
.get_current_transport_frame()+100000)
335 def setBufferSize(self
, size
):
336 jack
.set_buffer_size(size
)
337 for i
in range(len(self
.act_bf_list
)):
338 if (self
.act_bf_list
[i
].text().replace("&","") == str(size
)):
339 self
.act_bf_list
[i
].setChecked(True)
341 self
.act_bf_list
[i
].setChecked(False)
343 def changeTabButton(self
, button
):
344 if (button
!= self
.currentTabPage
):
345 self
.currentTabPage
= button
346 # Remove central widget
347 self
.centralW
.layout().takeAt(0)
348 # Restore all button states
349 self
.tb_main
.setChecked(False)
350 self
.tb_apps
.setChecked(False)
351 self
.tb_connections
.setChecked(False)
352 self
.tb_mixer
.setChecked(False)
353 # Hide all pages (we only need one)
354 self
.w_main
.setVisible(False)
355 self
.w_apps
.setVisible(False)
356 self
.w_connections
.setVisible(False)
357 self
.w_mixer
.setVisible(False)
358 if (button
== "main"):
359 self
.tb_main
.setChecked(True)
360 wToLoad
= self
.w_main
361 elif (button
== "apps"):
362 self
.tb_apps
.setChecked(True)
363 wToLoad
= self
.w_apps
364 elif (button
== "connections"):
365 self
.tb_connections
.setChecked(True)
366 wToLoad
= self
.w_connections
367 elif (button
== "mixer"):
368 self
.tb_mixer
.setChecked(True)
369 wToLoad
= self
.w_mixer
370 self
.centralW
.layout().addWidget(wToLoad
)
371 wToLoad
.setVisible(True)
373 if (button
== "main"): self
.tb_main
.setChecked(True)
374 elif (button
== "apps"): self
.tb_apps
.setChecked(True)
375 elif (button
== "connections"): self
.tb_connections
.setChecked(True)
376 elif (button
== "mixer"): self
.tb_mixer
.setChecked(True)
379 def updateTransport(self
):
380 state
= jack
.get_transport_state()
381 frame
= jack
.get_current_transport_frame()
382 rate
= jack
.get_sample_rate()
386 self
.b_playpause
.setChecked(False)
387 self
.act_playpause
.setText("&Play")
388 self
.act_playpause
.setIcon(KIcon("media-playback-start"))
389 self
.b_playpause
.setIcon(KIcon("media-playback-start"))
390 elif (state
== 1 or state
== 2):
391 self
.b_playpause
.setChecked(True)
392 self
.act_playpause
.setText("&Pause")
393 self
.act_playpause
.setIcon(KIcon("media-playback-pause"))
394 self
.b_playpause
.setIcon(KIcon("media-playback-pause"))
399 mins
= (time
/ 60) % 60
400 hrs
= (time
/ 3600) % 60
401 secH
= minH
= hrsH
= ""
402 if secs
< 10: secH
= "0"
403 if mins
< 10: minH
= "0"
404 if hrs
< 10: hrsH
= "0"
405 self
.l_time
.setText(hrsH
+str(hrs
)+":"+minH
+str(mins
)+":"+secH
+str(secs
))
408 if not self
.transportSlider
.isSliderDown():
409 self
.transportSlider
.setMinimum(shared
.Globals
.sliderMinValue
)
410 self
.transportSlider
.setMaximum(shared
.Globals
.sliderMaxValue
)
411 self
.transportSlider
.setValue(time
)
413 def updateDSPLoad(self
):
414 load
= int(jack
.get_cpu_load())
415 self
.sbW_cpu_bar
.setValue(load
)
417 def updateSlider(self
):
418 value
= self
.transportSlider
.value()
419 jack
.transport_locate(value
*jack
.get_sample_rate())
421 def updateJackVars(self
):
422 self
.sbW_jack_SampleRate
.setText(str(jack
.get_sample_rate())+" Hz")
423 self
.sbW_jack_BufferSize
.setText(str(jack
.get_buffer_size()))
424 if (jack
.is_realtime()):
425 self
.sbW_jack_RT
.setText("RT")
427 self
.sbW_jack_RT
.setText("")
429 def updateSizes(self
):
430 self
.sbW_msg
.setMinimumSize(self
.width()/4, 16)
431 self
.sbW_msg
.setMaximumSize(self
.width()/4, 16)
432 self
.sbW_jack
.setMaximumSize(self
.width()/3, 16)
433 self
.sbW_cpu
.setMaximumSize(self
.width()/4, 16)
434 self
.sbW_drops
.setMaximumSize(self
.width()/8, 16)
436 def resizeEvent(self
, event
):
440 renderw
.KlaudiaRenderW().exec_()
442 def importLadishStudio(self
):
446 class StudiosW(QDialog
, ui_dia_studios
.Ui_StudiosW
):
447 def __init__(self
, *args
):
448 QDialog
.__init
__(self
, *args
)
451 self
.buttonBox
.button(QDialogButtonBox
.Ok
).setEnabled(False)
452 self
.listStudio
.setColumnWidth(0, 200)
454 self
.connect(self
, SIGNAL("accepted()"), self
.Done
)
455 self
.connect(self
.listStudio
, SIGNAL("currentCellChanged(int, int, int, int)"), self
.checkOkButton
)
457 list_of_ladish_studios
= shared
.controlBus
.GetStudioList()
458 for i
in range(len(list_of_ladish_studios
)):
459 name
= QTableWidgetItem(str(list_of_ladish_studios
[i
][0]))
460 time
= QTableWidgetItem(ctime(float(list_of_ladish_studios
[i
][1][u
'Modification Time'])))
461 self
.listStudio
.insertRow(i
)
462 self
.listStudio
.setItem(i
, 0, name
)
463 self
.listStudio
.setItem(i
, 1, time
)
465 self
.listStudio
.sortByColumn(0, Qt
.AscendingOrder
)
469 shared
.controlBus
.LoadStudio(str(self
.listStudio
.item(self
.listStudio
.currentRow(), 0).text()))
470 shared
.jackBus
.StartServer()
471 jack
.attach("Klaudia")
473 def checkOkButton(self
, row
, b
, c
, d
):
475 self
.buttonBox
.button(QDialogButtonBox
.Ok
).setEnabled(False)
477 self
.buttonBox
.button(QDialogButtonBox
.Ok
).setEnabled(True)