Commit 0ec62d45 authored by Florent Jacquemard's avatar Florent Jacquemard
Browse files

simplification target squant2

scenario for KeySIO (rests)
parent 6f4c22aa
......@@ -43,14 +43,17 @@
/// runs for sequences of bars constructed as binary trees
#define QUANT_MULTIBAR_1BEST_SIR 9
/// idem with SIO keys (refactoring or SIR)
#define QUANT_MULTIBAR_1BEST_SIO 10
/// input segment of musical duration several bars, 1 best
/// construction of a table indexed by SIP keys
/// (state, interval, pre/post values)
/// runs for sequences of bars constructed as lists (flat)
#define QUANT_MULTIBAR_1BEST_SIPFLAT 10
#define QUANT_MULTIBAR_1BEST_SIPFLAT 11
/// current scenario
#define QUANT_SCENARIO QUANT_MULTIBAR_1BEST_SI
#define QUANT_SCENARIO QUANT_MULTIBAR_1BEST_SIO
#include <stdio.h>
......@@ -64,6 +67,7 @@
#include <getopt.h> // handling commandline options
#include <assert.h>
#include "config.hpp" // check compile flags
#include "trace.hpp"
#include "Rational.hpp"
......@@ -94,6 +98,7 @@
#include "KeySI.hpp"
#include "KeySIP.hpp"
//#include "KeySIR.hpp"
#include "KeySIO.hpp"
#include "Runey.hpp"
#include "RunInner.hpp"
#include "RunTerm.hpp"
......@@ -105,7 +110,7 @@
#include "Quantizer.hpp"
// output
//#include "LRT.hpp"
#include "LRT.hpp"
//#include "ScoringEnv.hpp";
#include "TableMonoImporter.hpp"
#include "MIDIOutput.hpp"
......@@ -130,7 +135,7 @@ namespace sm = ScoreModel;
static int verbosity = 0;
/// number of K-best to compute //was #define TEST_K 1
static size_t _k = 1;
static size_t _nbest = 1;
/// whether the best is the max (true) or the min (false) weight
static int f_max = true;
......@@ -514,12 +519,12 @@ static int getOption(int c, int option_index)
case 'k':
//k = strtoul(optarg, NULL, 10);
_k = atoi(optarg);
_nbest = atoi(optarg);
TRACE("Option {} : {}",
long_options[option_index].name, _k);
if (_k == 0)
long_options[option_index].name, _nbest);
if (_nbest == 0)
{
ERROR("option error: k={} must be > 0", _k);
ERROR("option error: k={} must be > 0", _nbest);
return 2;
}
break;
......@@ -713,6 +718,15 @@ bool checkOptions()
ERROR("options bars and barsec are mutually exclusive");
error = true;
}
if (f_out_midi && (! f_barbeat))
{
/// @todo adjust according to grammar optional content
/// SchemaFileIn.readTimesignature or
/// SchemaFileIn.read_option
ERROR("options: barbeat must be given for MIDI output");
error = true;
}
return error;
}
......@@ -738,6 +752,182 @@ void setVerbosityLevel()
}
/// @param init initial key to start parsing.
/// @param n number of best trees to compute.
/// @param f_max whether the best is the max (true) or the min (false) weight
/// @param env parsing environment (input and automaton).
/// @return the parse table computed, containing the k best trees..
/// - K = concrete key class (index rows in the table)
/// - H = KeyHasher (for keys)
template<class K, class H>
parsing::TableA<K>* parse(const K& init,
size_t n,
bool f_max,
parsing::ParsingEnv& env)
{
assert(env.segment);
parsing::RunCompare comp = (f_max)?parsing::weightMax:parsing::weightMin;
parsing::TableA<K>* tab = nullptr;
// initialize table (empty)
if (n == 1) // 1-best
{
tab = new parsing::TableParse<K, parsing::RecordOne<K>, H>(env, comp);
}
else // k-best
{
assert(n > 1); // cannot be 0
tab = new parsing::TableParse<K, parsing::RecordQueue<K>, H>(env, comp);
}
// fill table up to n-best
assert(tab);
tab->best(init, n); // const parsing::Run* (not used)
return tab;
}
/// extract a ScoreModel with 1 unique part from the 1-best tree in given table.
/// @param tab a parse table.
/// @param init initial key at top of the 1-best tree.
/// @param ts metre signature
/// @param scorename name given to the score in the build Score Model
/// @param partname name given to the unique part in the build Score Model
/// @param env scoring environment (input and automaton and voices).
template<class K>
sm::Score* buildSM(parsing::TableA<K>& tab,
const K& init,
const sm::MeterSig& ts,
const string& scorename,
const string& partname,
sm::ScoringEnv& env)
{
sm::TableMonoImporter importer(std::string(scorename), ts);
importer.readPart<K>(std::string("part1"), env, tab, init, 1);
sm::Score* score = importer.getScore();
assert(score);
return score;
}
void spellPitch(sm::Score& score)
{
for (sm::PartSeq::iterator i = score.begin(); i != score.end(); ++i)
{
sm::Part& part = **i;
INFO("Pitch Spelling part: {}", part.id());
sm::PS0 ps = sm::PS0(part);
ps.spell1();
}
}
void printSM(const sm::Score& score)
{
sm::Printer sm_pp = sm::Printer(std::cout, false);
std::cout << std::endl;
sm_pp.visitScore(&score);
std::cout << std::endl;
}
/// @param tab a parse table.
/// @param init initial key to start parsing.
/// @param n number of best trees to compute.
template<class K>
void printTrees(parsing::TableA<K>& tab,
const K& init,
size_t n)
{
for (size_t i = 1; i <= _nbest; i++)
{
const parsing::Run* best_run = tab.best(init, i);
if (best_run == NULL) // should no more happen (changed to FAIL)
{
//assert(best_tree == NULL);
INFO("{}-best: NULL", i);
}
else if (_nbest == 1)
{
//LabeledRhythmTree* best_tree = tab->bestTree(best_run);
LabeledRhythmTree* best_tree =
LRTFactory<K>::projection(tab, best_run, 1);
assert(best_tree);
INFO("{}-best = {} weight = {}", i,
best_tree->to_string(), best_run->weight());
delete best_tree;
}
else
{
const parsing::RunRanked<parsing::KeySIP>* best_runr =
dynamic_cast<const parsing::RunRanked<parsing::KeySIP>*>(best_run);
assert(best_runr);
//LabeledRhythmTree* best_tree = tab->bestTree(best_runr);
LabeledRhythmTree* best_tree =
LRTFactory<K>::projection(tab, best_runr);
assert(best_tree);
INFO("{}-best = {} weight = {}", i,
best_tree->to_string(), best_run->weight());
delete best_tree;
}
}
}
size_t writeMEI(const sm::Score& score,
const string& filename)
{
string prefix = util::prefix(filename);
if (score.nbParts() == 0)
{
ERROR("empty score (0 parts)");
return 1;
}
INFO("Export part 1/{} of the score model into MEI.", score.nbParts());
sm::MEIExporter sm_export = sm::MEIExporter();
sm::PartSeq::const_iterator pi = score.cbegin();
assert(pi != score.cend());
assert(*pi);
sm::Part& part1 = *(*pi);
sm_export.addScore(part1);
INFO("write to {}", filename);
sm_export.writeInFile(filename);
return 0;
}
template<class K>
size_t exportMIDI(parsing::TableA<K>& tab,
const K& init,
Rational barbeat,
const string& input_filename,
const string& output_filename,
parsing::ParsingEnv& env)
{
assert(env.segment);
INFO("quantize segment ({} points) wrt parse tree", env.segment->size()-1);
// quantize wrt the 1-best for k0
//_iseg->quantize<parsing::KeySIR>(tab, k0, 1);
parsing::Quantizer<K> quantizer(tab);
quantizer.quantize(*(env.segment), init, 1);
INFO("quantized input segment:");
env.segment->print(std::cout);
// qseg->respell(); // not for MIDI out!
INFO("export to MIDI file {}", output_filename);
if (output_filename.empty())
return 2;
assert(barbeat > Rational(0));
MIDIExporter midiexport(output_filename, barbeat);
// track nb = 1
assert(! input_filename.empty());
midiexport.export_midifile(*(env.segment), input_filename, 1);
return 0;
}
......@@ -1009,44 +1199,27 @@ int main(int argc, char** argv)
_iseg->print(std::cout);
}
#if QUANT_SCENARIO == QUANT_INPUTLESS
typedef parsing::KeyS KeyS;
// flag f_max: ordering for enumeration (user option)
parsing::RunCompare comp = (f_max)?parsing::weightMax:parsing::weightMin;
// empty env, not used here
INFO("{}-best computation", _nbest);
// no input segment
assert(_schema);
parsing::ParsingEnv env = parsing::ParsingEnv(_schema, NULL);
parsing::TableA<parsing::KeyS>* tab; // empty table
if (_k == 1) // 1-best
{
tab = new parsing::TableParse<parsing::KeyS,
parsing::RecordOne<parsing::KeyS>,
parsing::KeySHasher>(&env, comp);
}
else // k-best
{
assert(_k > 1); // cannot be 0
tab = new parsing::TableParse<KeyS,
parsing::RecordQueue<KeyS>,
parsing::KeySHasher>(&env, comp);
}
state_t init = _schema->initial();
const KeyS k0 = KeyS(init, env);
for (size_t i = 1; i <= _k; i++)
// flag f_max: ordering for enumeration (user option)
parsing::TableA<parsing::KeyS>* tab =
parse<parsing::KeyS, parsing::KeySHasher>(k0, _nbest, f_max, env);
tab->best(k0, _nbest); // fill table up to n-best
for (size_t i = 1; i <= _nbest; i++)
{
const parsing::Run* best_run = tab->best(k0, i);
if (best_run == NULL)
INFO("{}-BEST RUN: none", i);
else if (_k == 1)
else if (_nbest == 1)
{
INFO("{}-BEST RUN = {}", i, *(best_run));
}
......@@ -1061,9 +1234,11 @@ int main(int argc, char** argv)
delete tab;
#elif QUANT_SCENARIO == QUANT_1BAR_1BESTSIP
ERROR("missing scenario QUANT_1BAR_1BESTSIP");
#elif QUANT_SCENARIO == QUANT_1BAR_KBESTSKIP
ERROR("missing scenario QUANT_1BAR_KBESTSKIP");
......@@ -1079,54 +1254,31 @@ int main(int argc, char** argv)
ERROR("at least one of the options -bars or -barsec mandatory");
exit(2);
}
// check options
if (f_out_midi && (! f_barbeat))
{
/// @todo adjust according to grammar optional content
/// SchemaFileIn.readTimesignature or
/// SchemaFileIn.read_option
ERROR("options: barbeat must be given for MIDI output");
exit(2);
}
// prepare parsing environment
assert(_schema);
assert(_iseg);
parsing::ParsingEnv env = parsing::ParsingEnv(_schema, _iseg);
assert(env.segment);
// flag f_max: ordering for enumeration (user option)
parsing::RunCompare comp = (f_max)?parsing::weightMax:parsing::weightMin;
parsing::TableA<parsing::KeySI>* tab; // empty table
if (_k == 1) // 1-best
{
INFO("1-best computation");
tab = new parsing::TableParse<parsing::KeySI,
parsing::RecordOne<parsing::KeySI>,
parsing::KeySIHasher>(&env, comp);
}
else // k-best
{
INFO("{}-best computation", _k);
assert(_k > 1); // cannot be 0
tab = new parsing::TableParse<parsing::KeySI,
parsing::RecordQueue<parsing::KeySI>,
parsing::KeySIHasher>(&env, comp);
}
// state_t init = _schema->initial();
// initial augmented state
const parsing::KeySI k0 = parsing::KeySI(_barsec, env, false);
INFO("parsing segment [{}-{}], rdur={}",
env.segment->rbegin(),
env.segment->rend(),
env.segment->Interval::rduration());
INFO("fixed bar duration = {}s ({} bars)", _barsec, _bars);
clock_t time_start = clock();
INFO("start parsing");
const parsing::Run* r0 = tab->best(k0, _k);
clock_t time_start = clock();
// initial augmented state
const parsing::KeySI k0 = parsing::KeySI(_barsec, env, false);
// flag f_max: ordering for enumeration (user option)
parsing::TableA<parsing::KeySI>* tab =
parse<parsing::KeySI, parsing::KeySIHasher>(k0, _nbest, f_max, env);
// fill table up to n-best
const parsing::Run* r0 = tab->best(k0, _nbest);
INFO("time to parse : {}ms", util::duration(time_start));
LabeledRhythmTree* t0 = LRTFactory<parsing::KeySI>::best(tab, k0); // was: tab->bestTree(r0);
assert(t0);
......@@ -1146,183 +1298,104 @@ int main(int argc, char** argv)
if (tab)
delete tab;
#elif QUANT_SCENARIO == QUANT_MULTIBAR_1BEST_SIP
INFO("parser multibar with Key_SIP");
INFO("compute best tree sequence for {} and input in {}",
_schema_file, _input_file);
typedef LRTFactory<parsing::KeySIP> TreeFactory;
// check options
if (!(f_barsec || f_bars))
{
ERROR("at least one of the options -bars or -barsec mandatory");
exit(2);
}
// check options
if (f_out_midi && (! f_barbeat))
if (! f_timesig)
{
/// @todo adjust according to grammar optional content
/// SchemaFileIn.readTimesignature or
/// SchemaFileIn.read_option
ERROR("options: barbeat must be given for MIDI output");
exit(2);
WARN("no time signature in commandline, default to {}", _ts);
}
assert(_schema);
assert(_iseg);
parsing::ParsingEnv env = parsing::ParsingEnv(_schema, _iseg);
assert(env.segment);
// flag f_max: ordering for enumeration (user option)
parsing::ParsingEnv penv = parsing::ParsingEnv(_schema, _iseg);
assert(penv.segment);
parsing::RunCompare<parsing::KeySIP> comp =
(f_max)?parsing::weightMax<parsing::KeySIP>:parsing::weightMin<parsing::KeySIP>;
parsing::TableA<parsing::KeySIP>* tab; // empty table
if (_k == 1) // 1-best
{
INFO("1-best computation");
tab = new parsing::TableParse<parsing::KeySIP,
parsing::RecordOne<parsing::KeySIP>,
parsing::KeySIPHasher>(&env, comp);
}
else // k-best
{
INFO("{}-best computation", _k);
assert(_k > 1); // cannot be 0
tab = new parsing::TableParse<parsing::KeySIP,
parsing::RecordQueue<parsing::KeySIP>,
parsing::KeySIPHasher>(&env, comp);
}
INFO("parsing segment [{}-{}], rdur={}",
penv.segment->rbegin(),
penv.segment->rend(),
penv.segment->Interval::rduration());
INFO("fixed bar duration = {}s ({} bars)", _barsec, _bars);
INFO("start parsing");
// state_t init = _schema->initial();
clock_t time_start = clock();
// initial augmented state
// pre = 0
// post = 0 (complete key)
const parsing::KeySIP k0 = parsing::KeySIP(_barsec, env, true, 0, 0);
// state_t init = _schema->initial();
// pre = 0
// post = Unknown (partial key)
//const KeySIP k0 = KeySIP(_barsec, env, true, 0);
INFO("parsing segment [{}-{}], rdur={}",
env.segment->rbegin(),
env.segment->rend(),
env.segment->Interval::rduration());
INFO("fixed bar duration = {}s ({} bars)", _barsec, _bars);
clock_t time_start = clock();
INFO("start parsing");
// const Run<KeySIP>* r0 =
tab->best(k0, _k); // fill table up to k-best
const parsing::KeySIP k0 = parsing::KeySIP(_barsec, penv, true, 0);
// or post = 0 (complete key)
// const parsing::KeySIP k0 = parsing::KeySIP(_barsec, penv, true, 0, 0);
// flag f_max: ordering for enumeration (user option)
parsing::TableA<parsing::KeySIP>* tab =
parse<parsing::KeySIP, parsing::KeySIPHasher>(k0, _nbest, f_max, penv);
assert(tab);
// fill table up to n-best
tab->best(k0, _nbest); // const parsing::Run* r0
INFO("time to parse : {}ms", util::duration(time_start));
if (f_output)
if (f_output && (_output_file.size() == 0))
{
if(_output_file.size() == 0)
{
ERROR("empty output file name");
return 1;
}
/// @todo revise with score builder
if (f_out_mei)
{
INFO("export to MEI file {}", _output_file);
string prefix = util::prefix(_output_file);
}
/// @todo revise with score builder
else if (f_output && f_out_mei)
{
INFO("Construct the symbolic score model from from the parse table");
VoicingMono* voicing = NULL; //= new VoicingMono(*(penv.segment));
// voicing->revoice_all(); // quantize first!
//assert(voicing->voiced());
// pack Scoring Environment
sm::ScoringEnv senv = sm::ScoringEnv(penv, voicing);
string prefix = util::prefix(_output_file);
assert(tab);
sm::Score* score =
buildSM<parsing::KeySIP>(*tab, k0, _ts, prefix, "part1", senv);
assert(score);
INFO("Create the symbolic score model from the best tree");
INFO("Pitch Spelling in score: {}", score->id());
spellPitch(*score);
// _ts is the time signature
ScoreModel::Score myScore = ScoreModel::Score(prefix, _ts);
ScoreModel::Voice* voice = myScore.voice(prefix, prefix);
//LabeledRhythmTree* bars = tab->bestTree(k0, 1);
LabeledRhythmTree* bars = TreeFactory::best(tab, k0, 1);
size_t first = 0;
size_t next = 0;
while ((bars != NULL) &&
SymbLabel::bar(bars->label()) &&
SymbLabel::binary(bars->label()))
{
// RT representation of the current bar
const LabeledRhythmTree* bar =
(LabeledRhythmTree*) bars->child(0);
// empty measure
ScoreModel::Measure* measure = myScore.newMeasure();
INFO("Add measure {}", measure->id());
/// @todo complete
//voice->addLRT(measure, bar, _iseg, first, next, MTU::of_int(1), 0);
//INFO("read events {}-{}", first, next);
first = next;
bars = (LabeledRhythmTree*) bars->child(1);
}
INFO("Serialize in MEI and store in {}", _output_file);
MEI meiProcessor = MEI();
meiProcessor.createFromScore(myScore);
meiProcessor.writeInFile(_output_file);
INFO("Serialization in MEI in {} done", _output_file);
}
INFO("Print the score model");
printSM(*score);
if (f_out_midi)
{
INFO("export to MEI file {}", _output_file);
writeMEI(*score, _output_file);
if (score) delete score;
if (voicing) delete voicing;
}
else if (f_output && f_out_midi)
{
INFO("export to MIDI file");
/// @todo MIDI export
// see parser->demo(_schema_file, _input_file,
// _output_file, Rational(_barbeat));
}
}
else
{
INFO("DEBUG output:");
//parser->demo(_schema_file, _input_file);
for (size_t i = 1; i <= _k; i++)
{
const parsing::Run<parsing::KeySIP>* best_run = tab->best(k0, i);
if (best_run == NULL)
{
//assert(best_tree == NULL);
INFO("{}-best: FAIL", i);
}
else if (_k == 1)
{
//LabeledRhythmTree* best_tree = tab->bestTree(best_run);
LabeledRhythmTree* best_tree = TreeFactory::projection(tab, best_run);
assert(best_tree);
INFO("{}-best = {}", i, best_tree->to_string());
INFO(" weight = {}", best_run->weight());
}
else
{
const parsing::RunRanked<parsing::KeySIP>* best_runr =
dynamic_cast<const parsing::RunRanked<parsing::KeySIP>*>(best_run);
assert(best_runr);
//LabeledRhythmTree* best_tree = tab->bestTree(best_runr);
LabeledRhythmTree* best_tree = TreeFactory