1 #include "mixer/samplerbank.h"
2 
3 #include <QFileDialog>
4 #include <QMessageBox>
5 
6 #include "control/controlpushbutton.h"
7 #include "mixer/playermanager.h"
8 #include "mixer/sampler.h"
9 #include "moc_samplerbank.cpp"
10 #include "track/track.h"
11 #include "util/assert.h"
12 
SamplerBank(PlayerManager * pPlayerManager)13 SamplerBank::SamplerBank(PlayerManager* pPlayerManager)
14         : QObject(pPlayerManager),
15           m_pPlayerManager(pPlayerManager) {
16     DEBUG_ASSERT(m_pPlayerManager);
17 
18     m_pCOLoadBank = std::make_unique<ControlPushButton>(ConfigKey("[Sampler]", "LoadSamplerBank"), this);
19     connect(m_pCOLoadBank.get(),
20             &ControlObject::valueChanged,
21             this,
22             &SamplerBank::slotLoadSamplerBank);
23 
24     m_pCOSaveBank = std::make_unique<ControlPushButton>(ConfigKey("[Sampler]", "SaveSamplerBank"), this);
25     connect(m_pCOSaveBank.get(),
26             &ControlObject::valueChanged,
27             this,
28             &SamplerBank::slotSaveSamplerBank);
29 
30     m_pCONumSamplers = new ControlProxy(ConfigKey("[Master]", "num_samplers"), this);
31 }
32 
~SamplerBank()33 SamplerBank::~SamplerBank() {
34 }
35 
slotSaveSamplerBank(double v)36 void SamplerBank::slotSaveSamplerBank(double v) {
37     if (v <= 0.0) {
38         return;
39     }
40 
41     const QString xmlSuffix = QStringLiteral(".xml");
42     QString fileFilter = tr("Mixxx Sampler Banks (*%1)").arg(xmlSuffix);
43     QString samplerBankPath = QFileDialog::getSaveFileName(nullptr,
44             tr("Save Sampler Bank"),
45             QString(),
46             fileFilter,
47             &fileFilter);
48     if (samplerBankPath.isNull() || samplerBankPath.isEmpty()) {
49         return;
50     }
51 
52     // Manually add extension due to bug in QFileDialog
53     // via https://bugreports.qt-project.org/browse/QTBUG-27186
54     QFileInfo fileName(samplerBankPath);
55     if (fileName.suffix().isEmpty() || !fileName.suffix().endsWith(xmlSuffix)) {
56         samplerBankPath.append(xmlSuffix);
57     }
58 
59     if (!saveSamplerBankToPath(samplerBankPath)) {
60         QMessageBox::warning(nullptr,
61                 tr("Error Saving Sampler Bank"),
62                 tr("Could not write the sampler bank to '%1'.")
63                         .arg(samplerBankPath));
64     }
65 }
66 
saveSamplerBankToPath(const QString & samplerBankPath)67 bool SamplerBank::saveSamplerBankToPath(const QString& samplerBankPath) {
68     // The user has picked a new directory via a file dialog. This means the
69     // system sandboxer (if we are sandboxed) has granted us permission to this
70     // folder. We don't need access to this file on a regular basis so we do not
71     // register a security bookmark.
72 
73     VERIFY_OR_DEBUG_ASSERT(m_pPlayerManager) {
74         qWarning() << "SamplerBank::saveSamplerBankToPath called with no PlayerManager";
75         return false;
76     }
77 
78     QFile file(samplerBankPath);
79     if (!file.open(QIODevice::WriteOnly)) {
80         qWarning() << "Error saving sampler bank: Could not write to file"
81                    << samplerBankPath;
82         return false;
83     }
84 
85     QDomDocument doc("SamplerBank");
86 
87     QDomElement root = doc.createElement("samplerbank");
88     doc.appendChild(root);
89 
90     for (unsigned int i = 0; i < m_pPlayerManager->numSamplers(); ++i) {
91         Sampler* pSampler = m_pPlayerManager->getSampler(i + 1);
92         if (!pSampler) {
93             continue;
94         }
95         QDomElement samplerNode = doc.createElement(QString("sampler"));
96 
97         samplerNode.setAttribute("group", pSampler->getGroup());
98 
99         TrackPointer pTrack = pSampler->getLoadedTrack();
100         if (pTrack) {
101             QString samplerLocation = pTrack->getLocation();
102             samplerNode.setAttribute("location", samplerLocation);
103         }
104         root.appendChild(samplerNode);
105     }
106 
107     QString docStr = doc.toString();
108 
109     file.write(docStr.toUtf8().constData());
110     file.close();
111 
112     return true;
113 }
114 
slotLoadSamplerBank(double v)115 void SamplerBank::slotLoadSamplerBank(double v) {
116     if (v <= 0.0) {
117         return;
118     }
119 
120     QString samplerBankPath = QFileDialog::getOpenFileName(nullptr,
121             tr("Load Sampler Bank"),
122             QString(),
123             tr("Mixxx Sampler Banks (*.xml)"));
124     if (samplerBankPath.isEmpty()) {
125         return;
126     }
127 
128     if (!loadSamplerBankFromPath(samplerBankPath)) {
129         QMessageBox::warning(nullptr,
130                 tr("Error Reading Sampler Bank"),
131                 tr("Could not open the sampler bank file '%1'.")
132                         .arg(samplerBankPath));
133     }
134 }
135 
loadSamplerBankFromPath(const QString & samplerBankPath)136 bool SamplerBank::loadSamplerBankFromPath(const QString& samplerBankPath) {
137     // The user has picked a new directory via a file dialog. This means the
138     // system sandboxer (if we are sandboxed) has granted us permission to this
139     // folder. We don't need access to this file on a regular basis so we do not
140     // register a security bookmark.
141 
142     VERIFY_OR_DEBUG_ASSERT(m_pPlayerManager) {
143         qWarning() << "SamplerBank::loadSamplerBankFromPath called with no PlayerManager";
144         return false;
145     }
146 
147     QFile file(samplerBankPath);
148     if (!file.open(QIODevice::ReadOnly)) {
149         qWarning() << "Could not read sampler bank file" << samplerBankPath;
150         return false;
151     }
152 
153     QDomDocument doc;
154 
155     if (!doc.setContent(file.readAll())) {
156         qWarning() << "Could not read sampler bank file" << samplerBankPath;
157         return false;
158     }
159 
160     QDomElement root = doc.documentElement();
161     if (root.tagName() != "samplerbank") {
162         qWarning() << "Could not read sampler bank file" << samplerBankPath;
163         return false;
164     }
165 
166     QDomNode n = root.firstChild();
167 
168     while (!n.isNull()) {
169         QDomElement e = n.toElement();
170 
171         if (!e.isNull()) {
172             if (e.tagName() == "sampler") {
173                 QString group = e.attribute("group", "");
174                 QString location = e.attribute("location", "");
175                 int samplerNum;
176 
177                 if (!group.isEmpty()
178                         && m_pPlayerManager->isSamplerGroup(group, &samplerNum)) {
179                     if (m_pPlayerManager->numSamplers() < (unsigned) samplerNum) {
180                         m_pCONumSamplers->set(samplerNum);
181                     }
182 
183                     if (location.isEmpty()) {
184                         m_pPlayerManager->slotLoadTrackToPlayer(TrackPointer(), group);
185                     } else {
186                         m_pPlayerManager->slotLoadToPlayer(location, group);
187                     }
188                 }
189 
190             }
191         }
192         n = n.nextSibling();
193     }
194 
195     file.close();
196     return true;
197 }
198