Mercurial > hg > svapp
comparison framework/MainWindowBase.cpp @ 728:2dce002539a0
Merge from branch spectrogram-export
author | Chris Cannam |
---|---|
date | Fri, 10 Jan 2020 14:54:43 +0000 |
parents | e2ad6fe768b0 |
children | 15da3ab3d416 |
comparison
equal
deleted
inserted
replaced
720:55f317633b93 | 728:2dce002539a0 |
---|---|
35 #include "layer/SliceableLayer.h" | 35 #include "layer/SliceableLayer.h" |
36 #include "layer/ImageLayer.h" | 36 #include "layer/ImageLayer.h" |
37 #include "layer/NoteLayer.h" | 37 #include "layer/NoteLayer.h" |
38 #include "layer/FlexiNoteLayer.h" | 38 #include "layer/FlexiNoteLayer.h" |
39 #include "layer/RegionLayer.h" | 39 #include "layer/RegionLayer.h" |
40 #include "layer/SpectrogramLayer.h" | |
40 | 41 |
41 #include "widgets/ListInputDialog.h" | 42 #include "widgets/ListInputDialog.h" |
42 #include "widgets/CommandHistory.h" | 43 #include "widgets/CommandHistory.h" |
43 #include "widgets/ProgressDialog.h" | 44 #include "widgets/ProgressDialog.h" |
44 #include "widgets/MIDIFileImportDialog.h" | 45 #include "widgets/MIDIFileImportDialog.h" |
58 #include "data/fileio/BZipFileDevice.h" | 59 #include "data/fileio/BZipFileDevice.h" |
59 #include "data/fileio/FileSource.h" | 60 #include "data/fileio/FileSource.h" |
60 #include "data/fileio/AudioFileReaderFactory.h" | 61 #include "data/fileio/AudioFileReaderFactory.h" |
61 #include "rdf/RDFImporter.h" | 62 #include "rdf/RDFImporter.h" |
62 #include "rdf/RDFExporter.h" | 63 #include "rdf/RDFExporter.h" |
64 | |
65 #include "transform/ModelTransformerFactory.h" | |
63 | 66 |
64 #include "base/RecentFiles.h" | 67 #include "base/RecentFiles.h" |
65 | 68 |
66 #include "base/XmlExportable.h" | 69 #include "base/XmlExportable.h" |
67 #include "base/Profiler.h" | 70 #include "base/Profiler.h" |
157 m_midiInput(nullptr), | 160 m_midiInput(nullptr), |
158 m_recentFiles("RecentFiles", 20), | 161 m_recentFiles("RecentFiles", 20), |
159 m_recentTransforms("RecentTransforms", 20), | 162 m_recentTransforms("RecentTransforms", 20), |
160 m_documentModified(false), | 163 m_documentModified(false), |
161 m_openingAudioFile(false), | 164 m_openingAudioFile(false), |
162 m_abandoning(false), | |
163 m_labeller(nullptr), | 165 m_labeller(nullptr), |
164 m_lastPlayStatusSec(0), | 166 m_lastPlayStatusSec(0), |
165 m_initialDarkBackground(false), | 167 m_initialDarkBackground(false), |
166 m_defaultFfwdRwdStep(2, 0), | 168 m_defaultFfwdRwdStep(2, 0), |
167 m_audioRecordMode(RecordCreateAdditionalModel), | 169 m_audioRecordMode(RecordCreateAdditionalModel), |
525 { | 527 { |
526 if (m_oscQueue && m_oscQueue->isOK()) { | 528 if (m_oscQueue && m_oscQueue->isOK()) { |
527 connect(m_oscQueue, SIGNAL(messagesAvailable()), this, SLOT(pollOSC())); | 529 connect(m_oscQueue, SIGNAL(messagesAvailable()), this, SLOT(pollOSC())); |
528 QTimer *oscTimer = new QTimer(this); | 530 QTimer *oscTimer = new QTimer(this); |
529 connect(oscTimer, SIGNAL(timeout()), this, SLOT(pollOSC())); | 531 connect(oscTimer, SIGNAL(timeout()), this, SLOT(pollOSC())); |
530 oscTimer->start(1000); | 532 oscTimer->start(2000); |
531 | 533 |
532 if (m_oscQueue->hasPort()) { | 534 if (m_oscQueue->hasPort()) { |
533 SVDEBUG << "Finished setting up OSC interface" << endl; | 535 SVDEBUG << "Finished setting up OSC interface" << endl; |
534 } else { | 536 } else { |
535 SVDEBUG << "Finished setting up internal-only OSC queue" << endl; | 537 SVDEBUG << "Finished setting up internal-only OSC queue" << endl; |
684 dynamic_cast<FlexiNoteLayer *>(currentLayer) || | 686 dynamic_cast<FlexiNoteLayer *>(currentLayer) || |
685 dynamic_cast<RegionLayer *>(currentLayer))); | 687 dynamic_cast<RegionLayer *>(currentLayer))); |
686 bool haveCurrentColour3DPlot = | 688 bool haveCurrentColour3DPlot = |
687 (haveCurrentLayer && | 689 (haveCurrentLayer && |
688 dynamic_cast<Colour3DPlotLayer *>(currentLayer)); | 690 dynamic_cast<Colour3DPlotLayer *>(currentLayer)); |
691 bool haveCurrentSpectrogram = | |
692 (haveCurrentLayer && | |
693 dynamic_cast<SpectrogramLayer *>(currentLayer)); | |
689 bool haveClipboardContents = | 694 bool haveClipboardContents = |
690 (m_viewManager && | 695 (m_viewManager && |
691 !m_viewManager->getClipboard().empty()); | 696 !m_viewManager->getClipboard().empty()); |
692 bool haveTabularLayer = | 697 bool haveTabularLayer = |
693 (haveCurrentLayer && | 698 (haveCurrentLayer && |
702 emit canReplaceMainAudio(haveMainModel); | 707 emit canReplaceMainAudio(haveMainModel); |
703 emit canImportLayer(haveMainModel && haveCurrentPane); | 708 emit canImportLayer(haveMainModel && haveCurrentPane); |
704 emit canExportAudio(haveMainModel); | 709 emit canExportAudio(haveMainModel); |
705 emit canChangeSessionTemplate(haveMainModel); | 710 emit canChangeSessionTemplate(haveMainModel); |
706 emit canExportLayer(haveMainModel && | 711 emit canExportLayer(haveMainModel && |
707 (haveCurrentEditableLayer || haveCurrentColour3DPlot)); | 712 (haveCurrentEditableLayer || |
713 haveCurrentColour3DPlot || | |
714 haveCurrentSpectrogram)); | |
708 emit canExportImage(haveMainModel && haveCurrentPane); | 715 emit canExportImage(haveMainModel && haveCurrentPane); |
709 emit canDeleteCurrentLayer(haveCurrentLayer); | 716 emit canDeleteCurrentLayer(haveCurrentLayer); |
710 emit canRenameLayer(haveCurrentLayer); | 717 emit canRenameLayer(haveCurrentLayer); |
711 emit canEditLayer(haveCurrentEditableLayer); | 718 emit canEditLayer(haveCurrentEditableLayer); |
712 emit canEditLayerTabular(haveCurrentEditableLayer || haveTabularLayer); | 719 emit canEditLayerTabular(haveCurrentEditableLayer || haveTabularLayer); |
2795 return false; | 2802 return false; |
2796 } | 2803 } |
2797 } | 2804 } |
2798 | 2805 |
2799 bool | 2806 bool |
2800 MainWindowBase::exportLayerTo(Layer *layer, QString path, QString &error) | 2807 MainWindowBase::exportLayerTo(Layer *layer, View *fromView, |
2801 { | 2808 MultiSelection *selectionsToWrite, |
2809 QString path, QString &error) | |
2810 { | |
2811 //!!! should we pull out the whole export logic into another | |
2812 // class? then we can more reasonably query it for things like | |
2813 // "can we export this layer type to this file format? can we | |
2814 // export selections, or only the whole layer?" | |
2815 | |
2802 if (QFileInfo(path).suffix() == "") path += ".svl"; | 2816 if (QFileInfo(path).suffix() == "") path += ".svl"; |
2803 | 2817 |
2804 QString suffix = QFileInfo(path).suffix().toLower(); | 2818 QString suffix = QFileInfo(path).suffix().toLower(); |
2805 | 2819 |
2806 auto model = ModelById::get(layer->getModel()); | 2820 auto model = ModelById::get(layer->getExportModel(fromView)); |
2807 if (!model) { | 2821 if (!model) { |
2808 error = tr("Internal error: unknown model"); | 2822 error = tr("Internal error: unknown model"); |
2809 return false; | 2823 return false; |
2810 } | 2824 } |
2811 | 2825 |
2837 | 2851 |
2838 auto nm = ModelById::getAs<NoteModel>(layer->getModel()); | 2852 auto nm = ModelById::getAs<NoteModel>(layer->getModel()); |
2839 | 2853 |
2840 if (!nm) { | 2854 if (!nm) { |
2841 error = tr("Can't export non-note layers to MIDI"); | 2855 error = tr("Can't export non-note layers to MIDI"); |
2856 } else if (!selectionsToWrite) { | |
2857 MIDIFileWriter writer(path, nm.get(), nm->getSampleRate()); | |
2858 writer.write(); | |
2859 if (!writer.isOK()) { | |
2860 error = writer.getError(); | |
2861 } | |
2842 } else { | 2862 } else { |
2843 MIDIFileWriter writer(path, nm.get(), nm->getSampleRate()); | 2863 NoteModel temporary(nm->getSampleRate(), |
2864 nm->getResolution(), | |
2865 nm->getValueMinimum(), | |
2866 nm->getValueMaximum(), | |
2867 false); | |
2868 temporary.setScaleUnits(nm->getScaleUnits()); | |
2869 for (const auto &s: selectionsToWrite->getSelections()) { | |
2870 EventVector ev(nm->getEventsStartingWithin | |
2871 (s.getStartFrame(), s.getDuration())); | |
2872 for (const auto &e: ev) { | |
2873 temporary.add(e); | |
2874 } | |
2875 } | |
2876 MIDIFileWriter writer(path, &temporary, temporary.getSampleRate()); | |
2844 writer.write(); | 2877 writer.write(); |
2845 if (!writer.isOK()) { | 2878 if (!writer.isOK()) { |
2846 error = writer.getError(); | 2879 error = writer.getError(); |
2847 } | 2880 } |
2848 } | 2881 } |
2859 } | 2892 } |
2860 } | 2893 } |
2861 | 2894 |
2862 } else { | 2895 } else { |
2863 | 2896 |
2864 CSVFileWriter writer(path, model.get(), | 2897 ProgressDialog dialog { |
2898 QObject::tr("Exporting layer..."), true, 500, this, | |
2899 Qt::ApplicationModal | |
2900 }; | |
2901 | |
2902 CSVFileWriter writer(path, model.get(), &dialog, | |
2865 ((suffix == "csv") ? "," : "\t")); | 2903 ((suffix == "csv") ? "," : "\t")); |
2866 writer.write(); | 2904 |
2905 if (selectionsToWrite) { | |
2906 writer.writeSelection(*selectionsToWrite); | |
2907 } else { | |
2908 writer.write(); | |
2909 } | |
2867 | 2910 |
2868 if (!writer.isOK()) { | 2911 if (!writer.isOK()) { |
2869 error = writer.getError(); | 2912 error = writer.getError(); |
2913 if (error == "") { | |
2914 error = tr("Failed to export layer for an unknown reason"); | |
2915 } | |
2870 } | 2916 } |
2871 } | 2917 } |
2872 | 2918 |
2873 return (error == ""); | 2919 return (error == ""); |
2874 } | 2920 } |
4162 | 4208 |
4163 void | 4209 void |
4164 MainWindowBase::pollOSC() | 4210 MainWindowBase::pollOSC() |
4165 { | 4211 { |
4166 if (!m_oscQueue || m_oscQueue->isEmpty()) return; | 4212 if (!m_oscQueue || m_oscQueue->isEmpty()) return; |
4167 SVDEBUG << "MainWindowBase::pollOSC: have " << m_oscQueue->getMessagesAvailable() << " messages" << endl; | 4213 |
4168 | 4214 while (!m_oscQueue->isEmpty()) { |
4169 if (m_openingAudioFile) return; | 4215 |
4170 | 4216 if (m_openingAudioFile) { |
4171 OSCMessage message = m_oscQueue->readMessage(); | 4217 SVDEBUG << "MainWindowBase::pollOSC: " |
4172 | 4218 << "waiting for audio to finish loading" |
4173 if (message.getTarget() != 0) { | 4219 << endl; |
4174 return; //!!! for now -- this class is target 0, others not handled yet | 4220 return; |
4175 } | 4221 } |
4176 | 4222 |
4177 handleOSCMessage(message); | 4223 if (ModelTransformerFactory::getInstance()->haveRunningTransformers()) { |
4224 SVDEBUG << "MainWindowBase::pollOSC: " | |
4225 << "waiting for running transforms to complete" | |
4226 << endl; | |
4227 return; | |
4228 } | |
4229 | |
4230 SVDEBUG << "MainWindowBase::pollOSC: have " | |
4231 << m_oscQueue->getMessagesAvailable() | |
4232 << " messages" << endl; | |
4233 | |
4234 OSCMessage message = m_oscQueue->readMessage(); | |
4235 | |
4236 if (message.getTarget() != 0) { | |
4237 SVCERR << "MainWindowBase::pollOSC: ignoring message with target " | |
4238 << message.getTarget() << " (we are target 0)" << endl; | |
4239 continue; | |
4240 } | |
4241 | |
4242 handleOSCMessage(message); | |
4243 | |
4244 disconnect(m_oscQueue, SIGNAL(messagesAvailable()), | |
4245 this, SLOT(pollOSC())); | |
4246 | |
4247 QApplication::processEvents(QEventLoop::ExcludeUserInputEvents | | |
4248 QEventLoop::ExcludeSocketNotifiers); | |
4249 | |
4250 connect(m_oscQueue, SIGNAL(messagesAvailable()), | |
4251 this, SLOT(pollOSC())); | |
4252 } | |
4178 } | 4253 } |
4179 | 4254 |
4180 void | 4255 void |
4181 MainWindowBase::inProgressSelectionChanged() | 4256 MainWindowBase::inProgressSelectionChanged() |
4182 { | 4257 { |