MuseScore/mscore/exportaudio.cpp

184 lines
6.3 KiB
C++
Raw Normal View History

2012-05-26 14:49:10 +02:00
//=============================================================================
// MusE Score
// Linux Music Score Editor
// $Id: exportaudio.cpp 5660 2012-05-22 14:17:39Z wschweer $
//
// Copyright (C) 2009 Werner Schweer and others
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//=============================================================================
#include "config.h"
#include <sndfile.h>
#include "libmscore/score.h"
#include "libmscore/note.h"
#include "libmscore/part.h"
#include "libmscore/mscore.h"
#include "synthesizer/msynthesizer.h"
#include "musescore.h"
#include "preferences.h"
2012-05-26 14:49:10 +02:00
2013-05-13 18:49:17 +02:00
namespace Ms {
#ifdef HAS_AUDIOFILE
2012-05-26 14:49:10 +02:00
//---------------------------------------------------------
// saveAudio
//---------------------------------------------------------
bool MuseScore::saveAudio(Score* score, const QString& name, const QString& ext)
{
int format;
if (ext == "wav")
format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
else if (ext == "ogg")
format = SF_FORMAT_OGG | SF_FORMAT_VORBIS;
else if (ext == "flac")
format = SF_FORMAT_FLAC | SF_FORMAT_PCM_16;
else {
qDebug("unknown audio file type <%s>\n", qPrintable(ext));
return false;
}
EventMap events;
score->renderMidi(&events);
if(events.size() == 0)
return false;
MasterSynthesizer* synti = synthesizerFactory();
2013-04-24 15:37:55 +02:00
synti->init();
2012-05-26 14:49:10 +02:00
int sampleRate = preferences.exportAudioSampleRate;
2013-03-26 19:59:51 +01:00
synti->setSampleRate(sampleRate);
synti->setState(score->synthesizerState());
2012-05-26 14:49:10 +02:00
2013-03-27 17:16:24 +01:00
int oldSampleRate = MScore::sampleRate;
2012-06-21 11:21:25 +02:00
MScore::sampleRate = sampleRate;
2012-05-26 14:49:10 +02:00
SF_INFO info;
memset(&info, 0, sizeof(info));
info.channels = 2;
info.samplerate = sampleRate;
info.format = format;
SNDFILE* sf = sf_open(qPrintable(name), SFM_WRITE, &info);
if (sf == 0) {
qDebug("open soundfile failed: %s\n", sf_strerror(sf));
delete synti;
2012-06-21 11:21:25 +02:00
MScore::sampleRate = oldSampleRate;
2012-05-26 14:49:10 +02:00
return false;
}
QProgressBar* pBar = showProgressBar();
pBar->reset();
2013-04-04 12:12:10 +02:00
float peak = 0.0;
2012-05-26 14:49:10 +02:00
double gain = 1.0;
2013-04-08 10:31:17 +02:00
EventMap::const_iterator endPos = events.cend();
2012-05-26 14:49:10 +02:00
--endPos;
2013-04-08 10:31:17 +02:00
const int et = (score->utick2utime(endPos->first) + 1) * MScore::sampleRate;
pBar->setRange(0, et);
2012-05-26 14:49:10 +02:00
for (int pass = 0; pass < 2; ++pass) {
EventMap::const_iterator playPos;
2013-04-08 10:31:17 +02:00
playPos = events.cbegin();
2012-05-26 14:49:10 +02:00
//
// init instruments
//
foreach(const Part* part, score->parts()) {
foreach(const Channel& a, part->instr()->channel()) {
a.updateInitList();
foreach(MidiCoreEvent e, a.init) {
2012-05-26 14:49:10 +02:00
if (e.type() == ME_INVALID)
continue;
e.setChannel(a.channel);
2013-04-04 12:12:10 +02:00
int syntiIdx= synti->index(score->midiMapping(a.channel)->articulation->synti);
2012-05-26 14:49:10 +02:00
synti->play(e, syntiIdx);
}
}
}
static const unsigned FRAMES = 512;
float buffer[FRAMES * 2];
int playTime = 0;
for (;;) {
unsigned frames = FRAMES;
//
// collect events for one segment
//
memset(buffer, 0, sizeof(float) * FRAMES * 2);
int endTime = playTime + frames;
float* p = buffer;
2013-04-08 10:31:17 +02:00
for (; playPos != events.cend(); ++playPos) {
int f = score->utick2utime(playPos->first) * MScore::sampleRate;
2012-05-26 14:49:10 +02:00
if (f >= endTime)
break;
int n = f - playTime;
2013-04-04 12:12:10 +02:00
if (n) {
synti->process(n, p);
p += 2 * n;
}
2012-05-26 14:49:10 +02:00
playTime += n;
frames -= n;
const NPlayEvent& e = playPos->second;
2012-05-26 14:49:10 +02:00
if (e.isChannelEvent()) {
int channelIdx = e.channel();
Channel* c = score->midiMapping(channelIdx)->articulation;
if (!c->mute) {
2013-04-04 12:12:10 +02:00
synti->play(e, synti->index(c->synti));
2012-05-26 14:49:10 +02:00
}
}
}
if (frames) {
synti->process(frames, p);
playTime += frames;
}
2013-03-27 17:16:24 +01:00
if (pass == 1) {
for (unsigned i = 0; i < FRAMES * 2; ++i)
buffer[i] *= gain;
2012-05-26 14:49:10 +02:00
sf_writef_float(sf, buffer, FRAMES);
2013-03-27 17:16:24 +01:00
}
2012-05-26 14:49:10 +02:00
else {
for (unsigned i = 0; i < FRAMES * 2; ++i)
peak = qMax(peak, qAbs(buffer[i]));
}
playTime = endTime;
pBar->setValue((pass * et + playTime) / 2);
2013-03-27 17:16:24 +01:00
2012-05-26 14:49:10 +02:00
if (playTime >= et)
break;
}
2013-04-04 12:12:10 +02:00
if (pass == 0 && peak == 0.0) {
qDebug("song is empty");
break;
}
2012-05-26 14:49:10 +02:00
gain = 0.99 / peak;
}
hideProgressBar();
2012-06-21 11:21:25 +02:00
MScore::sampleRate = oldSampleRate;
2012-05-26 14:49:10 +02:00
delete synti;
if (sf_close(sf)) {
qDebug("close soundfile failed\n");
return false;
}
return true;
}
#endif // HAS_AUDIOFILE
2013-05-13 18:49:17 +02:00
}
2012-05-26 14:49:10 +02:00