Logo Search packages:      
Sourcecode: rosegarden version File versions  Download package

SF2PatchExtractor.cpp

// -*- c-basic-offset: 4 -*-

/*
    Rosegarden-4
    A sequencer and musical notation editor.

    This program is Copyright 2000-2006
        Guillaume Laurent   <glaurent@telegraph-road.org>,
        Chris Cannam        <cannam@all-day-breakfast.com>,
        Richard Bown        <bownie@bownie.com>

    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 Rosegarden::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

Generated by  Doxygen 1.6.0   Back to index