summaryrefslogtreecommitdiffstats
path: root/src/sound/SF2PatchExtractor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/sound/SF2PatchExtractor.cpp')
-rw-r--r--src/sound/SF2PatchExtractor.cpp217
1 files changed, 217 insertions, 0 deletions
diff --git a/src/sound/SF2PatchExtractor.cpp b/src/sound/SF2PatchExtractor.cpp
new file mode 100644
index 0000000..6ba8dc5
--- /dev/null
+++ b/src/sound/SF2PatchExtractor.cpp
@@ -0,0 +1,217 @@
+// -*- c-basic-offset: 4 -*-
+
+/*
+ Rosegarden
+ A sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <[email protected]>,
+ Chris Cannam <[email protected]>,
+ Richard Bown <[email protected]>
+
+ The moral right of the authors to claim authorship of this work
+ has been asserted.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+#include "SF2PatchExtractor.h"
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <map>
+#include <sys/types.h>
+
+namespace Rosegarden
+{
+
+using std::string;
+using std::cerr;
+using std::endl;
+using std::ifstream;
+using std::ios;
+
+
+struct Chunk
+{
+ char id[4];
+ u_int32_t size;
+
+ Chunk(ifstream *, bool idOnly = false);
+ bool isa(std::string s);
+};
+
+Chunk::Chunk(ifstream *file, bool idOnly)
+{
+ file->read((char *)this->id, 4);
+ size = 0;
+
+ if (idOnly)
+ return ;
+
+ unsigned char sz[4];
+ file->read((char *)sz, 4);
+ for (int i = 0; i < 4; ++i)
+ size += sz[i] << (i * 8);
+}
+
+bool
+Chunk::isa(string s)
+{
+ return string(id, 4) == s;
+}
+
+bool
+SF2PatchExtractor::isSF2File(string fileName)
+{
+ ifstream *file = new ifstream(fileName.c_str(), ios::in | ios::binary);
+ if (!file)
+ throw FileNotFoundException();
+
+ Chunk riffchunk(file);
+ if (!riffchunk.isa("RIFF")) {
+ file->close();
+ return false;
+ }
+
+ Chunk sfbkchunk(file, true);
+ if (!sfbkchunk.isa("sfbk")) {
+ file->close();
+ return false;
+ }
+
+ file->close();
+ return true;
+}
+
+SF2PatchExtractor::Device
+SF2PatchExtractor::read(string fileName)
+{
+ Device device;
+
+ ifstream *file = new ifstream(fileName.c_str(), ios::in | ios::binary);
+ if (!file)
+ throw FileNotFoundException();
+
+ Chunk riffchunk(file);
+ if (!riffchunk.isa("RIFF")) {
+ file->close();
+ throw WrongFileFormatException();
+ }
+
+ Chunk sfbkchunk(file, true);
+ if (!sfbkchunk.isa("sfbk")) {
+ file->close();
+ throw WrongFileFormatException();
+ }
+
+ while (!file->eof()) {
+
+ Chunk chunk(file);
+
+ if (!chunk.isa("LIST")) {
+ // cerr << "Skipping " << string(chunk.id, 4) << endl;
+ file->seekg(chunk.size, ios::cur);
+ continue;
+ }
+
+ Chunk listchunk(file, true);
+ if (!listchunk.isa("pdta")) {
+ // cerr << "Skipping " << string(id, 4) << endl;
+ file->seekg(chunk.size - 4, ios::cur);
+ continue;
+ }
+
+ int size = chunk.size - 4;
+ while (size > 0) {
+
+ Chunk pdtachunk(file);
+ size -= 8 + pdtachunk.size;
+ if (file->eof()) {
+ break;
+ }
+
+ if (!pdtachunk.isa("phdr")) { // preset header
+ // cerr << "Skipping " << string(pdtachunk.id, 4) << endl;
+ file->seekg(pdtachunk.size, ios::cur);
+ continue;
+ }
+
+ int presets = pdtachunk.size / 38;
+ for (int i = 0; i < presets; ++i) {
+
+ char name[21];
+ u_int16_t bank, program;
+
+ file->read((char *)name, 20);
+ name[20] = '\0';
+ file->read((char *)&program, 2);
+ file->read((char *)&bank, 2);
+
+ // cerr << "Read name as " << name << endl;
+
+ file->seekg(14, ios::cur);
+
+ if (i == presets - 1 &&
+ bank == 255 &&
+ program == 255 &&
+ string(name) == "EOP")
+ continue;
+
+ device[bank][program] = name;
+ }
+ }
+ }
+
+ file->close();
+ return device;
+}
+
+}
+
+
+#ifdef TEST_SF2_PATCH_EXTRACTOR
+
+int main(int argc, char **argv)
+{
+ using SF2PatchExtractor;
+
+ if (argc != 2) {
+ std::cerr << "Usage: " << argv[0] << " sf2filename" << std::endl;
+ return 2;
+ }
+
+ try {
+ SF2PatchExtractor::Device device =
+ SF2PatchExtractor::read(argv[1]);
+
+ std::cerr << "Done. Presets are:" << std::endl;
+
+ for (SF2PatchExtractor::Device::iterator di = device.begin();
+ di != device.end(); ++di) {
+
+ std::cerr << "Bank " << di->first << ":" << std::endl;
+
+ for (SF2PatchExtractor::Bank::iterator bi = di->second.begin();
+ bi != di->second.end();
+ ++bi) {
+
+ std::cerr << "Program " << bi->first << ": \"" << bi->second
+ << "\"" << std::endl;
+ }
+ }
+ } catch (SF2PatchExtractor::WrongFileFormatException) {
+ std::cerr << "Wrong file format" << std::endl;
+ } catch (SF2PatchExtractor::FileNotFoundException) {
+ std::cerr << "File not found or couldn't be opened" << std::endl;
+ }
+
+ return 0;
+}
+
+#endif