diff options
Diffstat (limited to 'src/sound/SF2PatchExtractor.cpp')
-rw-r--r-- | src/sound/SF2PatchExtractor.cpp | 217 |
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 |