/[svn]/linuxsampler/trunk/src/db/InstrumentsDb.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/db/InstrumentsDb.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1364 - (show annotations) (download)
Mon Oct 1 13:38:37 2007 UTC (16 years, 6 months ago) by schoenebeck
File size: 65976 byte(s)
* fixed egoistic --instruments-db-location command line switch ;-)
  which caused all subsequent command line switches to be ignored
* the default location of the instruments DB file can now be overridden
  with ./configure --enable-default-instruments-db-location=/foo/bar.db
* instruments DB feature can be disabled at compile time with
  ./configure --disable-instruments-db (i.e. for cross compilation)
* in case instruments DB feature is disable at compile time, don't
  actually compile the instruments DB source files and don't install the
  instruments DB API header files either

1 /***************************************************************************
2 * *
3 * Copyright (C) 2007 Grigor Iliev *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the Free Software *
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, *
18 * MA 02110-1301 USA *
19 ***************************************************************************/
20
21 #include "InstrumentsDb.h"
22
23 #if HAVE_SQLITE3
24
25 #include <iostream>
26 #include <sstream>
27 #include <vector>
28 #include <dirent.h>
29 #include <errno.h>
30 #include <fnmatch.h>
31
32 #include "../common/Exception.h"
33
34 namespace LinuxSampler {
35
36 InstrumentsDb* InstrumentsDb::pInstrumentsDb = new InstrumentsDb;
37
38 void InstrumentsDb::CreateInstrumentsDb(String File) {
39 struct stat statBuf;
40 int res = stat(File.c_str(), &statBuf);
41 if (!res) {
42 throw Exception("File exists: " + File);
43 }
44
45 GetInstrumentsDb()->SetDbFile(File);
46
47 String sql =
48 " CREATE TABLE instr_dirs ( "
49 " dir_id INTEGER PRIMARY KEY AUTOINCREMENT, "
50 " parent_dir_id INTEGER DEFAULT 0, "
51 " dir_name TEXT, "
52 " created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "
53 " modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "
54 " description TEXT, "
55 " FOREIGN KEY(parent_dir_id) REFERENCES instr_dirs(dir_id), "
56 " UNIQUE (parent_dir_id,dir_name) "
57 " ); ";
58
59 GetInstrumentsDb()->ExecSql(sql);
60
61 sql = "INSERT INTO instr_dirs (dir_id, parent_dir_id, dir_name) VALUES (0, -2, '/');";
62 GetInstrumentsDb()->ExecSql(sql);
63
64 sql =
65 " CREATE TABLE instruments ( "
66 " instr_id INTEGER PRIMARY KEY AUTOINCREMENT, "
67 " dir_id INTEGER DEFAULT 0, "
68 " instr_name TEXT, "
69 " instr_file TEXT, "
70 " instr_nr INTEGER, "
71 " format_family TEXT, "
72 " format_version TEXT, "
73 " instr_size INTEGER, "
74 " created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "
75 " modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "
76 " description TEXT, "
77 " is_drum INTEGER(1), "
78 " product TEXT, "
79 " artists TEXT, "
80 " keywords TEXT, "
81 " FOREIGN KEY(dir_id) REFERENCES instr_dirs(dir_id), "
82 " UNIQUE (dir_id,instr_name) "
83 " ); ";
84
85 GetInstrumentsDb()->ExecSql(sql);
86 }
87
88 InstrumentsDb::InstrumentsDb() {
89 db = NULL;
90 DbInstrumentsMutex = Mutex();
91 InTransaction = false;
92 }
93
94 InstrumentsDb::~InstrumentsDb() {
95 if (db != NULL) sqlite3_close(db);
96 }
97
98 void InstrumentsDb::Destroy() {
99 if (pInstrumentsDb != NULL) {
100 delete pInstrumentsDb;
101 pInstrumentsDb = NULL;
102 }
103 }
104
105 void InstrumentsDb::AddInstrumentsDbListener(InstrumentsDb::Listener* l) {
106 llInstrumentsDbListeners.AddListener(l);
107 }
108
109 void InstrumentsDb::RemoveInstrumentsDbListener(InstrumentsDb::Listener* l) {
110 llInstrumentsDbListeners.RemoveListener(l);
111 }
112
113 InstrumentsDb* InstrumentsDb::GetInstrumentsDb() {
114 return pInstrumentsDb;
115 }
116
117 void InstrumentsDb::SetDbFile(String File) {
118 DbInstrumentsMutex.Lock();
119 if (File.empty() || DbFile.length() > 0) {
120 DbInstrumentsMutex.Unlock();
121 throw Exception("Failed to set the database file");
122 }
123 DbFile = File;
124 DbInstrumentsMutex.Unlock();
125 }
126
127 sqlite3* InstrumentsDb::GetDb() {
128 if ( db != NULL) return db;
129
130 if (DbFile.empty()) DbFile = CONFIG_DEFAULT_INSTRUMENTS_DB_LOCATION;
131 int rc = sqlite3_open(DbFile.c_str(), &db);
132 if (rc) {
133 sqlite3_close(db);
134 db = NULL;
135 throw Exception("Cannot open instruments database: " + DbFile);
136 }
137 rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, NULL, Regexp, NULL, NULL);
138 if (rc) { throw Exception("Failed to add user function for handling regular expressions."); }
139
140 // TODO: remove this in the next version
141 try {
142 int i = ExecSqlInt("SELECT parent_dir_id FROM instr_dirs WHERE dir_id=0");
143 // The parent ID of the root directory should be -2 now.
144 if(i != -2) ExecSql("UPDATE instr_dirs SET parent_dir_id=-2 WHERE dir_id=0");
145 } catch(Exception e) { }
146 ////////////////////////////////////////
147
148 return db;
149 }
150
151 int InstrumentsDb::GetDirectoryCount(int DirId) {
152 dmsg(2,("InstrumentsDb: GetDirectoryCount(DirId=%d)\n", DirId));
153 if(DirId == -1) return -1;
154
155 std::stringstream sql;
156 sql << "SELECT COUNT(*) FROM instr_dirs WHERE parent_dir_id=" << DirId;
157
158 int count = ExecSqlInt(sql.str());
159
160 return count;
161 }
162
163 int InstrumentsDb::GetDirectoryCount(String Dir, bool Recursive) {
164 dmsg(2,("InstrumentsDb: GetDirectoryCount(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
165 int i;
166
167 BeginTransaction();
168 try {
169 if (Recursive) {
170 DirectoryCounter directoryCounter;
171 DirectoryTreeWalk(Dir, &directoryCounter);
172 i = directoryCounter.GetDirectoryCount();
173 } else {
174 i = GetDirectoryCount(GetDirectoryId(Dir));
175 }
176 } catch (Exception e) {
177 EndTransaction();
178 throw e;
179 }
180 EndTransaction();
181 if (i == -1) throw Exception("Unkown DB directory: " + toEscapedPath(Dir));
182
183 return i;
184 }
185
186 IntListPtr InstrumentsDb::GetDirectoryIDs(int DirId) {
187 std::stringstream sql;
188 sql << "SELECT dir_id FROM instr_dirs ";
189 sql << "WHERE parent_dir_id=" << DirId << " AND dir_id!=0";
190
191 return ExecSqlIntList(sql.str());
192 }
193
194 StringListPtr InstrumentsDb::GetDirectories(String Dir, bool Recursive) {
195 dmsg(2,("InstrumentsDb: GetDirectories(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
196
197 BeginTransaction();
198 try {
199 int dirId = GetDirectoryId(Dir);
200 if(dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
201
202 StringListPtr pDirs;
203 if (Recursive) {
204 SearchQuery q;
205 DirectoryFinder directoryFinder(&q);
206 DirectoryTreeWalk(Dir, &directoryFinder);
207 pDirs = directoryFinder.GetDirectories();
208 } else {
209 pDirs = GetDirectories(dirId);
210 }
211 EndTransaction();
212 return pDirs;
213 } catch (Exception e) {
214 EndTransaction();
215 throw e;
216 }
217 }
218
219 StringListPtr InstrumentsDb::GetDirectories(int DirId) {
220 std::stringstream sql;
221 sql << "SELECT dir_name FROM instr_dirs ";
222 sql << "WHERE parent_dir_id=" << DirId << " AND dir_id!=0";
223 StringListPtr dirs = ExecSqlStringList(sql.str());
224
225 for (int i = 0; i < dirs->size(); i++) {
226 for (int j = 0; j < dirs->at(i).length(); j++) {
227 if (dirs->at(i).at(j) == '/') dirs->at(i).at(j) = '\0';
228 }
229 }
230
231 return dirs;
232 }
233
234 int InstrumentsDb::GetDirectoryId(String Dir) {
235 dmsg(2,("InstrumentsDb: GetDirectoryId(Dir=%s)\n", Dir.c_str()));
236 CheckPathName(Dir);
237
238 if (Dir.empty() || Dir.at(0) != '/') {
239 return -1;
240 } else if (Dir.length() == 1) {
241 // We expect the root directory id to be always 0.
242 return 0;
243 }
244
245 int id = 0, i = 1;
246 int j = Dir.find('/', i);
247
248 while(j != std::string::npos) {
249 id = GetDirectoryId(id, Dir.substr(i, j - i));
250 i = j + 1;
251 if (i >= Dir.length()) return id;
252 j = Dir.find('/', i);
253 }
254
255 return GetDirectoryId(id, Dir.substr(i));
256 }
257
258 int InstrumentsDb::GetDirectoryId(int ParentDirId, String DirName) {
259 dmsg(2,("InstrumentsDb: GetDirectoryId(ParentDirId=%d, DirName=%s)\n", ParentDirId, DirName.c_str()));
260 DirName = toDbName(DirName);
261 std::stringstream sql;
262 sql << "SELECT dir_id FROM instr_dirs WHERE parent_dir_id=";
263 sql << ParentDirId << " AND dir_name=?";
264 return ExecSqlInt(sql.str(), DirName);
265 }
266
267 String InstrumentsDb::GetDirectoryName(int DirId) {
268 String sql = "SELECT dir_name FROM instr_dirs WHERE dir_id=" + ToString(DirId);
269 String name = ExecSqlString(sql);
270 if (name.empty()) throw Exception("Directory ID not found");
271 return name;
272 }
273
274 int InstrumentsDb::GetParentDirectoryId(int DirId) {
275 if (DirId == 0) throw Exception("The root directory is specified");
276 String sql = "SELECT parent_dir_id FROM instr_dirs WHERE dir_id=" + ToString(DirId);
277 int parentId = ExecSqlInt(sql);
278 if (parentId == -1) throw Exception("DB directory not found");
279 return parentId;
280 }
281
282 String InstrumentsDb::GetDirectoryPath(int DirId) {
283 String path = "";
284 int count = 1000; // used to prevent infinite loops
285
286 while(--count) {
287 if (DirId == 0) {
288 path = "/" + path;
289 break;
290 }
291 path = GetDirectoryName(DirId) + path;
292 DirId = GetParentDirectoryId(DirId);
293 }
294
295 if (!count) throw Exception("Possible infinite loop detected");
296
297 return path;
298 }
299
300 void InstrumentsDb::AddDirectory(String Dir) {
301 dmsg(2,("InstrumentsDb: AddDirectory(Dir=%s)\n", Dir.c_str()));
302 CheckPathName(Dir);
303 String ParentDir = GetParentDirectory(Dir);
304
305 BeginTransaction();
306 try {
307 if (Dir.length() > 1) {
308 if (Dir.at(Dir.length() - 1) == '/') Dir.erase(Dir.length() - 1);
309 }
310
311 String dirName = GetFileName(Dir);
312 if(ParentDir.empty() || dirName.empty()) {
313 throw Exception("Failed to add DB directory: " + toEscapedPath(Dir));
314 }
315
316 int id = GetDirectoryId(ParentDir);
317 if (id == -1) throw Exception("DB directory doesn't exist: " + toEscapedPath(ParentDir));
318 int id2 = GetDirectoryId(id, dirName);
319 if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(Dir));
320 id2 = GetInstrumentId(id, dirName);
321 if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(Dir));
322
323 std::stringstream sql;
324 sql << "INSERT INTO instr_dirs (parent_dir_id, dir_name) VALUES (";
325 sql << id << ", ?)";
326
327 ExecSql(sql.str(), toDbName(dirName));
328 } catch (Exception e) {
329 EndTransaction();
330 throw e;
331 }
332
333 EndTransaction();
334
335 FireDirectoryCountChanged(ParentDir);
336 }
337
338 void InstrumentsDb::RemoveDirectory(String Dir, bool Force) {
339 dmsg(2,("InstrumentsDb: RemoveDirectory(Dir=%s,Force=%d)\n", Dir.c_str(), Force));
340
341 String ParentDir = GetParentDirectory(Dir);
342
343 BeginTransaction();
344 try {
345 int dirId = GetDirectoryId(Dir);
346 if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
347 if (dirId == 0) throw Exception("Cannot delete the root directory: " + Dir);
348 if(ParentDir.empty()) throw Exception("Unknown parent directory");
349 if (Force) RemoveDirectoryContent(dirId);
350 RemoveDirectory(dirId);
351 } catch (Exception e) {
352 EndTransaction();
353 throw e;
354 }
355
356 EndTransaction();
357 FireDirectoryCountChanged(ParentDir);
358 }
359
360 void InstrumentsDb::RemoveDirectoryContent(int DirId, int Level) {
361 dmsg(2,("InstrumentsDb: RemoveDirectoryContent(DirId=%d,Level=%d)\n", DirId, Level));
362 if (Level > 1000) throw Exception("Directory level too deep: " + ToString(Level));
363 IntListPtr dirIds = GetDirectoryIDs(DirId);
364
365 for (int i = 0; i < dirIds->size(); i++) {
366 RemoveDirectoryContent(dirIds->at(i), Level + 1);
367 }
368
369 RemoveAllDirectories(DirId);
370 RemoveAllInstruments(DirId);
371 }
372
373 void InstrumentsDb::RemoveDirectory(int DirId) {
374 dmsg(2,("InstrumentsDb: RemoveDirectory(DirId=%d)\n", DirId));
375 if (GetInstrumentCount(DirId) > 0 || GetDirectoryCount(DirId) > 0) {
376 throw Exception("The specified DB directory is not empty");
377 }
378
379 std::stringstream sql;
380 sql << "DELETE FROM instr_dirs WHERE dir_id=" << DirId;
381
382 ExecSql(sql.str());
383 }
384
385 void InstrumentsDb::RemoveAllDirectories(int DirId) {
386 dmsg(2,("InstrumentsDb: RemoveAllDirectories(DirId=%d)\n", DirId));
387 IntListPtr dirIds = GetDirectoryIDs(DirId);
388
389 for (int i = 0; i < dirIds->size(); i++) {
390 if (!IsDirectoryEmpty(dirIds->at(i))) {
391 throw Exception("DB directory not empty!");
392 }
393 }
394 std::stringstream sql;
395 sql << "DELETE FROM instr_dirs WHERE parent_dir_id=" << DirId;
396 sql << " AND dir_id!=0";
397
398 ExecSql(sql.str());
399 }
400
401 bool InstrumentsDb::IsDirectoryEmpty(int DirId) {
402 dmsg(2,("InstrumentsDb: IsDirectoryEmpty(DirId=%d)\n", DirId));
403 int dirCount = GetDirectoryCount(DirId);
404 int instrCount = GetInstrumentCount(DirId);
405 dmsg(3,("InstrumentsDb: IsDirectoryEmpty: dirCount=%d,instrCount=%d\n", dirCount, instrCount));
406 if (dirCount == -1 || instrCount == -1) return false;
407 return dirCount == 0 && instrCount == 0;
408 }
409
410 bool InstrumentsDb::DirectoryExist(String Dir) {
411 dmsg(2,("InstrumentsDb: DirectoryExist(Dir=%s)\n", Dir.c_str()));
412 bool b;
413
414 DbInstrumentsMutex.Lock();
415 try { b = GetDirectoryId(Dir) != -1; }
416 catch (Exception e) {
417 DbInstrumentsMutex.Unlock();
418 throw e;
419 }
420 DbInstrumentsMutex.Unlock();
421
422 return b;
423 }
424
425 DbDirectory InstrumentsDb::GetDirectoryInfo(String Dir) {
426 dmsg(2,("InstrumentsDb: GetDirectoryInfo(Dir=%s)\n", Dir.c_str()));
427 DbDirectory d;
428
429 BeginTransaction();
430
431 try {
432 int id = GetDirectoryId(Dir);
433 if(id == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
434
435 sqlite3_stmt *pStmt = NULL;
436 std::stringstream sql;
437 sql << "SELECT created,modified,description FROM instr_dirs ";
438 sql << "WHERE dir_id=" << id;
439
440 int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
441 if (res != SQLITE_OK) {
442 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
443 }
444
445 res = sqlite3_step(pStmt);
446 if(res == SQLITE_ROW) {
447 d.Created = ToString(sqlite3_column_text(pStmt, 0));
448 d.Modified = ToString(sqlite3_column_text(pStmt, 1));
449 d.Description = ToString(sqlite3_column_text(pStmt, 2));
450 } else {
451 sqlite3_finalize(pStmt);
452
453 if (res != SQLITE_DONE) {
454 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
455 } else {
456 throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
457 }
458 }
459
460 sqlite3_finalize(pStmt);
461 } catch (Exception e) {
462 EndTransaction();
463 throw e;
464 }
465
466 EndTransaction();
467 return d;
468 }
469
470 void InstrumentsDb::RenameDirectory(String Dir, String Name) {
471 dmsg(2,("InstrumentsDb: RenameDirectory(Dir=%s,Name=%s)\n", Dir.c_str(), Name.c_str()));
472 CheckFileName(Name);
473 String dbName = toDbName(Name);
474
475 BeginTransaction();
476 try {
477 int dirId = GetDirectoryId(Dir);
478 if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedText(Dir));
479
480 std::stringstream sql;
481 sql << "SELECT parent_dir_id FROM instr_dirs WHERE dir_id=" << dirId;
482
483 int parent = ExecSqlInt(sql.str());
484 if (parent == -1) throw Exception("Unknown parent directory: " + toEscapedPath(Dir));
485
486 if (GetDirectoryId(parent, dbName) != -1) {
487 String s = toEscapedPath(Name);
488 throw Exception("Cannot rename. Directory with that name already exists: " + s);
489 }
490
491 if (GetInstrumentId(parent, dbName) != -1) {
492 throw Exception("Cannot rename. Instrument with that name exist: " + toEscapedPath(Dir));
493 }
494
495 sql.str("");
496 sql << "UPDATE instr_dirs SET dir_name=? WHERE dir_id=" << dirId;
497 ExecSql(sql.str(), dbName);
498 } catch (Exception e) {
499 EndTransaction();
500 throw e;
501 }
502
503 EndTransaction();
504 FireDirectoryNameChanged(Dir, toAbstractName(Name));
505 }
506
507 void InstrumentsDb::MoveDirectory(String Dir, String Dst) {
508 dmsg(2,("InstrumentsDb: MoveDirectory(Dir=%s,Dst=%s)\n", Dir.c_str(), Dst.c_str()));
509
510 if(Dir.compare("/") == 0) throw Exception("Cannot move the root directory");
511 String ParentDir = GetParentDirectory(Dir);
512 if(ParentDir.empty()) throw Exception("Unknown parent directory");
513
514 BeginTransaction();
515 try {
516 int dirId = GetDirectoryId(Dir);
517 if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
518 int dstId = GetDirectoryId(Dst);
519 if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
520 if (dirId == dstId) {
521 throw Exception("Cannot move directory to itself");
522 }
523
524 if (Dir.at(Dir.length() - 1) != '/') Dir.append("/");
525 if (Dst.length() > Dir.length()) {
526 if (Dir.compare(Dst.substr(0, Dir.length())) == 0) {
527 throw Exception("Cannot move a directory to a subdirectory of itself.");
528 }
529 }
530
531 Dir.erase(Dir.length() - 1);
532 String dirName = GetFileName(Dir);
533
534 int id2 = GetDirectoryId(dstId, dirName);
535 if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(dirName));
536 id2 = GetInstrumentId(dstId, dirName);
537 if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(dirName));
538
539 std::stringstream sql;
540 sql << "UPDATE instr_dirs SET parent_dir_id=" << dstId;
541 sql << " WHERE dir_id=" << dirId;
542 ExecSql(sql.str());
543 } catch (Exception e) {
544 EndTransaction();
545 throw e;
546 }
547
548 EndTransaction();
549 FireDirectoryCountChanged(ParentDir);
550 FireDirectoryCountChanged(Dst);
551 }
552
553 void InstrumentsDb::CopyDirectory(String Dir, String Dst) {
554 dmsg(2,("InstrumentsDb: CopyDirectory(Dir=%s,Dst=%s)\n", Dir.c_str(), Dst.c_str()));
555
556 if(Dir.compare("/") == 0) throw Exception("Cannot copy the root directory");
557 String ParentDir = GetParentDirectory(Dir);
558 if(ParentDir.empty()) throw Exception("Unknown parent directory");
559
560 BeginTransaction();
561 try {
562 int dirId = GetDirectoryId(Dir);
563 if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
564 int dstId = GetDirectoryId(Dst);
565 if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
566 if (dirId == dstId) {
567 throw Exception("Cannot copy directory to itself");
568 }
569
570 if (Dir.at(Dir.length() - 1) != '/') Dir.append("/");
571 if (Dst.length() > Dir.length()) {
572 if (Dir.compare(Dst.substr(0, Dir.length())) == 0) {
573 throw Exception("Cannot copy a directory to a subdirectory of itself.");
574 }
575 }
576
577 Dir.erase(Dir.length() - 1);
578 String dirName = GetFileName(Dir);
579
580 int id2 = GetDirectoryId(dstId, dirName);
581 if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(dirName));
582 id2 = GetInstrumentId(dstId, dirName);
583 if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(dirName));
584
585 DirectoryCopier directoryCopier(ParentDir, Dst);
586 DirectoryTreeWalk(Dir, &directoryCopier);
587 } catch (Exception e) {
588 EndTransaction();
589 throw e;
590 }
591
592 EndTransaction();
593 }
594
595 void InstrumentsDb::SetDirectoryDescription(String Dir, String Desc) {
596 dmsg(2,("InstrumentsDb: SetDirectoryDescription(Dir=%s,Desc=%s)\n", Dir.c_str(), Desc.c_str()));
597
598 BeginTransaction();
599 try {
600 int id = GetDirectoryId(Dir);
601 if(id == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
602
603 std::stringstream sql;
604 sql << "UPDATE instr_dirs SET description=?,modified=CURRENT_TIMESTAMP ";
605 sql << "WHERE dir_id="<< id;
606
607 ExecSql(sql.str(), Desc);
608 } catch (Exception e) {
609 EndTransaction();
610 throw e;
611 }
612 EndTransaction();
613
614 FireDirectoryInfoChanged(Dir);
615 }
616
617 int InstrumentsDb::AddInstruments(ScanMode Mode, String DbDir, String FsDir, bool bBackground) {
618 dmsg(2,("InstrumentsDb: AddInstruments(Mode=%d,DbDir=%s,FsDir=%s,bBackground=%d)\n", Mode, DbDir.c_str(), FsDir.c_str(), bBackground));
619 if(!bBackground) {
620 switch (Mode) {
621 case NON_RECURSIVE:
622 AddInstrumentsNonrecursive(DbDir, FsDir);
623 break;
624 case RECURSIVE:
625 AddInstrumentsRecursive(DbDir, FsDir);
626 break;
627 case FLAT:
628 AddInstrumentsRecursive(DbDir, FsDir, true);
629 break;
630 default:
631 throw Exception("Unknown scan mode");
632 }
633
634 return -1;
635 }
636
637 ScanJob job;
638 int jobId = Jobs.AddJob(job);
639 InstrumentsDbThread.Execute(new AddInstrumentsJob(jobId, Mode, DbDir, FsDir));
640
641 return jobId;
642 }
643
644 int InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index, bool bBackground) {
645 dmsg(2,("InstrumentsDb: AddInstruments(DbDir=%s,FilePath=%s,Index=%d,bBackground=%d)\n", DbDir.c_str(), FilePath.c_str(), Index, bBackground));
646 if(!bBackground) {
647 AddInstruments(DbDir, FilePath, Index);
648 return -1;
649 }
650
651 ScanJob job;
652 int jobId = Jobs.AddJob(job);
653 InstrumentsDbThread.Execute(new AddInstrumentsFromFileJob(jobId, DbDir, FilePath, Index));
654
655 return jobId;
656 }
657
658 void InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index, ScanProgress* pProgress) {
659 dmsg(2,("InstrumentsDb: AddInstruments(DbDir=%s,FilePath=%s,Index=%d)\n", DbDir.c_str(), FilePath.c_str(), Index));
660 if (DbDir.empty() || FilePath.empty()) return;
661
662 DbInstrumentsMutex.Lock();
663 try {
664 int dirId = GetDirectoryId(DbDir);
665 if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedText(DbDir));
666
667 struct stat statBuf;
668 int res = stat(FilePath.c_str(), &statBuf);
669 if (res) {
670 std::stringstream ss;
671 ss << "Fail to stat `" << FilePath << "`: " << strerror(errno);
672 throw Exception(ss.str());
673 }
674
675 if (!S_ISREG(statBuf.st_mode)) {
676 std::stringstream ss;
677 ss << "`" << FilePath << "` is not an instrument file";
678 throw Exception(ss.str());
679 }
680
681 AddInstrumentsFromFile(DbDir, FilePath, Index, pProgress);
682 } catch (Exception e) {
683 DbInstrumentsMutex.Unlock();
684 throw e;
685 }
686
687 DbInstrumentsMutex.Unlock();
688 }
689
690 void InstrumentsDb::AddInstrumentsNonrecursive(String DbDir, String FsDir, ScanProgress* pProgress) {
691 dmsg(2,("InstrumentsDb: AddInstrumentsNonrecursive(DbDir=%s,FsDir=%s)\n", DbDir.c_str(), FsDir.c_str()));
692 if (DbDir.empty() || FsDir.empty()) return;
693
694 DbInstrumentsMutex.Lock();
695 try {
696 int dirId = GetDirectoryId(DbDir);
697 if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedPath(DbDir));
698
699 struct stat statBuf;
700 int res = stat(FsDir.c_str(), &statBuf);
701 if (res) {
702 std::stringstream ss;
703 ss << "Fail to stat `" << FsDir << "`: " << strerror(errno);
704 throw Exception(ss.str());
705 }
706
707 if (!S_ISDIR(statBuf.st_mode)) {
708 throw Exception("Directory expected");
709 }
710
711 if (FsDir.at(FsDir.length() - 1) != '/') FsDir.append("/");
712
713 DIR* pDir = opendir(FsDir.c_str());
714 if (pDir == NULL) {
715 std::stringstream ss;
716 ss << "The scanning of directory `" << FsDir << "` failed: ";
717 ss << strerror(errno);
718 std::cerr << ss.str();
719 DbInstrumentsMutex.Unlock();
720 return;
721 }
722
723 struct dirent* pEnt = readdir(pDir);
724 while (pEnt != NULL) {
725 if (pEnt->d_type != DT_REG) {
726 pEnt = readdir(pDir);
727 continue;
728 }
729
730 AddInstrumentsFromFile(DbDir, FsDir + String(pEnt->d_name), -1, pProgress);
731 pEnt = readdir(pDir);
732 }
733
734 if (closedir(pDir)) {
735 std::stringstream ss;
736 ss << "Failed to close directory `" << FsDir << "`: ";
737 ss << strerror(errno);
738 std::cerr << ss.str();
739 }
740 } catch (Exception e) {
741 DbInstrumentsMutex.Unlock();
742 throw e;
743 }
744
745 DbInstrumentsMutex.Unlock();
746 }
747
748 void InstrumentsDb::AddInstrumentsRecursive(String DbDir, String FsDir, bool Flat, ScanProgress* pProgress) {
749 dmsg(2,("InstrumentsDb: AddInstrumentsRecursive(DbDir=%s,FsDir=%s,Flat=%d)\n", DbDir.c_str(), FsDir.c_str(), Flat));
750 if (pProgress != NULL) {
751 pProgress->SetTotalFileCount(InstrumentFileCounter::Count(FsDir));
752 }
753
754 DirectoryScanner::Scan(DbDir, FsDir, Flat, pProgress);
755 }
756
757 int InstrumentsDb::GetInstrumentCount(int DirId) {
758 dmsg(2,("InstrumentsDb: GetInstrumentCount(DirId=%d)\n", DirId));
759 if(DirId == -1) return -1;
760
761 std::stringstream sql;
762 sql << "SELECT COUNT(*) FROM instruments WHERE dir_id=" << DirId;
763
764 return ExecSqlInt(sql.str());
765 }
766
767 int InstrumentsDb::GetInstrumentCount(String Dir, bool Recursive) {
768 dmsg(2,("InstrumentsDb: GetInstrumentCount(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
769 int i;
770
771 BeginTransaction();
772 try {
773 if (Recursive) {
774 InstrumentCounter instrumentCounter;
775 DirectoryTreeWalk(Dir, &instrumentCounter);
776 i = instrumentCounter.GetInstrumentCount();
777 } else {
778 i = GetInstrumentCount(GetDirectoryId(Dir));
779 }
780 } catch (Exception e) {
781 EndTransaction();
782 throw e;
783 }
784 EndTransaction();
785
786 if (i == -1) throw Exception("Unknown Db directory: " + toEscapedPath(Dir));
787 return i;
788 }
789
790 IntListPtr InstrumentsDb::GetInstrumentIDs(int DirId) {
791 std::stringstream sql;
792 sql << "SELECT instr_id FROM instruments WHERE dir_id=" << DirId;
793
794 return ExecSqlIntList(sql.str());
795 }
796
797 StringListPtr InstrumentsDb::GetInstruments(String Dir, bool Recursive) {
798 dmsg(2,("InstrumentsDb: GetInstruments(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
799 BeginTransaction();
800 try {
801 int dirId = GetDirectoryId(Dir);
802 if(dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
803
804 StringListPtr pInstrs;
805
806 if(Recursive) {
807 SearchQuery q;
808 InstrumentFinder instrumentFinder(&q);
809 DirectoryTreeWalk(Dir, &instrumentFinder);
810 pInstrs = instrumentFinder.GetInstruments();
811 } else {
812 std::stringstream sql;
813 sql << "SELECT instr_name FROM instruments WHERE dir_id=" << dirId;
814
815 pInstrs = ExecSqlStringList(sql.str());
816 // Converting to abstract names
817 for (int i = 0; i < pInstrs->size(); i++) {
818 for (int j = 0; j < pInstrs->at(i).length(); j++) {
819 if (pInstrs->at(i).at(j) == '/') pInstrs->at(i).at(j) = '\0';
820 }
821 }
822 }
823 EndTransaction();
824 return pInstrs;
825 } catch (Exception e) {
826 EndTransaction();
827 throw e;
828 }
829 }
830
831 int InstrumentsDb::GetInstrumentId(String Instr) {
832 dmsg(2,("InstrumentsDb: GetInstrumentId(Instr=%s)\n", Instr.c_str()));
833 String Dir = GetDirectoryPath(Instr);
834 if (Dir.empty()) return -1;
835
836 return GetInstrumentId(GetDirectoryId(Dir), GetFileName(Instr));
837 }
838
839 int InstrumentsDb::GetInstrumentId(int DirId, String InstrName) {
840 dmsg(2,("InstrumentsDb: GetInstrumentId(DirId=%d,InstrName=%s)\n", DirId, InstrName.c_str()));
841 if (DirId == -1 || InstrName.empty()) return -1;
842
843 std::stringstream sql;
844 sql << "SELECT instr_id FROM instruments WHERE dir_id=";
845 sql << DirId << " AND instr_name=?";
846 return ExecSqlInt(sql.str(), toDbName(InstrName));
847 }
848
849 String InstrumentsDb::GetInstrumentName(int InstrId) {
850 dmsg(2,("InstrumentsDb: GetInstrumentName(InstrId=%d)\n", InstrId));
851 std::stringstream sql;
852 sql << "SELECT instr_name FROM instruments WHERE instr_id=" << InstrId;
853 return toAbstractName(ExecSqlString(sql.str()));
854 }
855
856 void InstrumentsDb::RemoveInstrument(String Instr) {
857 dmsg(2,("InstrumentsDb: RemoveInstrument(Instr=%s)\n", Instr.c_str()));
858 String ParentDir = GetDirectoryPath(Instr);
859 if(ParentDir.empty()) throw Exception("Unknown parent directory");
860
861 BeginTransaction();
862 try {
863 int instrId = GetInstrumentId(Instr);
864 if(instrId == -1) {
865 throw Exception("The specified instrument does not exist: " + toEscapedPath(Instr));
866 }
867 RemoveInstrument(instrId);
868 } catch (Exception e) {
869 EndTransaction();
870 throw e;
871 }
872 EndTransaction();
873 FireInstrumentCountChanged(ParentDir);
874 }
875
876 void InstrumentsDb::RemoveInstrument(int InstrId) {
877 dmsg(2,("InstrumentsDb: RemoveInstrument(InstrId=%d)\n", InstrId));
878
879 std::stringstream sql;
880 sql << "DELETE FROM instruments WHERE instr_id=" << InstrId;
881
882 ExecSql(sql.str());
883 }
884
885 void InstrumentsDb::RemoveAllInstruments(int DirId) {
886 dmsg(2,("InstrumentsDb: RemoveAllInstruments(DirId=%d)\n", DirId));
887
888 std::stringstream sql;
889 sql << "DELETE FROM instruments WHERE dir_id=" << DirId;
890 ExecSql(sql.str());
891 }
892
893 DbInstrument InstrumentsDb::GetInstrumentInfo(String Instr) {
894 dmsg(2,("InstrumentsDb: GetInstrumentInfo(Instr=%s)\n", Instr.c_str()));
895 DbInstrument i;
896
897 BeginTransaction();
898 try {
899 int id = GetInstrumentId(Instr);
900 if(id == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
901 i = GetInstrumentInfo(id);
902 } catch (Exception e) {
903 EndTransaction();
904 throw e;
905 }
906 EndTransaction();
907
908 return i;
909 }
910
911 DbInstrument InstrumentsDb::GetInstrumentInfo(int InstrId) {
912 sqlite3_stmt *pStmt = NULL;
913 std::stringstream sql;
914 sql << "SELECT instr_file,instr_nr,format_family,format_version,";
915 sql << "instr_size,created,modified,description,is_drum,product,";
916 sql << "artists,keywords FROM instruments WHERE instr_id=" << InstrId;
917
918 int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
919 if (res != SQLITE_OK) {
920 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
921 }
922
923 DbInstrument i;
924 res = sqlite3_step(pStmt);
925 if(res == SQLITE_ROW) {
926 i.InstrFile = ToString(sqlite3_column_text(pStmt, 0));
927 i.InstrNr = sqlite3_column_int(pStmt, 1);
928 i.FormatFamily = ToString(sqlite3_column_text(pStmt, 2));
929 i.FormatVersion = ToString(sqlite3_column_text(pStmt, 3));
930 i.Size = sqlite3_column_int64(pStmt, 4);
931 i.Created = ToString(sqlite3_column_text(pStmt, 5));
932 i.Modified = ToString(sqlite3_column_text(pStmt, 6));
933 i.Description = ToString(sqlite3_column_text(pStmt, 7));
934 i.IsDrum = sqlite3_column_int(pStmt, 8);
935 i.Product = ToString(sqlite3_column_text(pStmt, 9));
936 i.Artists = ToString(sqlite3_column_text(pStmt, 10));
937 i.Keywords = ToString(sqlite3_column_text(pStmt, 11));
938 } else {
939 sqlite3_finalize(pStmt);
940
941 if (res != SQLITE_DONE) {
942 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
943 } else {
944 throw Exception("Unknown DB instrument");
945 }
946 }
947
948 sqlite3_finalize(pStmt);
949 return i;
950 }
951
952 void InstrumentsDb::RenameInstrument(String Instr, String Name) {
953 dmsg(2,("InstrumentsDb: RenameInstrument(Instr=%s,Name=%s)\n", Instr.c_str(), Name.c_str()));
954 CheckFileName(Name);
955
956 BeginTransaction();
957 try {
958 int dirId = GetDirectoryId(GetDirectoryPath(Instr));
959 if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
960
961 int instrId = GetInstrumentId(dirId, GetFileName(Instr));
962 if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
963
964 if (GetInstrumentId(dirId, Name) != -1) {
965 String s = toEscapedPath(Name);
966 throw Exception("Cannot rename. Instrument with that name already exists: " + s);
967 }
968
969 if (GetDirectoryId(dirId, Name) != -1) {
970 String s = toEscapedPath(Name);
971 throw Exception("Cannot rename. Directory with that name already exists: " + s);
972 }
973
974 std::stringstream sql;
975 sql << "UPDATE instruments SET instr_name=? WHERE instr_id=" << instrId;
976 ExecSql(sql.str(), toDbName(Name));
977 } catch (Exception e) {
978 EndTransaction();
979 throw e;
980 }
981 EndTransaction();
982 FireInstrumentNameChanged(Instr, toAbstractName(Name));
983 }
984
985 void InstrumentsDb::MoveInstrument(String Instr, String Dst) {
986 dmsg(2,("InstrumentsDb: MoveInstrument(Instr=%s,Dst=%s)\n", Instr.c_str(), Dst.c_str()));
987 String ParentDir = GetDirectoryPath(Instr);
988 if(ParentDir.empty()) throw Exception("Unknown parent directory");
989
990 BeginTransaction();
991 try {
992 int dirId = GetDirectoryId(ParentDir);
993 if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
994
995 String instrName = GetFileName(Instr);
996 int instrId = GetInstrumentId(dirId, instrName);
997 if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
998
999 int dstId = GetDirectoryId(Dst);
1000 if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
1001 if (dirId == dstId) {
1002 EndTransaction();
1003 return;
1004 }
1005
1006 if (GetInstrumentId(dstId, instrName) != -1) {
1007 String s = toEscapedPath(instrName);
1008 throw Exception("Cannot move. Instrument with that name already exists: " + s);
1009 }
1010
1011 if (GetDirectoryId(dstId, instrName) != -1) {
1012 String s = toEscapedPath(instrName);
1013 throw Exception("Cannot move. Directory with that name already exists: " + s);
1014 }
1015
1016 std::stringstream sql;
1017 sql << "UPDATE instruments SET dir_id=" << dstId;
1018 sql << " WHERE instr_id=" << instrId;
1019 ExecSql(sql.str());
1020 } catch (Exception e) {
1021 EndTransaction();
1022 throw e;
1023 }
1024 EndTransaction();
1025 FireInstrumentCountChanged(ParentDir);
1026 FireInstrumentCountChanged(Dst);
1027 }
1028
1029 void InstrumentsDb::CopyInstrument(String Instr, String Dst) {
1030 dmsg(2,("InstrumentsDb: CopyInstrument(Instr=%s,Dst=%s)\n", Instr.c_str(), Dst.c_str()));
1031 String ParentDir = GetDirectoryPath(Instr);
1032 if(ParentDir.empty()) throw Exception("Unknown parent directory");
1033
1034 BeginTransaction();
1035 try {
1036 int dirId = GetDirectoryId(GetDirectoryPath(Instr));
1037 if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1038
1039 String instrName = GetFileName(Instr);
1040 int instrId = GetInstrumentId(dirId, instrName);
1041 if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1042
1043 int dstId = GetDirectoryId(Dst);
1044 if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
1045 if (dirId == dstId) {
1046 EndTransaction();
1047 return;
1048 }
1049
1050 CopyInstrument(instrId, instrName, dstId, Dst);
1051 } catch (Exception e) {
1052 EndTransaction();
1053 throw e;
1054 }
1055 EndTransaction();
1056
1057 }
1058
1059 void InstrumentsDb::CopyInstrument(int InstrId, String InstrName, int DstDirId, String DstDir) {
1060 if (GetInstrumentId(DstDirId, InstrName) != -1) {
1061 String s = toEscapedPath(InstrName);
1062 throw Exception("Cannot copy. Instrument with that name already exists: " + s);
1063 }
1064
1065 if (GetDirectoryId(DstDirId, InstrName) != -1) {
1066 String s = toEscapedPath(InstrName);
1067 throw Exception("Cannot copy. Directory with that name already exists: " + s);
1068 }
1069
1070 DbInstrument i = GetInstrumentInfo(InstrId);
1071 sqlite3_stmt *pStmt = NULL;
1072 std::stringstream sql;
1073 sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,instr_nr,format_family,";
1074 sql << "format_version,instr_size,description,is_drum,product,artists,keywords) ";
1075 sql << "VALUES (" << DstDirId << ",?,?," << i.InstrNr << ",?,?," << i.Size << ",?,";
1076 sql << i.IsDrum << ",?,?,?)";
1077
1078 int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
1079 if (res != SQLITE_OK) {
1080 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1081 }
1082
1083 String s = toDbName(InstrName);
1084 BindTextParam(pStmt, 1, s);
1085 BindTextParam(pStmt, 2, i.InstrFile);
1086 BindTextParam(pStmt, 3, i.FormatFamily);
1087 BindTextParam(pStmt, 4, i.FormatVersion);
1088 BindTextParam(pStmt, 5, i.Description);
1089 BindTextParam(pStmt, 6, i.Product);
1090 BindTextParam(pStmt, 7, i.Artists);
1091 BindTextParam(pStmt, 8, i.Keywords);
1092
1093 res = sqlite3_step(pStmt);
1094 if(res != SQLITE_DONE) {
1095 sqlite3_finalize(pStmt);
1096 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1097 }
1098
1099 sqlite3_finalize(pStmt);
1100 FireInstrumentCountChanged(DstDir);
1101 }
1102
1103 void InstrumentsDb::SetInstrumentDescription(String Instr, String Desc) {
1104 dmsg(2,("InstrumentsDb: SetInstrumentDescription(Instr=%s,Desc=%s)\n", Instr.c_str(), Desc.c_str()));
1105
1106 BeginTransaction();
1107 try {
1108 int id = GetInstrumentId(Instr);
1109 if(id == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1110
1111 std::stringstream sql;
1112 sql << "UPDATE instruments SET description=?,modified=CURRENT_TIMESTAMP ";
1113 sql << "WHERE instr_id="<< id;
1114
1115 ExecSql(sql.str(), Desc);
1116 } catch (Exception e) {
1117 EndTransaction();
1118 throw e;
1119 }
1120 EndTransaction();
1121 FireInstrumentInfoChanged(Instr);
1122 }
1123
1124 void InstrumentsDb::AddInstrumentsFromFile(String DbDir, String File, int Index, ScanProgress* pProgress) {
1125 dmsg(2,("InstrumentsDb: AddInstrumentsFromFile(DbDir=%s,File=%s,Index=%d)\n", DbDir.c_str(), File.c_str(), Index));
1126
1127 if(File.length() < 4) return;
1128
1129 try {
1130 if(!strcasecmp(".gig", File.substr(File.length() - 4).c_str())) {
1131 if (pProgress != NULL) {
1132 pProgress->SetStatus(0);
1133 pProgress->CurrentFile = File;
1134 }
1135
1136 AddGigInstruments(DbDir, File, Index, pProgress);
1137
1138 if (pProgress != NULL) {
1139 pProgress->SetScannedFileCount(pProgress->GetScannedFileCount() + 1);
1140 }
1141 }
1142 } catch(Exception e) {
1143 std::cerr << e.Message() << std::endl;
1144 }
1145 }
1146
1147 void InstrumentsDb::AddGigInstruments(String DbDir, String File, int Index, ScanProgress* pProgress) {
1148 dmsg(2,("InstrumentsDb: AddGigInstruments(DbDir=%s,File=%s,Index=%d)\n", DbDir.c_str(), File.c_str(), Index));
1149 int dirId = GetDirectoryId(DbDir);
1150 if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedPath(DbDir));
1151
1152 struct stat statBuf;
1153 int res = stat(File.c_str(), &statBuf);
1154 if (res) {
1155 std::stringstream ss;
1156 ss << "Fail to stat `" << File << "`: " << strerror(errno);
1157 throw Exception(ss.str());
1158 }
1159
1160 if (!S_ISREG(statBuf.st_mode)) {
1161 std::stringstream ss;
1162 ss << "`" << File << "` is not a regular file";
1163 throw Exception(ss.str());
1164 }
1165
1166 RIFF::File* riff = NULL;
1167 gig::File* gig = NULL;
1168 try {
1169 riff = new RIFF::File(File);
1170 gig::File* gig = new gig::File(riff);
1171
1172 std::stringstream sql;
1173 sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,";
1174 sql << "instr_nr,format_family,format_version,instr_size,";
1175 sql << "description,is_drum,product,artists,keywords) VALUES (";
1176 sql << dirId << ",?,?,?,'GIG',?," << statBuf.st_size << ",?,?,?,?,?)";
1177
1178 sqlite3_stmt* pStmt = NULL;
1179
1180 int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
1181 if (res != SQLITE_OK) {
1182 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1183 }
1184
1185 String s = toEscapedFsPath(File);
1186 BindTextParam(pStmt, 2, s);
1187 String ver = "";
1188 if (gig->pVersion != NULL) ver = ToString(gig->pVersion->major);
1189 BindTextParam(pStmt, 4, ver);
1190
1191 if (Index == -1) {
1192 int instrIndex = 0;
1193 if (pProgress != NULL) gig->GetInstrument(0, &(pProgress->GigFileProgress)); // TODO: this workaround should be fixed
1194 gig::Instrument* pInstrument = gig->GetFirstInstrument();
1195 while (pInstrument) {
1196 BindTextParam(pStmt, 7, gig->pInfo->Product);
1197 BindTextParam(pStmt, 8, gig->pInfo->Artists);
1198 BindTextParam(pStmt, 9, gig->pInfo->Keywords);
1199 AddGigInstrument(pStmt, DbDir, dirId, File, pInstrument, instrIndex);
1200
1201 instrIndex++;
1202 pInstrument = gig->GetNextInstrument();
1203 }
1204 } else {
1205 gig::Instrument* pInstrument;
1206 if (pProgress == NULL) pInstrument = gig->GetInstrument(Index);
1207 else pInstrument = gig->GetInstrument(Index, &(pProgress->GigFileProgress));
1208 if (pInstrument != NULL) {
1209 BindTextParam(pStmt, 7, gig->pInfo->Product);
1210 BindTextParam(pStmt, 8, gig->pInfo->Artists);
1211 BindTextParam(pStmt, 9, gig->pInfo->Keywords);
1212 AddGigInstrument(pStmt, DbDir, dirId, File, pInstrument, Index);
1213 }
1214 }
1215
1216 sqlite3_finalize(pStmt);
1217 delete gig;
1218 delete riff;
1219 } catch (RIFF::Exception e) {
1220 if (gig != NULL) delete gig;
1221 if (riff != NULL) delete riff;
1222 std::stringstream ss;
1223 ss << "Failed to scan `" << File << "`: " << e.Message;
1224
1225 throw Exception(ss.str());
1226 } catch (Exception e) {
1227 if (gig != NULL) delete gig;
1228 if (riff != NULL) delete riff;
1229 throw e;
1230 } catch (...) {
1231 if (gig != NULL) delete gig;
1232 if (riff != NULL) delete riff;
1233 throw Exception("Failed to scan `" + File + "`");
1234 }
1235 }
1236
1237 void InstrumentsDb::AddGigInstrument(sqlite3_stmt* pStmt, String DbDir, int DirId, String File, gig::Instrument* pInstrument, int Index) {
1238 String name = pInstrument->pInfo->Name;
1239 if (name == "") return;
1240 name = GetUniqueInstrumentName(DirId, name);
1241
1242 std::stringstream sql2;
1243 sql2 << "SELECT COUNT(*) FROM instruments WHERE instr_file=? AND ";
1244 sql2 << "instr_nr=" << Index;
1245 String s = toEscapedFsPath(File);
1246 if (ExecSqlInt(sql2.str(), s) > 0) return;
1247
1248 BindTextParam(pStmt, 1, name);
1249 BindIntParam(pStmt, 3, Index);
1250
1251 BindTextParam(pStmt, 5, pInstrument->pInfo->Comments);
1252 BindIntParam(pStmt, 6, pInstrument->IsDrum);
1253
1254 if (!pInstrument->pInfo->Product.empty()) {
1255 BindTextParam(pStmt, 7, pInstrument->pInfo->Product);
1256 }
1257 if (!pInstrument->pInfo->Artists.empty()) {
1258 BindTextParam(pStmt, 8, pInstrument->pInfo->Artists);
1259 }
1260
1261 if (!pInstrument->pInfo->Keywords.empty()) {
1262 BindTextParam(pStmt, 9, pInstrument->pInfo->Keywords);
1263 }
1264
1265 int res = sqlite3_step(pStmt);
1266 if(res != SQLITE_DONE) {
1267 sqlite3_finalize(pStmt);
1268 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1269 }
1270
1271 res = sqlite3_reset(pStmt);
1272 FireInstrumentCountChanged(DbDir);
1273 }
1274
1275 void InstrumentsDb::DirectoryTreeWalk(String AbstractPath, DirectoryHandler* pHandler) {
1276 int DirId = GetDirectoryId(AbstractPath);
1277 if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(AbstractPath));
1278 DirectoryTreeWalk(pHandler, AbstractPath, DirId, 0);
1279 }
1280
1281 void InstrumentsDb::DirectoryTreeWalk(DirectoryHandler* pHandler, String AbstractPath, int DirId, int Level) {
1282 if(Level == 1000) throw Exception("Possible infinite loop detected");
1283 pHandler->ProcessDirectory(AbstractPath, DirId);
1284
1285 String s;
1286 StringListPtr pDirs = GetDirectories(DirId);
1287 for(int i = 0; i < pDirs->size(); i++) {
1288 if (AbstractPath.length() == 1 && AbstractPath.at(0) == '/') {
1289 s = "/" + pDirs->at(i);
1290 } else {
1291 s = AbstractPath + "/" + pDirs->at(i);
1292 }
1293 DirectoryTreeWalk(pHandler, s, GetDirectoryId(DirId, pDirs->at(i)), Level + 1);
1294 }
1295 }
1296
1297 StringListPtr InstrumentsDb::FindDirectories(String Dir, SearchQuery* pQuery, bool Recursive) {
1298 dmsg(2,("InstrumentsDb: FindDirectories(Dir=%s)\n", Dir.c_str()));
1299 DirectoryFinder directoryFinder(pQuery);
1300
1301 BeginTransaction();
1302 try {
1303 int DirId = GetDirectoryId(Dir);
1304 if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1305
1306 if (Recursive) DirectoryTreeWalk(Dir, &directoryFinder);
1307 else directoryFinder.ProcessDirectory(Dir, DirId);
1308 } catch (Exception e) {
1309 EndTransaction();
1310 throw e;
1311 }
1312 EndTransaction();
1313
1314 return directoryFinder.GetDirectories();
1315 }
1316
1317 StringListPtr InstrumentsDb::FindInstruments(String Dir, SearchQuery* pQuery, bool Recursive) {
1318 dmsg(2,("InstrumentsDb: FindInstruments(Dir=%s)\n", Dir.c_str()));
1319 InstrumentFinder instrumentFinder(pQuery);
1320
1321 BeginTransaction();
1322 try {
1323 int DirId = GetDirectoryId(Dir);
1324 if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1325
1326 if (Recursive) DirectoryTreeWalk(Dir, &instrumentFinder);
1327 else instrumentFinder.ProcessDirectory(Dir, DirId);
1328 } catch (Exception e) {
1329 EndTransaction();
1330 throw e;
1331 }
1332 EndTransaction();
1333
1334 return instrumentFinder.GetInstruments();
1335 }
1336
1337 void InstrumentsDb::BeginTransaction() {
1338 dmsg(2,("InstrumentsDb: BeginTransaction(InTransaction=%d)\n", InTransaction));
1339 DbInstrumentsMutex.Lock();
1340 if (InTransaction) return;
1341
1342 if(db == NULL) return;
1343 sqlite3_stmt *pStmt = NULL;
1344
1345 InTransaction = true;
1346 int res = sqlite3_prepare(db, "BEGIN TRANSACTION", -1, &pStmt, NULL);
1347 if (res != SQLITE_OK) {
1348 std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1349 return;
1350 }
1351
1352 res = sqlite3_step(pStmt);
1353 if(res != SQLITE_DONE) {
1354 sqlite3_finalize(pStmt);
1355 std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1356 return;
1357 }
1358
1359 sqlite3_finalize(pStmt);
1360 }
1361
1362 void InstrumentsDb::EndTransaction() {
1363 dmsg(2,("InstrumentsDb: EndTransaction(InTransaction=%d)\n", InTransaction));
1364 if (!InTransaction) {
1365 DbInstrumentsMutex.Unlock();
1366 return;
1367 }
1368 InTransaction = false;
1369
1370 if(db == NULL) {
1371 DbInstrumentsMutex.Unlock();
1372 return;
1373 }
1374 sqlite3_stmt *pStmt = NULL;
1375
1376 int res = sqlite3_prepare(db, "END TRANSACTION", -1, &pStmt, NULL);
1377 if (res != SQLITE_OK) {
1378 std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1379 DbInstrumentsMutex.Unlock();
1380 return;
1381 }
1382
1383 res = sqlite3_step(pStmt);
1384 if(res != SQLITE_DONE) {
1385 sqlite3_finalize(pStmt);
1386 std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1387 DbInstrumentsMutex.Unlock();
1388 return;
1389 }
1390
1391 sqlite3_finalize(pStmt);
1392 DbInstrumentsMutex.Unlock();
1393 }
1394
1395 void InstrumentsDb::ExecSql(String Sql) {
1396 dmsg(2,("InstrumentsDb: ExecSql(Sql=%s)\n", Sql.c_str()));
1397 sqlite3_stmt *pStmt = NULL;
1398
1399 int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1400 if (res != SQLITE_OK) {
1401 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1402 }
1403
1404 res = sqlite3_step(pStmt);
1405 if(res != SQLITE_DONE) {
1406 sqlite3_finalize(pStmt);
1407 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1408 }
1409
1410 sqlite3_finalize(pStmt);
1411 }
1412
1413 void InstrumentsDb::ExecSql(String Sql, String Param) {
1414 dmsg(2,("InstrumentsDb: ExecSql(Sql=%s,Param=%s)\n", Sql.c_str(), Param.c_str()));
1415 sqlite3_stmt *pStmt = NULL;
1416
1417 int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1418 if (res != SQLITE_OK) {
1419 sqlite3_finalize(pStmt);
1420 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1421 }
1422
1423 BindTextParam(pStmt, 1, Param);
1424
1425 res = sqlite3_step(pStmt);
1426 if (res != SQLITE_DONE) {
1427 sqlite3_finalize(pStmt);
1428 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1429 }
1430
1431 sqlite3_finalize(pStmt);
1432 }
1433
1434 int InstrumentsDb::ExecSqlInt(String Sql) {
1435 dmsg(2,("InstrumentsDb: ExecSqlInt(Sql=%s)\n", Sql.c_str()));
1436 sqlite3_stmt *pStmt = NULL;
1437
1438 int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1439 if (res != SQLITE_OK) {
1440 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1441 }
1442
1443 int i = -1;
1444 res = sqlite3_step(pStmt);
1445 if(res == SQLITE_ROW) {
1446 i = sqlite3_column_int(pStmt, 0);
1447 } else if (res != SQLITE_DONE) {
1448 sqlite3_finalize(pStmt);
1449 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1450 }
1451
1452 sqlite3_finalize(pStmt);
1453
1454 return i;
1455 }
1456
1457 int InstrumentsDb::ExecSqlInt(String Sql, String Param) {
1458 dmsg(2,("InstrumentsDb: ExecSqlInt(Sql=%s,Param=%s)\n", Sql.c_str(), Param.c_str()));
1459 sqlite3_stmt *pStmt = NULL;
1460
1461 int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1462 if (res != SQLITE_OK) {
1463 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1464 }
1465
1466 BindTextParam(pStmt, 1, Param);
1467
1468 int i = -1;
1469 res = sqlite3_step(pStmt);
1470 if(res == SQLITE_ROW) {
1471 i = sqlite3_column_int(pStmt, 0);
1472 } else if (res != SQLITE_DONE) {
1473 sqlite3_finalize(pStmt);
1474 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1475 }
1476
1477 sqlite3_finalize(pStmt);
1478 return i;
1479 }
1480
1481 String InstrumentsDb::ExecSqlString(String Sql) {
1482 dmsg(2,("InstrumentsDb: ExecSqlString(Sql=%s)\n", Sql.c_str()));
1483 sqlite3_stmt *pStmt = NULL;
1484
1485 int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1486 if (res != SQLITE_OK) {
1487 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1488 }
1489
1490 String s;
1491 res = sqlite3_step(pStmt);
1492 if(res == SQLITE_ROW) {
1493 s = ToString(sqlite3_column_text(pStmt, 0));
1494 } else if (res != SQLITE_DONE) {
1495 sqlite3_finalize(pStmt);
1496 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1497 }
1498
1499 sqlite3_finalize(pStmt);
1500
1501 return s;
1502 }
1503
1504 IntListPtr InstrumentsDb::ExecSqlIntList(String Sql) {
1505 IntListPtr intList(new std::vector<int>);
1506
1507 sqlite3_stmt *pStmt = NULL;
1508
1509 int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1510 if (res != SQLITE_OK) {
1511 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1512 }
1513
1514 res = sqlite3_step(pStmt);
1515 while(res == SQLITE_ROW) {
1516 intList->push_back(sqlite3_column_int(pStmt, 0));
1517 res = sqlite3_step(pStmt);
1518 }
1519
1520 if (res != SQLITE_DONE) {
1521 sqlite3_finalize(pStmt);
1522 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1523 }
1524
1525 sqlite3_finalize(pStmt);
1526
1527 return intList;
1528 }
1529
1530 StringListPtr InstrumentsDb::ExecSqlStringList(String Sql) {
1531 StringListPtr stringList(new std::vector<String>);
1532
1533 sqlite3_stmt *pStmt = NULL;
1534
1535 int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1536 if (res != SQLITE_OK) {
1537 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1538 }
1539
1540 res = sqlite3_step(pStmt);
1541 while(res == SQLITE_ROW) {
1542 stringList->push_back(ToString(sqlite3_column_text(pStmt, 0)));
1543 res = sqlite3_step(pStmt);
1544 }
1545
1546 if (res != SQLITE_DONE) {
1547 sqlite3_finalize(pStmt);
1548 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1549 }
1550
1551 sqlite3_finalize(pStmt);
1552
1553 return stringList;
1554 }
1555
1556 void InstrumentsDb::BindTextParam(sqlite3_stmt* pStmt, int Index, String Text) {
1557 if (pStmt == NULL) return;
1558 int res = sqlite3_bind_text(pStmt, Index, Text.c_str(), -1, SQLITE_STATIC);
1559 if (res != SQLITE_OK) {
1560 sqlite3_finalize(pStmt);
1561 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1562 }
1563 }
1564
1565 void InstrumentsDb::BindIntParam(sqlite3_stmt* pStmt, int Index, int Param) {
1566 if (pStmt == NULL) return;
1567 int res = sqlite3_bind_int(pStmt, Index, Param);
1568 if (res != SQLITE_OK) {
1569 sqlite3_finalize(pStmt);
1570 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1571 }
1572 }
1573
1574 void InstrumentsDb::Regexp(sqlite3_context* pContext, int argc, sqlite3_value** ppValue) {
1575 if (argc != 2) return;
1576
1577 String pattern = ToString(sqlite3_value_text(ppValue[0]));
1578 String str = ToString(sqlite3_value_text(ppValue[1]));
1579
1580 if(!fnmatch(pattern.c_str(), str.c_str(), FNM_CASEFOLD)) {
1581 sqlite3_result_int(pContext, 1);
1582 }
1583 }
1584
1585 String InstrumentsDb::GetDirectoryPath(String File) {
1586 if (File.empty()) return String("");
1587 if (File.at(0) != '/') String("");
1588 if (File.length() == 1) return File;
1589 if (File.at(File.length() - 1) == '/') return File.substr(0, File.length() - 1);
1590 int i = File.rfind('/', File.length() - 1);
1591 if(i == std::string::npos) return String("");
1592 if(i == 0) return String("/");
1593 return File.substr(0, i);
1594 }
1595
1596 String InstrumentsDb::GetFileName(String Path) {
1597 if (Path.length() < 2) return String("");
1598 if (Path.at(0) != '/') String("");
1599 if (Path.at(Path.length() - 1) == '/') return String("");
1600 int i = Path.rfind('/', Path.length() - 1);
1601 return Path.substr(i + 1);
1602 }
1603
1604 void InstrumentsDb::CheckPathName(String Path) {
1605 if (Path.empty()) return;
1606
1607 int i = 0, j = Path.find('/', i);
1608
1609 while(j != std::string::npos) {
1610 if (j + 1 >= Path.length()) return;
1611 if (Path.at(j + 1) == '/') throw Exception("Invalid path name: " + Path);
1612
1613 i = j + 1;
1614 j = Path.find('/', i);
1615 }
1616 }
1617
1618 String InstrumentsDb::GetParentDirectory(String Dir) {
1619 if (Dir.length() < 2) return String("");
1620 if (Dir.at(0) != '/') String("");
1621 int i = Dir.rfind('/', Dir.length() - 2);
1622 if (i == 0) return "/";
1623 return Dir.substr(0, i);
1624 }
1625
1626 void InstrumentsDb::Format() {
1627 DbInstrumentsMutex.Lock();
1628 if (db != NULL) {
1629 sqlite3_close(db);
1630 db = NULL;
1631 }
1632
1633 if (DbFile.empty()) DbFile = CONFIG_DEFAULT_INSTRUMENTS_DB_LOCATION;
1634 String bkp = DbFile + ".bkp";
1635 remove(bkp.c_str());
1636 if (rename(DbFile.c_str(), bkp.c_str()) && errno != ENOENT) {
1637 DbInstrumentsMutex.Unlock();
1638 throw Exception(String("Failed to backup database: ") + strerror(errno));
1639 }
1640
1641 String f = DbFile;
1642 DbFile = "";
1643 try { CreateInstrumentsDb(f); }
1644 catch(Exception e) {
1645 DbInstrumentsMutex.Unlock();
1646 throw e;
1647 }
1648 DbInstrumentsMutex.Unlock();
1649
1650 FireDirectoryCountChanged("/");
1651 FireInstrumentCountChanged("/");
1652 }
1653
1654 void InstrumentsDb::CheckFileName(String File) {
1655 if (File.empty()) throw Exception("Invalid file name: " + File);
1656 }
1657
1658 String InstrumentsDb::GetUniqueInstrumentName(int DirId, String Name) {
1659 dmsg(2,("InstrumentsDb: GetUniqueInstrumentName(DirId=%d,Name=%s)\n", DirId, Name.c_str()));
1660
1661 if (GetInstrumentId(DirId, Name) == -1 && GetDirectoryId(DirId, Name) == -1) return Name;
1662 std::stringstream ss;
1663 for(int i = 2; i < 1001; i++) {
1664 ss.str("");
1665 ss << Name << '[' << i << ']';
1666 if (GetInstrumentId(DirId, ss.str()) == -1 && GetInstrumentId(DirId, ss.str()) == -1) {
1667 return ss.str();
1668 }
1669 }
1670
1671 throw Exception("Unable to find an unique name: " + Name);
1672 }
1673
1674 String InstrumentsDb::toDbName(String AbstractName) {
1675 for (int i = 0; i < AbstractName.length(); i++) {
1676 if (AbstractName.at(i) == '\0') AbstractName.at(i) = '/';
1677 }
1678 return AbstractName;
1679 }
1680
1681 String InstrumentsDb::toEscapedPath(String AbstractName) {
1682 for (int i = 0; i < AbstractName.length(); i++) {
1683 if (AbstractName.at(i) == '\0') AbstractName.replace(i++, 1, "\\x2f");
1684 else if (AbstractName.at(i) == '\\') AbstractName.replace(i++, 1, "\\\\");
1685 else if (AbstractName.at(i) == '\'') AbstractName.replace(i++, 1, "\\'");
1686 else if (AbstractName.at(i) == '"') AbstractName.replace(i++, 1, "\\\"");
1687 else if (AbstractName.at(i) == '\r') AbstractName.replace(i++, 1, "\\r");
1688 else if (AbstractName.at(i) == '\n') AbstractName.replace(i++, 1, "\\n");
1689 }
1690 return AbstractName;
1691 }
1692
1693 String InstrumentsDb::toEscapedText(String text) {
1694 for (int i = 0; i < text.length(); i++) {
1695 if (text.at(i) == '\\') text.replace(i++, 1, "\\\\");
1696 else if (text.at(i) == '\'') text.replace(i++, 1, "\\'");
1697 else if (text.at(i) == '"') text.replace(i++, 1, "\\\"");
1698 else if (text.at(i) == '\r') text.replace(i++, 1, "\\r");
1699 else if (text.at(i) == '\n') text.replace(i++, 1, "\\n");
1700 }
1701 return text;
1702 }
1703
1704 String InstrumentsDb::toEscapedFsPath(String FsPath) {
1705 return toEscapedText(FsPath);
1706 }
1707
1708 String InstrumentsDb::toAbstractName(String DbName) {
1709 for (int i = 0; i < DbName.length(); i++) {
1710 if (DbName.at(i) == '/') DbName.at(i) = '\0';
1711 }
1712 return DbName;
1713 }
1714
1715 void InstrumentsDb::FireDirectoryCountChanged(String Dir) {
1716 for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1717 llInstrumentsDbListeners.GetListener(i)->DirectoryCountChanged(Dir);
1718 }
1719 }
1720
1721 void InstrumentsDb::FireDirectoryInfoChanged(String Dir) {
1722 for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1723 llInstrumentsDbListeners.GetListener(i)->DirectoryInfoChanged(Dir);
1724 }
1725 }
1726
1727 void InstrumentsDb::FireDirectoryNameChanged(String Dir, String NewName) {
1728 for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1729 llInstrumentsDbListeners.GetListener(i)->DirectoryNameChanged(Dir, NewName);
1730 }
1731 }
1732
1733 void InstrumentsDb::FireInstrumentCountChanged(String Dir) {
1734 for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1735 llInstrumentsDbListeners.GetListener(i)->InstrumentCountChanged(Dir);
1736 }
1737 }
1738
1739 void InstrumentsDb::FireInstrumentInfoChanged(String Instr) {
1740 for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1741 llInstrumentsDbListeners.GetListener(i)->InstrumentInfoChanged(Instr);
1742 }
1743 }
1744
1745 void InstrumentsDb::FireInstrumentNameChanged(String Instr, String NewName) {
1746 for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1747 llInstrumentsDbListeners.GetListener(i)->InstrumentNameChanged(Instr, NewName);
1748 }
1749 }
1750
1751 void InstrumentsDb::FireJobStatusChanged(int JobId) {
1752 for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1753 llInstrumentsDbListeners.GetListener(i)->JobStatusChanged(JobId);
1754 }
1755 }
1756
1757 } // namespace LinuxSampler
1758
1759 #endif // HAVE_SQLITE3

  ViewVC Help
Powered by ViewVC