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