1 /*
2 Copyright (C) 2005-2007 Remon Sijrier
3
4 This file is part of Traverso
5
6 Traverso is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 */
21
22 #include <QFile>
23 #include <QDir>
24 #include <QTextStream>
25 #include <QMessageBox>
26 #include <QString>
27
28 #include <cfloat>
29
30 #include "Project.h"
31 #include "Sheet.h"
32 #include "ProjectManager.h"
33 #include "Information.h"
34 #include "InputEngine.h"
35 #include "ResourcesManager.h"
36 #include "Export.h"
37 #include "AudioDevice.h"
38 #include "Config.h"
39 #include "ContextPointer.h"
40 #include "Utils.h"
41 #include <AddRemove.h>
42 #include "FileHelpers.h"
43
44 #define PROJECT_FILE_VERSION 3
45
46 // Always put me below _all_ includes, this is needed
47 // in case we run with memory leak detection enabled!
48 #include "Debugger.h"
49
50 /** \class Project
51 \brief Project restores and saves the state of a Traverso Project
52
53 A Project can have as much Sheet's as one likes. A Project with one Sheet acts like a 'Session'
54 where the Sheet can be turned into a CD with various Tracks using Marker 's
55 When a Project has multiple Sheet's, each Sheet will be a CD Track, this can be usefull if each
56 Track on a CD is independend of the other CD Tracks.
57
58 */
59
60
Project(const QString & title)61 Project::Project(const QString& title)
62 : ContextItem(), m_title(title)
63 {
64 PENTERCONS;
65 m_currentSheetId = 0;
66 m_exportThread = 0;
67 engineer = "";
68
69 m_useResampling = config().get_property("Conversion", "DynamicResampling", true).toBool();
70 m_rootDir = config().get_property("Project", "directory", "/directory/unknown/").toString() + "/" + m_title;
71 m_sourcesDir = m_rootDir + "/audiosources";
72 m_rate = audiodevice().get_sample_rate();
73 m_bitDepth = audiodevice().get_bit_depth();
74
75 m_resourcesManager = new ResourcesManager(this);
76 m_hs = new QUndoStack(pm().get_undogroup());
77
78 cpointer().add_contextitem(this);
79 }
80
81
~Project()82 Project::~Project()
83 {
84 PENTERDES;
85 cpointer().remove_contextitem(this);
86
87 foreach(Sheet* sheet, m_sheets) {
88 sheet->schedule_for_deletion();
89 sheet->disconnect_from_audiodevice();
90 }
91
92 delete m_hs;
93 }
94
95
create(int sheetcount,int numtracks)96 int Project::create(int sheetcount, int numtracks)
97 {
98 PENTER;
99 PMESG("Creating new project %s NumSheets=%d", QS_C(m_title), sheetcount);
100
101 QDir dir;
102 if (dir.mkdir(m_rootDir) < 0) {
103 info().critical(tr("Cannot create dir %1").arg(m_rootDir));
104 return -1;
105 }
106
107 if (create_peakfiles_dir() < 0) {
108 return -1;
109 }
110
111 if (create_audiosources_dir() < 0) {
112 return -1;
113 }
114
115 if (pm().create_projectfilebackup_dir(m_rootDir) < 0) {
116 return -1;
117 }
118
119 for (int i=0; i< sheetcount; i++) {
120 Sheet* sheet = new Sheet(this, numtracks);
121 m_sheets.append(sheet);
122 sheet->connect_to_audiodevice();
123 }
124
125 if (m_sheets.size()) {
126 set_current_sheet(m_sheets.first()->get_id());
127 }
128
129 m_id = create_id();
130 m_importDir = QDir::homePath();
131
132 info().information(tr("Created new Project %1").arg(m_title));
133 return 1;
134 }
135
create_audiosources_dir()136 int Project::create_audiosources_dir()
137 {
138 QDir dir;
139 if (dir.mkdir(m_sourcesDir) < 0) {
140 info().critical(tr("Cannot create dir %1").arg(m_sourcesDir));
141 return -1;
142 }
143
144 return 1;
145
146 }
147
create_peakfiles_dir()148 int Project::create_peakfiles_dir()
149 {
150 QDir dir;
151 QString peaksDir = m_rootDir + "/peakfiles/";
152
153 if (dir.mkdir(peaksDir) < 0) {
154 info().critical(tr("Cannot create dir %1").arg(peaksDir));
155 return -1;
156 }
157
158 return 1;
159 }
160
load(QString projectfile)161 int Project::load(QString projectfile)
162 {
163 PENTER;
164 QDomDocument doc("Project");
165
166 QFile file;
167 QString filename;
168
169 if (projectfile.isEmpty()) {
170 filename = m_rootDir + "/project.tpf";
171 file.setFileName(filename);
172 } else {
173 filename = projectfile;
174 file.setFileName(filename);
175 }
176
177 if (!file.open(QIODevice::ReadOnly)) {
178 m_errorString = tr("Project %1: Cannot open project.tpf file! (Reason: %2)").arg(m_title).arg(file.errorString());
179 info().critical(m_errorString);
180 return PROJECT_FILE_COULD_NOT_BE_OPENED;
181 }
182
183 // Check if important directories still exist!
184 QDir dir;
185 if (!dir.exists(m_rootDir + "/peakfiles")) {
186 create_peakfiles_dir();
187 }
188 if (!dir.exists(m_rootDir + "/audiosources")) {
189 create_audiosources_dir();
190 }
191
192
193 // Start setting and parsing the content of the xml file
194 QString errorMsg;
195 if (!doc.setContent(&file, &errorMsg)) {
196 m_errorString = tr("Project %1: Failed to parse project.tpf file! (Reason: %2)").arg(m_title).arg(errorMsg);
197 info().critical(m_errorString);
198 return SETTING_XML_CONTENT_FAILED;
199 }
200
201 QDomElement docElem = doc.documentElement();
202 QDomNode propertiesNode = docElem.firstChildElement("Properties");
203 QDomElement e = propertiesNode.toElement();
204
205 if (e.attribute("projectfileversion", "-1").toInt() != PROJECT_FILE_VERSION) {
206 m_errorString = tr("Project File Version does not match, unable to load Project!");
207 info().warning(m_errorString);
208 return PROJECT_FILE_VERSION_MISMATCH;
209 }
210
211 m_title = e.attribute( "title", "" );
212 engineer = e.attribute( "engineer", "" );
213 m_description = e.attribute( "description", "No description set");
214 m_discid = e.attribute( "discId", "" );
215 m_upcEan = e.attribute( "upc_ean", "" );
216 m_genre = e.attribute( "genre", "" ).toInt();
217 m_performer = e.attribute( "performer", "" );
218 m_arranger = e.attribute( "arranger", "" );
219 m_songwriter = e.attribute( "songwriter", "" );
220 m_message = e.attribute( "message", "" );
221 m_rate = e.attribute( "rate", "" ).toInt();
222 m_bitDepth = e.attribute( "bitdepth", "" ).toInt();
223 m_id = e.attribute("id", "0").toLongLong();
224 if (m_id == 0) {
225 m_id = create_id();
226 }
227 m_importDir = e.attribute("importdir", QDir::homePath());
228
229
230 // Load all the AudioSources for this project
231 QDomNode asmNode = docElem.firstChildElement("ResourcesManager");
232 m_resourcesManager->set_state(asmNode);
233
234
235 QDomNode sheetsNode = docElem.firstChildElement("Sheets");
236 QDomNode sheetNode = sheetsNode.firstChild();
237
238 // Load all the Sheets
239 while(!sheetNode.isNull())
240 {
241 Sheet* sheet = new Sheet(this, sheetNode);
242 Command::process_command(add_sheet(sheet, false));
243 sheetNode = sheetNode.nextSibling();
244 }
245
246 qint64 id = e.attribute("currentsheetid", "0" ).toLongLong();
247
248 if ( id == 0) {
249 if (m_sheets.size()) {
250 id = m_sheets.first()->get_id();
251 }
252 }
253
254 set_current_sheet(id);
255
256 info().information( tr("Project %1 loaded").arg(m_title) );
257
258 emit projectLoadFinished();
259
260 return 1;
261 }
262
263
save(bool autosave)264 int Project::save(bool autosave)
265 {
266 PENTER;
267 QDomDocument doc("Project");
268 QString fileName = m_rootDir + "/project.tpf";
269
270 QFile data( fileName );
271
272 if (!data.open( QIODevice::WriteOnly ) ) {
273 QString errorstring = FileHelper::fileerror_to_string(data.error());
274 info().critical( tr("Couldn't open Project properties file for writing! (File %1. Reason: %2)").arg(fileName).arg(errorstring) );
275 return -1;
276 }
277
278 get_state(doc);
279 QTextStream stream(&data);
280 doc.save(stream, 4);
281 data.close();
282
283 if (!autosave) {
284 info().information( tr("Project %1 saved ").arg(m_title) );
285 }
286
287 pm().start_incremental_backup(m_title);
288
289 return 1;
290 }
291
292
get_state(QDomDocument doc,bool istemplate)293 QDomNode Project::get_state(QDomDocument doc, bool istemplate)
294 {
295 PENTER;
296
297 QDomElement projectNode = doc.createElement("Project");
298 QDomElement properties = doc.createElement("Properties");
299
300 properties.setAttribute("title", m_title);
301 properties.setAttribute("engineer", engineer);
302 properties.setAttribute("description", m_description);
303 properties.setAttribute("discId", m_discid );
304 properties.setAttribute("upc_ean", m_upcEan);
305 properties.setAttribute("genre", QString::number(m_genre));
306 properties.setAttribute("performer", m_performer);
307 properties.setAttribute("arranger", m_arranger);
308 properties.setAttribute("songwriter", m_songwriter);
309 properties.setAttribute("message", m_message);
310 properties.setAttribute("currentsheetid", m_currentSheetId);
311 properties.setAttribute("rate", m_rate);
312 properties.setAttribute("bitdepth", m_bitDepth);
313 properties.setAttribute("projectfileversion", PROJECT_FILE_VERSION);
314 if (! istemplate) {
315 properties.setAttribute("id", m_id);
316 } else {
317 properties.setAttribute("title", "Template Project File!!");
318 }
319
320 properties.setAttribute("importdir", m_importDir);
321
322 projectNode.appendChild(properties);
323
324 doc.appendChild(projectNode);
325
326 // Get the AudioSources Node, and append
327 if (! istemplate) {
328 projectNode.appendChild(m_resourcesManager->get_state(doc));
329 }
330
331 // Get all the Sheets
332 QDomNode sheetsNode = doc.createElement("Sheets");
333
334 foreach(Sheet* sheet, m_sheets) {
335 sheetsNode.appendChild(sheet->get_state(doc, istemplate));
336 }
337
338 projectNode.appendChild(sheetsNode);
339
340 return projectNode;
341 }
342
343
set_title(const QString & title)344 void Project::set_title(const QString& title)
345 {
346 if (title == m_title) {
347 // do nothing if the title is the same as the current one
348 return;
349 }
350
351 if (pm().project_exists(title)) {
352 info().critical(tr("Project with title '%1' allready exists, not setting new title!").arg(title));
353 return;
354 }
355
356 QString newrootdir = config().get_property("Project", "directory", "/directory/unknown/").toString() + "/" + title;
357
358 QDir dir(m_rootDir);
359
360 if ( ! dir.exists() ) {
361 info().critical(tr("Project directory %1 no longer exists, did you rename it? "
362 "Shame on you! Please undo that, and come back later to rename your Project...").arg(m_rootDir));
363 return;
364 }
365
366 m_title = title;
367
368 save();
369
370 if (pm().rename_project_dir(m_rootDir, newrootdir) < 0 ) {
371 return;
372 }
373
374 QMessageBox::information( 0,
375 tr("Traverso - Information"),
376 tr("Project title changed, Project will to be reloaded to ensure proper operation"),
377 QMessageBox::Ok);
378
379 pm().load_renamed_project(m_title);
380 }
381
382
set_engineer(const QString & pEngineer)383 void Project::set_engineer(const QString& pEngineer)
384 {
385 engineer=pEngineer;
386 }
387
set_description(const QString & des)388 void Project::set_description(const QString& des)
389 {
390 m_description = des;
391 }
392
set_discid(const QString & pId)393 void Project::set_discid(const QString& pId)
394 {
395 m_discid = pId;
396 }
397
set_performer(const QString & pPerformer)398 void Project::set_performer(const QString& pPerformer)
399 {
400 m_performer = pPerformer;
401 }
402
set_arranger(const QString & pArranger)403 void Project::set_arranger(const QString& pArranger)
404 {
405 m_arranger = pArranger;
406 }
407
set_songwriter(const QString & sw)408 void Project::set_songwriter(const QString& sw)
409 {
410 m_songwriter = sw;
411 }
412
set_message(const QString & pMessage)413 void Project::set_message(const QString& pMessage)
414 {
415 m_message = pMessage;
416 }
417
set_upc_ean(const QString & pUpc)418 void Project::set_upc_ean(const QString& pUpc)
419 {
420 m_upcEan = pUpc;
421 }
422
set_genre(int pGenre)423 void Project::set_genre(int pGenre)
424 {
425 m_genre = pGenre;
426 }
427
has_changed()428 bool Project::has_changed()
429 {
430 foreach(Sheet* sheet, m_sheets) {
431 if(sheet->is_changed())
432 return true;
433 }
434 return false;
435 }
436
437
add_sheet(Sheet * sheet,bool historable)438 Command* Project::add_sheet(Sheet* sheet, bool historable)
439 {
440 PENTER;
441
442 AddRemove* cmd;
443 cmd = new AddRemove(this, sheet, historable, 0,
444 "private_add_sheet(Sheet*)", "sheetAdded(Sheet*)",
445 "private_remove_sheet(Sheet*)", "sheetRemoved(Sheet*)",
446 tr("Sheet %1 added").arg(sheet->get_title()));
447
448 cmd->set_instantanious(true);
449
450 return cmd;
451 }
452
453
set_current_sheet(qint64 id)454 void Project::set_current_sheet(qint64 id)
455 {
456 PENTER;
457
458 if (m_currentSheetId == id) {
459 return;
460 }
461
462 Sheet* newcurrent = 0;
463
464 foreach(Sheet* sheet, m_sheets) {
465 if (sheet->get_id() == id) {
466 newcurrent = sheet;
467 break;
468 }
469 }
470
471 if (!newcurrent) {
472 info().information( tr("Sheet '%1' doesn't exist!").arg(id) );
473 emit currentSheetChanged(0);
474 return;
475 }
476
477 m_currentSheetId=id;
478
479 emit currentSheetChanged(newcurrent);
480 }
481
482
get_current_sheet() const483 Sheet* Project::get_current_sheet() const
484 {
485 Sheet* current = 0;
486
487 foreach(Sheet* sheet, m_sheets) {
488 if (sheet->get_id() == m_currentSheetId) {
489 current = sheet;
490 break;
491 }
492 }
493
494 return current;
495 }
496
497
get_sheet(qint64 id) const498 Sheet* Project::get_sheet(qint64 id) const
499 {
500 Sheet* current = 0;
501
502 foreach(Sheet* sheet, m_sheets) {
503 if (sheet->get_id() == id) {
504 current = sheet;
505 break;
506 }
507 }
508
509 return current;
510 }
511
512
remove_sheet(Sheet * sheet,bool historable)513 Command* Project::remove_sheet(Sheet* sheet, bool historable)
514 {
515 AddRemove* cmd;
516 cmd = new AddRemove(this, sheet, historable, 0,
517 "private_remove_sheet(Sheet*)", "sheetRemoved(Sheet*)",
518 "private_add_sheet(Sheet*)", "sheetAdded(Sheet*)",
519 tr("Remove Sheet %1").arg(sheet->get_title()));
520
521 cmd->set_instantanious(true);
522
523 return cmd;
524 }
525
526
export_project(ExportSpecification * spec)527 int Project::export_project(ExportSpecification* spec)
528 {
529 PENTER;
530
531 if (!m_exportThread) {
532 m_exportThread = new ExportThread(this);
533 }
534
535 if (m_exportThread->isRunning()) {
536 info().warning(tr("Export already in progress, cannot start it twice!"));
537 return -1;
538 }
539
540 QDir dir(spec->exportdir);
541 if (!spec->exportdir.isEmpty() && !dir.exists()) {
542 if (!dir.mkdir(spec->exportdir)) {
543 info().warning(tr("Unable to create export directory! Please check permissions for this directory: %1").arg(spec->exportdir));
544 return -1;
545 }
546 }
547
548 spec->progress = 0;
549 spec->running = true;
550 spec->stop = false;
551 spec->breakout = false;
552
553 m_exportThread->set_specification(spec);
554 m_exportThread->start();
555
556 return 0;
557 }
558
start_export(ExportSpecification * spec)559 int Project::start_export(ExportSpecification* spec)
560 {
561 PMESG("Starting export, rate is %d bitdepth is %d", spec->sample_rate, spec->data_width );
562
563 spec->blocksize = 32768;
564
565 spec->dataF = new audio_sample_t[spec->blocksize * spec->channels];
566 audio_sample_t* readbuffer = new audio_sample_t[spec->blocksize * spec->channels];
567
568 overallExportProgress = renderedSheets = 0;
569 sheetsToRender.clear();
570
571 if (spec->allSheets) {
572 foreach(Sheet* sheet, m_sheets) {
573 sheetsToRender.append(sheet);
574 }
575 } else {
576 Sheet* sheet = get_current_sheet();
577 if (sheet) {
578 sheetsToRender.append(sheet);
579 }
580 }
581
582 foreach(Sheet* sheet, sheetsToRender) {
583 PMESG("Starting export for sheet %lld", sheet->get_id());
584 emit exportStartedForSheet(sheet);
585 spec->resumeTransport = false;
586 spec->resumeTransportLocation = sheet->get_transport_location();
587 sheet->readbuffer = readbuffer;
588
589 if (spec->normalize) {
590 spec->peakvalue = 0.0;
591 spec->renderpass = ExportSpecification::CALC_NORM_FACTOR;
592
593
594 if (sheet->prepare_export(spec) < 0) {
595 PERROR("Failed to prepare sheet for export");
596 continue;
597 }
598
599 while(sheet->render(spec) > 0) {}
600
601 spec->normvalue = (1.0 - FLT_EPSILON) / spec->peakvalue;
602
603 if (spec->peakvalue > 1.0) {
604 info().critical(tr("Detected clipping in exported audio! (%1)")
605 .arg(coefficient_to_dbstring(spec->peakvalue)));
606 }
607
608 if (!spec->breakout) {
609 info().information(tr("calculated norm factor: %1").arg(coefficient_to_dbstring(spec->normvalue)));
610 }
611 }
612
613 spec->renderpass = ExportSpecification::WRITE_TO_HARDDISK;
614
615 if (sheet->prepare_export(spec) < 0) {
616 PERROR("Failed to prepare sheet for export");
617 break;
618 }
619
620 while(sheet->render(spec) > 0) {}
621
622 if (!QMetaObject::invokeMethod(sheet, "set_transport_pos", Qt::QueuedConnection, Q_ARG(TimeRef, spec->resumeTransportLocation))) {
623 printf("Invoking Sheet::set_transport_pos() failed\n");
624 }
625 if (spec->resumeTransport) {
626 if (!QMetaObject::invokeMethod(sheet, "start_transport", Qt::QueuedConnection)) {
627 printf("Invoking Sheet::start_transport() failed\n");
628 }
629 }
630 if (spec->breakout) {
631 break;
632 }
633 renderedSheets++;
634 }
635
636 PMESG("Export Finished");
637
638 spec->running = false;
639 overallExportProgress = 0;
640
641 delete [] spec->dataF;
642 delete [] readbuffer;
643 spec->dataF = 0;
644
645 emit exportFinished();
646
647 return 1;
648 }
649
create_cdrdao_toc(ExportSpecification * spec)650 int Project::create_cdrdao_toc(ExportSpecification* spec)
651 {
652 QList<Sheet* > sheets;
653 QString filename = spec->exportdir;
654
655 if (spec->allSheets) {
656 foreach(Sheet* sheet, m_sheets) {
657 sheets.append(sheet);
658 }
659 // filename of the toc file is "project-name.toc"
660 filename += get_title() + ".toc";
661 } else {
662 Sheet* sheet = get_current_sheet();
663 if (!sheet) {
664 return -1;
665 }
666 sheets.append(sheet);
667 }
668
669 QString output;
670
671 output += "CD_DA\n\n";
672 output += "CD_TEXT {\n";
673
674 output += " LANGUAGE_MAP {\n 0 : EN\n }\n\n";
675
676 output += " LANGUAGE 0 {\n";
677 output += " TITLE \"" + get_title() + "\"\n";
678 output += " PERFORMER \"" + get_performer() + "\"\n";
679 output += " DISC_ID \"" + get_discid() + "\"\n";
680 output += " UPC_EAN \"" + get_upc_ean() + "\"\n\n";
681
682 output += " ARRANGER \"" + get_arranger() + "\"\n";
683 output += " SONGWRITER \"" + get_songwriter() + "\"\n";
684 output += " MESSAGE \"" + get_message() + "\"\n";
685 output += " GENRE \"" + QString::number(get_genre()) + "\"\n }\n}\n\n";
686
687
688 bool pregap = true;
689 spec->renderpass = ExportSpecification::CREATE_CDRDAO_TOC;
690
691 foreach(Sheet* sheet, sheets) {
692 if (sheet->prepare_export(spec) < 0) {
693 return -1;
694 }
695 output += sheet->get_cdrdao_tracklist(spec, pregap);
696 pregap = false; // only add the pregap at the first sheet
697 }
698
699
700 if (spec->writeToc) {
701 if (!spec->allSheets) {
702 // filename of the toc file is "sheet-name.toc"
703 filename += spec->basename + ".toc";
704 }
705
706 spec->tocFileName = filename;
707
708 QFile file(filename);
709
710 if (file.open(QFile::WriteOnly)) {
711 printf("Saving cdrdao toc-file to %s\n", QS_C(spec->tocFileName));
712 QTextStream out(&file);
713 out << output;
714 file.close();
715 }
716 }
717
718 spec->cdrdaoToc = output;
719
720 return 1;
721 }
722
select()723 Command* Project::select()
724 {
725 int index = ie().collected_number();
726 if (index <= m_sheets.size() && index > 0) {
727 set_current_sheet(m_sheets.at(index - 1)->get_id());
728 }
729 return (Command*) 0;
730 }
731
get_rate() const732 int Project::get_rate( ) const
733 {
734 // FIXME: Projects should eventually just use the universal samplerate
735 if (m_useResampling) {
736 return audiodevice().get_sample_rate();
737 }
738
739 return m_rate;
740 }
741
get_bitdepth() const742 int Project::get_bitdepth( ) const
743 {
744 return m_bitDepth;
745 }
746
set_sheet_export_progress(int progress)747 void Project::set_sheet_export_progress(int progress)
748 {
749 overallExportProgress = (progress / sheetsToRender.count()) +
750 (renderedSheets * (100 / sheetsToRender.count()) );
751
752 emit sheetExportProgressChanged(progress);
753 emit overallExportProgressChanged(overallExportProgress);
754 }
755
get_sheets() const756 QList<Sheet* > Project::get_sheets( ) const
757 {
758 return m_sheets;
759 }
760
get_sheet_index(qint64 id) const761 int Project::get_sheet_index(qint64 id) const
762 {
763 for (int i=0; i<m_sheets.size(); ++i) {
764 if (m_sheets.at(i)->get_id() == id) {
765 return i + 1;
766 }
767 }
768
769 return 0;
770 }
771
772
get_current_sheet_id() const773 int Project::get_current_sheet_id( ) const
774 {
775 return m_currentSheetId;
776 }
777
get_num_sheets() const778 int Project::get_num_sheets( ) const
779 {
780 return m_sheets.size();
781 }
782
get_title() const783 QString Project::get_title( ) const
784 {
785 return m_title;
786 }
787
get_engineer() const788 QString Project::get_engineer( ) const
789 {
790 return engineer;
791 }
792
get_description() const793 QString Project::get_description() const
794 {
795 return m_description;
796 }
797
get_discid() const798 QString Project::get_discid() const
799 {
800 return m_discid;
801 }
802
get_performer() const803 QString Project::get_performer() const
804 {
805 return m_performer;
806 }
807
get_arranger() const808 QString Project::get_arranger() const
809 {
810 return m_arranger;
811 }
812
get_songwriter() const813 QString Project::get_songwriter() const
814 {
815 return m_songwriter;
816 }
817
get_message() const818 QString Project::get_message() const
819 {
820 return m_message;
821 }
822
get_upc_ean() const823 QString Project::get_upc_ean() const
824 {
825 return m_upcEan;
826 }
827
get_genre()828 int Project::get_genre()
829 {
830 return m_genre;
831 }
832
get_root_dir() const833 QString Project::get_root_dir( ) const
834 {
835 return m_rootDir;
836 }
837
get_audiosources_dir() const838 QString Project::get_audiosources_dir() const
839 {
840 return m_rootDir + "/audiosources/";
841 }
842
get_audiosource_manager() const843 ResourcesManager * Project::get_audiosource_manager( ) const
844 {
845 return m_resourcesManager;
846 }
847
848
private_add_sheet(Sheet * sheet)849 void Project::private_add_sheet(Sheet * sheet)
850 {
851 PENTER;
852 m_sheets.append(sheet);
853 sheet->connect_to_audiodevice();
854
855 set_current_sheet(sheet->get_id());
856 }
857
private_remove_sheet(Sheet * sheet)858 void Project::private_remove_sheet(Sheet * sheet)
859 {
860 PENTER;
861 m_sheets.removeAll(sheet);
862
863 if (m_sheets.isEmpty()) {
864 m_currentSheetId = -1;
865 }
866
867 qint64 newcurrent = 0;
868
869 if (m_sheets.size() > 0) {
870 newcurrent = m_sheets.last()->get_id();
871 }
872
873 set_current_sheet(newcurrent);
874
875 sheet->disconnect_from_audiodevice();
876 }
877
get_import_dir() const878 QString Project::get_import_dir() const
879 {
880 return m_importDir;
881 }
882
set_import_dir(const QString & dir)883 void Project::set_import_dir(const QString& dir)
884 {
885 m_importDir = dir;
886 }
887
is_save_to_close() const888 bool Project::is_save_to_close() const
889 {
890 if (is_recording()) {
891 QMessageBox::information( 0,
892 tr("Traverso - Information"),
893 tr("You're still recording, please stop recording first to be able to exit the application!"),
894 QMessageBox::Ok);
895 return false;
896 }
897 return true;
898 }
899
is_recording() const900 bool Project::is_recording() const
901 {
902 foreach(Sheet* sheet, m_sheets) {
903 if (sheet->is_recording() && sheet->is_transport_rolling()) {
904 return true;
905 }
906 }
907 return false;
908 }
909
910