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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1908 - (show annotations) (download)
Mon Jun 1 18:50:06 2009 UTC (14 years, 10 months ago) by persson
File size: 21178 byte(s)
* VST: avoid opening Fantasia more than once for each VST instance
* VST: export main function as "main" on Linux too (fix for energyXT)
* VST: prepare code for multiple output channels
* work-around for missing fnmatch function on Windows to make
  instrument database compilable

1 /***************************************************************************
2 * *
3 * Copyright (C) 2007 - 2009 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 "InstrumentsDbUtilities.h"
22
23 #include "../common/File.h"
24 #include "../common/global_private.h"
25
26 #include <errno.h>
27
28 #include "../common/Exception.h"
29 #include "InstrumentsDb.h"
30
31 namespace LinuxSampler {
32
33 void DbInstrument::Copy(const DbInstrument& Instr) {
34 if (this == &Instr) return;
35
36 InstrFile = Instr.InstrFile;
37 InstrNr = Instr.InstrNr;
38 FormatFamily = Instr.FormatFamily;
39 FormatVersion = Instr.FormatVersion;
40 Size = Instr.Size;
41 Created = Instr.Created;
42 Modified = Instr.Modified;
43 Description = Instr.Description;
44 IsDrum = Instr.IsDrum;
45 Product = Instr.Product;
46 Artists = Instr.Artists;
47 Keywords = Instr.Keywords;
48 }
49
50
51 void DbDirectory::Copy(const DbDirectory& Dir) {
52 if (this == &Dir) return;
53
54 Created = Dir.Created;
55 Modified = Dir.Modified;
56 Description = Dir.Description;
57 }
58
59 SearchQuery::SearchQuery() {
60 MinSize = -1;
61 MaxSize = -1;
62 InstrType = BOTH;
63 }
64
65 void SearchQuery::SetFormatFamilies(String s) {
66 if (s.length() == 0) return;
67 int i = 0;
68 int j = s.find(',', 0);
69
70 while (j != std::string::npos) {
71 FormatFamilies.push_back(s.substr(i, j - i));
72 i = j + 1;
73 j = s.find(',', i);
74 }
75
76 if (i < s.length()) FormatFamilies.push_back(s.substr(i));
77 }
78
79 void SearchQuery::SetSize(String s) {
80 String s2 = GetMin(s);
81 if (s2.length() > 0) MinSize = atoll(s2.c_str());
82 else MinSize = -1;
83
84 s2 = GetMax(s);
85 if (s2.length() > 0) MaxSize = atoll(s2.c_str());
86 else MaxSize = -1;
87 }
88
89 void SearchQuery::SetCreated(String s) {
90 CreatedAfter = GetMin(s);
91 CreatedBefore = GetMax(s);
92 }
93
94 void SearchQuery::SetModified(String s) {
95 ModifiedAfter = GetMin(s);
96 ModifiedBefore = GetMax(s);
97 }
98
99 String SearchQuery::GetMin(String s) {
100 if (s.length() < 3) return "";
101 if (s.at(0) == '.' && s.at(1) == '.') return "";
102 int i = s.find("..");
103 if (i == std::string::npos) return "";
104 return s.substr(0, i);
105 }
106
107 String SearchQuery::GetMax(String s) {
108 if (s.length() < 3) return "";
109 if (s.find("..", s.length() - 2) != std::string::npos) return "";
110 int i = s.find("..");
111 if (i == std::string::npos) return "";
112 return s.substr(i + 2);
113 }
114
115 void ScanJob::Copy(const ScanJob& Job) {
116 if (this == &Job) return;
117
118 JobId = Job.JobId;
119 FilesTotal = Job.FilesTotal;
120 FilesScanned = Job.FilesScanned;
121 Scanning = Job.Scanning;
122 Status = Job.Status;
123 }
124
125 int JobList::AddJob(ScanJob Job) {
126 if (Counter + 1 < Counter) Counter = 0;
127 else Counter++;
128 Job.JobId = Counter;
129 Jobs.push_back(Job);
130 if (Jobs.size() > 3) {
131 std::vector<ScanJob>::iterator iter = Jobs.begin();
132 Jobs.erase(iter);
133 }
134 return Job.JobId;
135 }
136
137 ScanJob& JobList::GetJobById(int JobId) {
138 for (int i = 0; i < Jobs.size(); i++) {
139 if (Jobs.at(i).JobId == JobId) return Jobs.at(i);
140 }
141
142 throw Exception("Invalid job ID: " + ToString(JobId));
143 }
144
145 bool AbstractFinder::IsRegex(String Pattern) {
146 if(Pattern.find('?') != String::npos) return true;
147 if(Pattern.find('*') != String::npos) return true;
148 return false;
149 }
150
151 void AbstractFinder::AddSql(String Col, String Pattern, std::stringstream& Sql) {
152 if (Pattern.length() == 0) return;
153
154 if (IsRegex(Pattern)) {
155 #ifndef WIN32
156 Sql << " AND " << Col << " regexp ?";
157 #else
158 for (int i = 0; i < Pattern.length(); i++) {
159 if (Pattern.at(i) == '?') Pattern.at(i) = '_';
160 else if (Pattern.at(i) == '*') Pattern.at(i) = '%';
161 }
162 Sql << " AND " << Col << " LIKE ?";
163 #endif
164 Params.push_back(Pattern);
165 return;
166 }
167
168 String buf;
169 std::vector<String> tokens;
170 std::vector<String> tokens2;
171 std::stringstream ss(Pattern);
172 while (ss >> buf) tokens.push_back(buf);
173
174 if (tokens.size() == 0) {
175 Sql << " AND " << Col << " LIKE ?";
176 Params.push_back("%" + Pattern + "%");
177 return;
178 }
179
180 bool b = false;
181 for (int i = 0; i < tokens.size(); i++) {
182 Sql << (i == 0 ? " AND (" : "");
183
184 for (int j = 0; j < tokens.at(i).length(); j++) {
185 if (tokens.at(i).at(j) == '+') tokens.at(i).at(j) = ' ';
186 }
187
188 ss.clear();
189 ss.str("");
190 ss << tokens.at(i);
191
192 tokens2.clear();
193 while (ss >> buf) tokens2.push_back(buf);
194
195 if (b && tokens2.size() > 0) Sql << " OR ";
196 if (tokens2.size() > 1) Sql << "(";
197 for (int j = 0; j < tokens2.size(); j++) {
198 if (j != 0) Sql << " AND ";
199 Sql << Col << " LIKE ?";
200 Params.push_back("%" + tokens2.at(j) + "%");
201 b = true;
202 }
203 if (tokens2.size() > 1) Sql << ")";
204 }
205 if (!b) Sql << "0)";
206 else Sql << ")";
207 }
208
209 DirectoryFinder::DirectoryFinder(SearchQuery* pQuery) : pDirectories(new std::vector<String>) {
210 pStmt = NULL;
211 this->pQuery = pQuery;
212 std::stringstream sql;
213 sql << "SELECT dir_name from instr_dirs WHERE dir_id!=0 AND parent_dir_id=?";
214
215 if (pQuery->CreatedAfter.length() != 0) {
216 sql << " AND created > ?";
217 Params.push_back(pQuery->CreatedAfter);
218 }
219 if (pQuery->CreatedBefore.length() != 0) {
220 sql << " AND created < ?";
221 Params.push_back(pQuery->CreatedBefore);
222 }
223 if (pQuery->ModifiedAfter.length() != 0) {
224 sql << " AND modified > ?";
225 Params.push_back(pQuery->ModifiedAfter);
226 }
227 if (pQuery->ModifiedBefore.length() != 0) {
228 sql << " AND modified < ?";
229 Params.push_back(pQuery->ModifiedBefore);
230 }
231
232 AddSql("dir_name", pQuery->Name, sql);
233 AddSql("description", pQuery->Description, sql);
234 SqlQuery = sql.str();
235
236 InstrumentsDb* idb = InstrumentsDb::GetInstrumentsDb();
237
238 int res = sqlite3_prepare(idb->GetDb(), SqlQuery.c_str(), -1, &pStmt, NULL);
239 if (res != SQLITE_OK) {
240 throw Exception("DB error: " + ToString(sqlite3_errmsg(idb->GetDb())));
241 }
242
243 for(int i = 0; i < Params.size(); i++) {
244 idb->BindTextParam(pStmt, i + 2, Params.at(i));
245 }
246 }
247
248 DirectoryFinder::~DirectoryFinder() {
249 if (pStmt != NULL) sqlite3_finalize(pStmt);
250 }
251
252 StringListPtr DirectoryFinder::GetDirectories() {
253 return pDirectories;
254 }
255
256 void DirectoryFinder::ProcessDirectory(String Path, int DirId) {
257 InstrumentsDb* idb = InstrumentsDb::GetInstrumentsDb();
258 idb->BindIntParam(pStmt, 1, DirId);
259
260 String s = Path;
261 if(Path.compare("/") != 0) s += "/";
262 int res = sqlite3_step(pStmt);
263 while(res == SQLITE_ROW) {
264 pDirectories->push_back(s + idb->toAbstractName(ToString(sqlite3_column_text(pStmt, 0))));
265 res = sqlite3_step(pStmt);
266 }
267
268 if (res != SQLITE_DONE) {
269 sqlite3_finalize(pStmt);
270 throw Exception("DB error: " + ToString(sqlite3_errmsg(idb->GetDb())));
271 }
272
273 res = sqlite3_reset(pStmt);
274 if (res != SQLITE_OK) {
275 sqlite3_finalize(pStmt);
276 throw Exception("DB error: " + ToString(sqlite3_errmsg(idb->GetDb())));
277 }
278 }
279
280 InstrumentFinder::InstrumentFinder(SearchQuery* pQuery) : pInstruments(new std::vector<String>) {
281 pStmt = NULL;
282 this->pQuery = pQuery;
283 std::stringstream sql;
284 sql << "SELECT instr_name from instruments WHERE dir_id=?";
285
286 if (pQuery->CreatedAfter.length() != 0) {
287 sql << " AND created > ?";
288 Params.push_back(pQuery->CreatedAfter);
289 }
290 if (pQuery->CreatedBefore.length() != 0) {
291 sql << " AND created < ?";
292 Params.push_back(pQuery->CreatedBefore);
293 }
294 if (pQuery->ModifiedAfter.length() != 0) {
295 sql << " AND modified > ?";
296 Params.push_back(pQuery->ModifiedAfter);
297 }
298 if (pQuery->ModifiedBefore.length() != 0) {
299 sql << " AND modified < ?";
300 Params.push_back(pQuery->ModifiedBefore);
301 }
302 if (pQuery->MinSize != -1) sql << " AND instr_size > " << pQuery->MinSize;
303 if (pQuery->MaxSize != -1) sql << " AND instr_size < " << pQuery->MaxSize;
304
305 if (pQuery->InstrType == SearchQuery::CHROMATIC) sql << " AND is_drum = 0";
306 else if (pQuery->InstrType == SearchQuery::DRUM) sql << " AND is_drum != 0";
307
308 if (pQuery->FormatFamilies.size() > 0) {
309 sql << " AND (format_family=?";
310 Params.push_back(pQuery->FormatFamilies.at(0));
311 for (int i = 1; i < pQuery->FormatFamilies.size(); i++) {
312 sql << "OR format_family=?";
313 Params.push_back(pQuery->FormatFamilies.at(i));
314 }
315 sql << ")";
316 }
317
318 AddSql("instr_name", pQuery->Name, sql);
319 AddSql("description", pQuery->Description, sql);
320 AddSql("product", pQuery->Product, sql);
321 AddSql("artists", pQuery->Artists, sql);
322 AddSql("keywords", pQuery->Keywords, sql);
323 SqlQuery = sql.str();
324
325 InstrumentsDb* idb = InstrumentsDb::GetInstrumentsDb();
326
327 int res = sqlite3_prepare(idb->GetDb(), SqlQuery.c_str(), -1, &pStmt, NULL);
328 if (res != SQLITE_OK) {
329 throw Exception("DB error: " + ToString(sqlite3_errmsg(idb->GetDb())));
330 }
331
332 for(int i = 0; i < Params.size(); i++) {
333 idb->BindTextParam(pStmt, i + 2, Params.at(i));
334 }
335 }
336
337 InstrumentFinder::~InstrumentFinder() {
338 if (pStmt != NULL) sqlite3_finalize(pStmt);
339 }
340
341 void InstrumentFinder::ProcessDirectory(String Path, int DirId) {
342 InstrumentsDb* idb = InstrumentsDb::GetInstrumentsDb();
343 idb->BindIntParam(pStmt, 1, DirId);
344
345 String s = Path;
346 if(Path.compare("/") != 0) s += "/";
347 int res = sqlite3_step(pStmt);
348 while(res == SQLITE_ROW) {
349 pInstruments->push_back(s + idb->toAbstractName(ToString(sqlite3_column_text(pStmt, 0))));
350 res = sqlite3_step(pStmt);
351 }
352
353 if (res != SQLITE_DONE) {
354 sqlite3_finalize(pStmt);
355 throw Exception("DB error: " + ToString(sqlite3_errmsg(idb->GetDb())));
356 }
357
358 res = sqlite3_reset(pStmt);
359 if (res != SQLITE_OK) {
360 sqlite3_finalize(pStmt);
361 throw Exception("DB error: " + ToString(sqlite3_errmsg(idb->GetDb())));
362 }
363 }
364
365 StringListPtr InstrumentFinder::GetInstruments() {
366 return pInstruments;
367 }
368
369 void DirectoryCounter::ProcessDirectory(String Path, int DirId) {
370 count += InstrumentsDb::GetInstrumentsDb()->GetDirectoryCount(DirId);
371 }
372
373 void InstrumentCounter::ProcessDirectory(String Path, int DirId) {
374 count += InstrumentsDb::GetInstrumentsDb()->GetInstrumentCount(DirId);
375 }
376
377 DirectoryCopier::DirectoryCopier(String SrcParentDir, String DestDir) {
378 this->SrcParentDir = SrcParentDir;
379 this->DestDir = DestDir;
380
381 if (DestDir.at(DestDir.length() - 1) != '/') {
382 this->DestDir.append("/");
383 }
384 if (SrcParentDir.at(SrcParentDir.length() - 1) != '/') {
385 this->SrcParentDir.append("/");
386 }
387 }
388
389 void DirectoryCopier::ProcessDirectory(String Path, int DirId) {
390 InstrumentsDb* db = InstrumentsDb::GetInstrumentsDb();
391
392 String dir = DestDir;
393 String subdir = Path;
394 if(subdir.length() > SrcParentDir.length()) {
395 subdir = subdir.substr(SrcParentDir.length());
396 dir += subdir;
397 db->AddDirectory(dir);
398 }
399
400 int dstDirId = db->GetDirectoryId(dir);
401 if(dstDirId == -1) {
402 throw Exception("Unkown DB directory: " + InstrumentsDb::toEscapedPath(dir));
403 }
404 IntListPtr ids = db->GetInstrumentIDs(DirId);
405 for (int i = 0; i < ids->size(); i++) {
406 String name = db->GetInstrumentName(ids->at(i));
407 db->CopyInstrument(ids->at(i), name, dstDirId, dir);
408 }
409 }
410
411 ScanProgress::ScanProgress() {
412 TotalFileCount = ScannedFileCount = Status = 0;
413 CurrentFile = "";
414 GigFileProgress.custom = this;
415 GigFileProgress.callback = GigFileProgressCallback;
416 }
417
418 void ScanProgress::StatusChanged() {
419 InstrumentsDb* db = InstrumentsDb::GetInstrumentsDb();
420 db->Jobs.GetJobById(JobId).FilesTotal = GetTotalFileCount();
421 db->Jobs.GetJobById(JobId).FilesScanned = GetScannedFileCount();
422 db->Jobs.GetJobById(JobId).Scanning = CurrentFile;
423 db->Jobs.GetJobById(JobId).Status = GetStatus();
424
425 InstrumentsDb::GetInstrumentsDb()->FireJobStatusChanged(JobId);
426 }
427
428 int ScanProgress::GetTotalFileCount() {
429 return TotalFileCount;
430 }
431
432 void ScanProgress::SetTotalFileCount(int Count) {
433 if (TotalFileCount == Count) return;
434 TotalFileCount = Count;
435 StatusChanged();
436 }
437
438 int ScanProgress::GetScannedFileCount() {
439 return ScannedFileCount;
440 }
441
442 void ScanProgress::SetScannedFileCount(int Count) {
443 if (ScannedFileCount == Count) return;
444 ScannedFileCount = Count;
445 if (Count > TotalFileCount) TotalFileCount = Count;
446 StatusChanged();
447 }
448
449 int ScanProgress::GetStatus() {
450 return Status;
451 }
452
453 void ScanProgress::SetStatus(int Status) {
454 if (this->Status == Status) return;
455 if (Status < 0) this->Status = 0;
456 else if (Status > 100) this->Status = 100;
457 else this->Status = Status;
458 StatusChanged();
459 }
460
461 void ScanProgress::SetErrorStatus(int Err) {
462 if (Err > 0) Err *= -1;
463 Status = Err;
464 StatusChanged();
465 }
466
467 void ScanProgress::GigFileProgressCallback(gig::progress_t* pProgress) {
468 if (pProgress == NULL) return;
469 ScanProgress* sp = static_cast<ScanProgress*> (pProgress->custom);
470
471 sp->SetStatus((int)(pProgress->factor * 100));
472 }
473
474 AddInstrumentsJob::AddInstrumentsJob(int JobId, ScanMode Mode, String DbDir, String FsDir, bool insDir) {
475 this->JobId = JobId;
476 Progress.JobId = JobId;
477 this->Mode = Mode;
478 this->DbDir = DbDir;
479 this->FsDir = FsDir;
480 this->insDir = insDir;
481 }
482
483 void AddInstrumentsJob::Run() {
484 try {
485 InstrumentsDb* db = InstrumentsDb::GetInstrumentsDb();
486
487 switch (Mode) {
488 case NON_RECURSIVE:
489 Progress.SetTotalFileCount(GetFileCount());
490 db->AddInstrumentsNonrecursive(DbDir, FsDir, insDir, &Progress);
491 break;
492 case RECURSIVE:
493 db->AddInstrumentsRecursive(DbDir, FsDir, false, insDir, &Progress);
494 break;
495 case FLAT:
496 db->AddInstrumentsRecursive(DbDir, FsDir, true, insDir, &Progress);
497 break;
498 default:
499 throw Exception("Unknown scan mode");
500 }
501
502 // Just to be sure that the frontends will be notified about the job completion
503 if (Progress.GetTotalFileCount() != Progress.GetScannedFileCount()) {
504 Progress.SetTotalFileCount(Progress.GetScannedFileCount());
505 }
506 if (Progress.GetStatus() != 100) Progress.SetStatus(100);
507 } catch(Exception e) {
508 Progress.SetErrorStatus(-1);
509 throw e;
510 }
511 }
512
513 int AddInstrumentsJob::GetFileCount() {
514 int count = 0;
515
516 try {
517 FileListPtr fileList = File::GetFiles(FsDir);
518
519 for (int i = 0; i < fileList->size(); i++) {
520 String s = fileList->at(i);
521 if (s.length() < 4) continue;
522 if(!strcasecmp(".gig", s.substr(s.length() - 4).c_str())) count++;
523 }
524 } catch(Exception e) {
525 e.PrintMessage();
526 return 0;
527 }
528
529 return count;
530 }
531
532 AddInstrumentsFromFileJob::AddInstrumentsFromFileJob(int JobId, String DbDir, String FilePath, int Index, bool insDir) {
533 this->JobId = JobId;
534 Progress.JobId = JobId;
535 Progress.SetTotalFileCount(1);
536
537 this->DbDir = DbDir;
538 this->FilePath = FilePath;
539 this->Index = Index;
540 this->insDir = insDir;
541 }
542
543 void AddInstrumentsFromFileJob::Run() {
544 try {
545 InstrumentsDb::GetInstrumentsDb()->AddInstruments(DbDir, insDir, FilePath, Index, &Progress);
546
547 // Just to be sure that the frontends will be notified about the job completion
548 if (Progress.GetTotalFileCount() != Progress.GetScannedFileCount()) {
549 Progress.SetTotalFileCount(Progress.GetScannedFileCount());
550 }
551 if (Progress.GetStatus() != 100) Progress.SetStatus(100);
552 } catch(Exception e) {
553 Progress.SetErrorStatus(-1);
554 throw e;
555 }
556 }
557
558
559 void DirectoryScanner::Scan(String DbDir, String FsDir, bool Flat, bool insDir, ScanProgress* pProgress) {
560 dmsg(2,("DirectoryScanner: Scan(DbDir=%s,FsDir=%s,Flat=%d,insDir=%d)\n", DbDir.c_str(), FsDir.c_str(), Flat, insDir));
561 if (DbDir.empty() || FsDir.empty()) throw Exception("Directory expected");
562
563 this->DbDir = DbDir;
564 this->FsDir = FsDir;
565 this->insDir = insDir;
566 if (DbDir.at(DbDir.length() - 1) != '/') {
567 this->DbDir.append("/");
568 }
569 if (FsDir.at(FsDir.length() - 1) != File::DirSeparator) {
570 this->FsDir.push_back(File::DirSeparator);
571 }
572 this->Flat = Flat;
573 this->pProgress = pProgress;
574
575 File::WalkDirectoryTree(FsDir, this);
576 }
577
578 void DirectoryScanner::DirectoryEntry(std::string Path) {
579 dmsg(2,("DirectoryScanner: DirectoryEntry(Path=%s)\n", Path.c_str()));
580
581 String dir = DbDir;
582 if (!Flat) {
583 String subdir = Path;
584 if(subdir.length() > FsDir.length()) {
585 subdir = subdir.substr(FsDir.length());
586 dir += subdir;
587 }
588 }
589
590 InstrumentsDb* db = InstrumentsDb::GetInstrumentsDb();
591
592 if (HasInstrumentFiles(Path)) {
593 if (!db->DirectoryExist(dir)) db->AddDirectory(dir);
594 db->AddInstrumentsNonrecursive(dir, Path, insDir, pProgress);
595 }
596 };
597
598 bool DirectoryScanner::HasInstrumentFiles(String Dir) {
599 InstrumentFileCounter c;
600 return c.Count(Dir) > 0;
601 }
602
603 int InstrumentFileCounter::Count(String FsDir) {
604 dmsg(2,("InstrumentFileCounter: Count(FsDir=%s)\n", FsDir.c_str()));
605 if (FsDir.empty()) throw Exception("Directory expected");
606 FileCount = 0;
607
608 File::WalkDirectoryTree(FsDir, this);
609 return FileCount;
610 }
611
612 void InstrumentFileCounter::FileEntry(std::string Path) {
613 dmsg(2,("InstrumentFileCounter: FileEntry(Path=%s)\n", Path.c_str()));
614 if(Path.length() < 4) return;
615 if(!strcasecmp(".gig", Path.substr(Path.length() - 4).c_str())) FileCount++;
616 };
617
618 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC