/[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 1642 - (show annotations) (download)
Sun Jan 13 16:36:14 2008 UTC (16 years, 3 months ago) by nagata
File size: 66185 byte(s)
* OSX: Definition of ATOMIC_INIT is added
* OSX: "~" in DB/plugin names are expanded to "$HOME"
* OSX: MIDI device name are now "linuxsampler_in_%d" where %d=0,1,etc.

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

  ViewVC Help
Powered by ViewVC