196 lines
5.7 KiB
C++
196 lines
5.7 KiB
C++
//=============================================================================
|
|
// Zerberus
|
|
// Zample player
|
|
//
|
|
// Copyright (C) 2013 Werner Schweer
|
|
//
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License version 2
|
|
// as published by the Free Software Foundation and appearing in
|
|
// the file LICENCE.GPL
|
|
//=============================================================================
|
|
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
#include <QFile>
|
|
#include <QFileInfo>
|
|
#include <QStringList>
|
|
|
|
#include "libmscore/xml.h"
|
|
#include "libmscore/qzipreader_p.h"
|
|
#include "audiofile/audiofile.h"
|
|
|
|
#include "instrument.h"
|
|
#include "zone.h"
|
|
#include "sample.h"
|
|
|
|
QByteArray ZInstrument::buf;
|
|
int ZInstrument::idx;
|
|
|
|
//---------------------------------------------------------
|
|
// Sample
|
|
//---------------------------------------------------------
|
|
|
|
Sample::~Sample()
|
|
{
|
|
delete _data;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// readSample
|
|
//---------------------------------------------------------
|
|
|
|
Sample* ZInstrument::readSample(const QString& s, QZipReader* uz)
|
|
{
|
|
if (uz) {
|
|
QList<QZipReader::FileInfo> fi = uz->fileInfoList();
|
|
|
|
buf = uz->fileData(s);
|
|
if (buf.isEmpty()) {
|
|
printf("Sample::read: cannot read sample data <%s>\n", qPrintable(s));
|
|
return 0;
|
|
}
|
|
}
|
|
else {
|
|
QFile f(s);
|
|
if (!f.open(QIODevice::ReadOnly)) {
|
|
printf("Sample::read: open <%s> failed\n", qPrintable(s));
|
|
return 0;
|
|
}
|
|
buf = f.readAll();
|
|
}
|
|
|
|
AudioFile a;
|
|
if (!a.open(buf)) {
|
|
printf("open <%s> failed: %s\n", qPrintable(s), a.error());
|
|
return 0;
|
|
}
|
|
|
|
int channel = a.channels();
|
|
int frames = a.frames();
|
|
int sr = a.samplerate();
|
|
|
|
short* data = new short[(frames + 3) * channel];
|
|
Sample* sa = new Sample(channel, data, frames, sr);
|
|
|
|
if (frames != a.read(data + channel, frames)) {
|
|
printf("Sample read failed: %s\n", a.error());
|
|
delete[] data;
|
|
delete sa;
|
|
sa = 0;
|
|
}
|
|
for (int i = 0; i < channel; ++i) {
|
|
data[i] = data[channel + i];
|
|
data[(frames-1) * channel + i] = data[(frames-3) * channel + i];
|
|
data[(frames-2) * channel + i] = data[(frames-3) * channel + i];
|
|
}
|
|
return sa;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// ZInstrument
|
|
//---------------------------------------------------------
|
|
|
|
ZInstrument::ZInstrument(Zerberus* z)
|
|
{
|
|
zerberus = z;
|
|
_program = -1;
|
|
_refCount = 0;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// ZInstrument
|
|
//---------------------------------------------------------
|
|
|
|
ZInstrument::~ZInstrument()
|
|
{
|
|
for (Zone* z : _zones)
|
|
delete z;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// load
|
|
// return true on success
|
|
//---------------------------------------------------------
|
|
|
|
bool ZInstrument::load(const QString& path)
|
|
{
|
|
instrumentPath = path;
|
|
QFileInfo fi(path);
|
|
_name = fi.baseName();
|
|
if (fi.isFile())
|
|
return loadFromFile(path);
|
|
if (fi.isDir())
|
|
return loadFromDir(path);
|
|
return false;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// loadFromDir
|
|
//---------------------------------------------------------
|
|
|
|
bool ZInstrument::loadFromDir(const QString& s)
|
|
{
|
|
QFile f(s + "/orchestra.xml");
|
|
if (!f.open(QIODevice::ReadOnly)) {
|
|
printf("cannot load orchestra.xml in <%s>\n", qPrintable(s));
|
|
return false;
|
|
}
|
|
QByteArray buf = f.readAll();
|
|
if (buf.isEmpty()) {
|
|
printf("Instrument::loadFromFile: orchestra.xml is empty\n");
|
|
return false;
|
|
}
|
|
return read(buf, 0, s);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// loadFromFile
|
|
//---------------------------------------------------------
|
|
|
|
bool ZInstrument::loadFromFile(const QString& path)
|
|
{
|
|
if (path.endsWith(".sfz"))
|
|
return loadSfz(path);
|
|
if (!path.endsWith(".msoz")) {
|
|
printf("<%s> not a orchestra file\n", qPrintable(path));
|
|
return false;
|
|
}
|
|
QZipReader uz(path);
|
|
if (!uz.exists()) {
|
|
printf("Instrument::load: %s not found\n", qPrintable(path));
|
|
return false;
|
|
}
|
|
QByteArray buf = uz.fileData("orchestra.xml");
|
|
if (buf.isEmpty()) {
|
|
printf("Instrument::loadFromFile: orchestra.xml not found\n");
|
|
return false;
|
|
}
|
|
return read(buf, &uz, QString());
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// read
|
|
// read orchestra
|
|
//---------------------------------------------------------
|
|
|
|
bool ZInstrument::read(const QByteArray& buf, QZipReader* /*uz*/, const QString& /*path*/)
|
|
{
|
|
Ms::XmlReader e(buf);
|
|
while (e.readNextStartElement()) {
|
|
if (e.name() == "MuseSynth") {
|
|
while (e.readNextStartElement()) {
|
|
if (e.name() == "Instrument") {
|
|
// if (!read(e, uz, path))
|
|
// return false;
|
|
}
|
|
else
|
|
e.unknown();
|
|
}
|
|
}
|
|
else
|
|
e.unknown();
|
|
}
|
|
return true;
|
|
}
|
|
|