/[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 1644 - (show annotations) (download)
Sat Jan 19 16:55:03 2008 UTC (16 years, 2 months ago) by persson
File size: 65992 byte(s)
* fixed memory leaks that occurred when liblinuxsampler was unloaded
* fixed a memory leak that could happen when a channel was deleted
  while notes were playing
* fixed memory management bug in ASIO driver
* optimized the SynchronizedConfig class so it doesn't wait
  unnecessarily long after an update

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

  ViewVC Help
Powered by ViewVC