diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b923b49..221e61e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,7 @@ set(SRCS src/tool-filter.cpp src/tool-hproof.cpp src/tool-imitation.cpp + src/tool-worex.cpp src/tool-mei2hum.cpp src/tool-metlev.cpp src/tool-msearch.cpp @@ -154,6 +155,7 @@ set(HDRS include/tool-fb.h include/tool-hproof.h include/tool-imitation.h + include/tool-worex.h include/tool-mei2hum.h include/tool-metlev.h include/tool-msearch.h diff --git a/Makefile b/Makefile index 6028d96a..3138bc9f 100644 --- a/Makefile +++ b/Makefile @@ -644,7 +644,7 @@ tool-filter.o: tool-filter.cpp tool-filter.h \ tool-composite.h tool-dissonant.h \ tool-extract.h tool-fb.h tool-homorhythm.h \ tool-homorhythm2.h tool-hproof.h \ - tool-humdiff.h tool-shed.h tool-imitation.h \ + tool-humdiff.h tool-shed.h tool-imitation.h tool-worex.h \ tool-kern2mens.h tool-melisma.h tool-metlev.h \ tool-msearch.h tool-myank.h tool-phrase.h \ tool-recip.h tool-restfill.h tool-satb2gs.h \ @@ -708,6 +708,15 @@ tool-imitation.o: tool-imitation.cpp tool-imitation.h \ NoteGrid.h NoteCell.h Convert.h \ HumRegex.h +tool-worex.o: tool-worex.cpp tool-worex.h \ + HumTool.h Options.h HumdrumFileSet.h \ + HumdrumFile.h HumdrumFileContent.h \ + HumdrumFileStructure.h HumdrumFileBase.h \ + HumSignifiers.h HumSignifier.h HumdrumLine.h \ + HumdrumToken.h HumNum.h HumAddress.h \ + HumHash.h HumParamSet.h HumdrumFileStream.h \ + HumRegex.h + tool-kern2mens.o: tool-kern2mens.cpp tool-kern2mens.h \ HumTool.h Options.h HumdrumFileSet.h \ HumdrumFile.h HumdrumFileContent.h \ diff --git a/cli/worex.cpp b/cli/worex.cpp new file mode 100644 index 00000000..e5443d8f --- /dev/null +++ b/cli/worex.cpp @@ -0,0 +1,14 @@ +// +// Programmer: Wolfgang Drescher +// Creation Date: Sa 4 Feb 2023 16:27:58 CET +// Filename: worex.cpp +// URL: https://github.com/craigsapp/humlib/blob/master/cli/worex.cpp +// Syntax: C++11 +// vim: ts=3 noexpandtab nowrap +// +// Description: Word extender program. +// + +#include "humlib.h" + +STREAM_INTERFACE(Tool_worex) diff --git a/include/humlib.h b/include/humlib.h index 1941c190..fd85d628 100644 --- a/include/humlib.h +++ b/include/humlib.h @@ -1,7 +1,7 @@ // // Programmer: Craig Stuart Sapp // Creation Date: Sat Aug 8 12:24:49 PDT 2015 -// Last Modified: Thu Jan 26 22:41:11 PST 2023 +// Last Modified: Mi 8 Feb 2023 14:42:01 CET // Filename: humlib.h // URL: https://github.com/craigsapp/humlib/blob/master/include/humlib.h // Syntax: C++11 @@ -10247,6 +10247,31 @@ class Tool_trillspell : public HumTool { +class Tool_worex : public HumTool { + + public: + Tool_worex (void); + ~Tool_worex() {}; + + bool run(HumdrumFileSet& infiles); + bool run(HumdrumFile& infile); + bool run(const string& indata, ostream& out); + bool run(HumdrumFile& infile, ostream& out); + + protected: + void initialize (void); + void processFile (HumdrumFile& infile); + void addWordExtenders (vector spineStartList); + void removeWordExtenders(vector spineStartList); + HTp getParallelNote (HTp token); + + + private: + bool m_removeWordExtenderQ; + +}; + + } // end of namespace hum diff --git a/include/tool-worex.h b/include/tool-worex.h new file mode 100644 index 00000000..9dde5ef4 --- /dev/null +++ b/include/tool-worex.h @@ -0,0 +1,50 @@ +// +// Programmer: Wolfgang Drescher +// Creation Date: Sa 4 Feb 2023 16:27:58 CET +// Filename: tool-worex.h +// URL: https://github.com/craigsapp/humlib/blob/master/include/tool-worex.h +// Syntax: C++11; humlib +// vim: syntax=cpp ts=3 noexpandtab nowrap +// +// Description: Interface for worex tool, which adds word extenders to the lyrics. +// + +#ifndef _TOOL_WOREX_H +#define _TOOL_WOREX_H + +#include "HumTool.h" +#include "HumdrumFile.h" + +namespace hum { + +// START_MERGE + +class Tool_worex : public HumTool { + + public: + Tool_worex (void); + ~Tool_worex() {}; + + bool run(HumdrumFileSet& infiles); + bool run(HumdrumFile& infile); + bool run(const string& indata, ostream& out); + bool run(HumdrumFile& infile, ostream& out); + + protected: + void initialize (void); + void processFile (HumdrumFile& infile); + void addWordExtenders (vector spineStartList); + void removeWordExtenders(vector spineStartList); + HTp getParallelNote (HTp token); + + + private: + bool m_removeWordExtenderQ; + +}; + +// END_MERGE + +} // end namespace hum + +#endif /* _TOOL_WOREX_H */ diff --git a/src/humlib.cpp b/src/humlib.cpp index e38057dd..f0d78fcd 100644 --- a/src/humlib.cpp +++ b/src/humlib.cpp @@ -1,7 +1,7 @@ // // Programmer: Craig Stuart Sapp // Creation Date: Sat Aug 8 12:24:49 PDT 2015 -// Last Modified: Thu Jan 26 22:41:11 PST 2023 +// Last Modified: Mi 8 Feb 2023 14:42:01 CET // Filename: /include/humlib.cpp // URL: https://github.com/craigsapp/humlib/blob/master/src/humlib.cpp // Syntax: C++11 @@ -79073,6 +79073,8 @@ bool Tool_filter::run(HumdrumFileSet& infiles) { RUNTOOL(humtr, infile, commands[i].second, status); } else if (commands[i].first == "imitation") { RUNTOOL(imitation, infile, commands[i].second, status); + } else if (commands[i].first == "worex") { + RUNTOOL(worex, infile, commands[i].second, status); } else if (commands[i].first == "kern2mens") { RUNTOOL(kern2mens, infile, commands[i].second, status); } else if (commands[i].first == "kernview") { @@ -116497,4 +116499,202 @@ int Tool_trillspell::getBase40(int diatonic, int accidental) { +////////////////////////////// +// +// Tool_worex::Tool_worex -- Set the recognized options for the tool. +// + +Tool_worex::Tool_worex(void) { + define("r|remove=b", "Remove melismatic underlines at ending syllables of words"); +} + + + +////////////////////////////// +// +// Tool_worex::run -- Do the main work of the tool. +// + +bool Tool_worex::run(HumdrumFileSet &infiles) { + bool status = true; + for (int i = 0; i < infiles.getCount(); i++) { + status &= run(infiles[i]); + } + return status; +} + +bool Tool_worex::run(const string &indata, ostream &out) { + HumdrumFile infile(indata); + bool status = run(infile); + if (hasAnyText()) { + getAllText(out); + } else { + out << infile; + } + return status; +} + +bool Tool_worex::run(HumdrumFile &infile, ostream &out) { + bool status = run(infile); + if (hasAnyText()) { + getAllText(out); + } else { + out << infile; + } + return status; +} + +bool Tool_worex::run(HumdrumFile &infile) { + initialize(); + processFile(infile); + return true; +} + + + +////////////////////////////// +// +// Tool_worex::initialize -- +// + +void Tool_worex::initialize(void) { + m_removeWordExtenderQ = getBoolean("remove"); +} + + + +////////////////////////////// +// +// Tool_worex::processFile -- +// + +void Tool_worex::processFile(HumdrumFile& infile) { + + vector textSpinesStartList; + infile.getSpineStartList(textSpinesStartList, "**text"); + + if (m_removeWordExtenderQ) { + removeWordExtenders(textSpinesStartList); + } else { + addWordExtenders(textSpinesStartList); + } + + infile.createLinesFromTokens(); + + m_humdrum_text << infile; +} + + + +////////////////////////////// +// +// Tool_worex::addWordExtenders -- +// + +void Tool_worex::addWordExtenders(vector spineStartList) { + for (HTp token : spineStartList) { + if (!token->isDataType("**text")) { + continue; + } + HTp currentToken = token; + while (currentToken) { + HTp parallelNoteToken = getParallelNote(currentToken); + HTp nextToken = currentToken->getNextToken(); + // get token of next syllable + while (nextToken != NULL && !nextToken->isNonNullData()) { + nextToken = nextToken->getNextToken(); + } + if (nextToken == NULL) { + // ignore current token if there is no next + break; + } + if (parallelNoteToken != NULL) { + // if next syllable if not direclty after the duration of the current parallel note token + if (nextToken->getDurationFromStart() > (parallelNoteToken->getDurationFromStart() + parallelNoteToken->getDuration())) { + // check if parallel note of current track is not followed by a rest + HTp nextNonNullDataToken = parallelNoteToken->getNextNonNullDataToken(); + if (!nextNonNullDataToken->isRest()) { + string syllableExtender = "-"; + bool isWordEnd = equal(syllableExtender.rbegin(), syllableExtender.rend(), currentToken->getText().rbegin()) == false; + string wordEndExtender = "_"; + bool endsWithUnderscore = equal(wordEndExtender.rbegin(), wordEndExtender.rend(), currentToken->getText().rbegin()) == true; + // if current syllable is the end end of a word + // and the token does not alredy end with a underscore + if(isWordEnd && !endsWithUnderscore) { + currentToken->setText(currentToken->getText() + "_"); + } + } + } + } + currentToken = nextToken; + } + } +} + + + +////////////////////////////// +// +// Tool_worex::removeWordExtenders -- +// + +void Tool_worex::removeWordExtenders(vector spineStartList) { + for (HTp token : spineStartList) { + if (!token->isDataType("**text")) { + continue; + } + HTp currentToken = token; + while (currentToken) { + if (currentToken->isNonNullData()) { + string wordEndExtender = "_"; + bool endsWithUnderscore = equal(wordEndExtender.rbegin(), wordEndExtender.rend(), currentToken->getText().rbegin()) == true; + if (endsWithUnderscore) { + string text = currentToken->getText(); + text.pop_back(); + currentToken->setText(text); + } + } + currentToken = currentToken->getNextToken(); + } + } +} + + + +////////////////////////////// +// +// Tool_worex::getParallelNote -- Go backwards on the line and count any note +// attack (or tied note) on the first staff-like spine (track) found to the +// left. If there is a spine split in the text and or **kern data, then this +// algorithm needs to be refined further. +// + +HTp Tool_worex::getParallelNote(hum::HTp token) { + hum::HTp current = token; + int track = -1; + while (current) { + current = current->getPreviousField(); + if (!current) { + break; + } + if (current->isStaff()) { + int ctrack = current->getTrack(); + if (track < 0) { + track = ctrack; + } + if (track != ctrack) { + return NULL; + } + if (current->isNull()) { + continue; + } + if (current->isNote()) { + return current; + } + } + } + return NULL; +} + + } // end namespace hum diff --git a/src/tool-filter.cpp b/src/tool-filter.cpp index d43ff794..e1a1da44 100644 --- a/src/tool-filter.cpp +++ b/src/tool-filter.cpp @@ -40,6 +40,7 @@ #include "tool-humsheet.h" #include "tool-humtr.h" #include "tool-imitation.h" +#include "tool-worex.h" #include "tool-kern2mens.h" #include "tool-kernview.h" #include "tool-mei2hum.h" @@ -258,6 +259,8 @@ bool Tool_filter::run(HumdrumFileSet& infiles) { RUNTOOL(humtr, infile, commands[i].second, status); } else if (commands[i].first == "imitation") { RUNTOOL(imitation, infile, commands[i].second, status); + } else if (commands[i].first == "worex") { + RUNTOOL(worex, infile, commands[i].second, status); } else if (commands[i].first == "kern2mens") { RUNTOOL(kern2mens, infile, commands[i].second, status); } else if (commands[i].first == "kernview") { diff --git a/src/tool-worex.cpp b/src/tool-worex.cpp new file mode 100644 index 00000000..07eefa31 --- /dev/null +++ b/src/tool-worex.cpp @@ -0,0 +1,223 @@ +// +// Programmer: Wolfgang Drescher +// Creation Date: Sa 4 Feb 2023 16:27:58 CET +// Filename: tool-worex.cpp +// URL: https://github.com/craigsapp/humlib/blob/master/src/tool-worex.cpp +// Syntax: C++11; humlib +// vim: syntax=cpp ts=3 noexpandtab nowrap +// +// Description: Add melismatic underlines at ending syllables of words +// + +#include "tool-worex.h" +#include "Convert.h" +#include "HumRegex.h" +#include +#include + +using namespace std; + +namespace hum { + +// START_MERGE + +////////////////////////////// +// +// Tool_worex::Tool_worex -- Set the recognized options for the tool. +// + +Tool_worex::Tool_worex(void) { + define("r|remove=b", "Remove melismatic underlines at ending syllables of words"); +} + + + +////////////////////////////// +// +// Tool_worex::run -- Do the main work of the tool. +// + +bool Tool_worex::run(HumdrumFileSet &infiles) { + bool status = true; + for (int i = 0; i < infiles.getCount(); i++) { + status &= run(infiles[i]); + } + return status; +} + +bool Tool_worex::run(const string &indata, ostream &out) { + HumdrumFile infile(indata); + bool status = run(infile); + if (hasAnyText()) { + getAllText(out); + } else { + out << infile; + } + return status; +} + +bool Tool_worex::run(HumdrumFile &infile, ostream &out) { + bool status = run(infile); + if (hasAnyText()) { + getAllText(out); + } else { + out << infile; + } + return status; +} + +bool Tool_worex::run(HumdrumFile &infile) { + initialize(); + processFile(infile); + return true; +} + + + +////////////////////////////// +// +// Tool_worex::initialize -- +// + +void Tool_worex::initialize(void) { + m_removeWordExtenderQ = getBoolean("remove"); +} + + + +////////////////////////////// +// +// Tool_worex::processFile -- +// + +void Tool_worex::processFile(HumdrumFile& infile) { + + vector textSpinesStartList; + infile.getSpineStartList(textSpinesStartList, "**text"); + + if (m_removeWordExtenderQ) { + removeWordExtenders(textSpinesStartList); + } else { + addWordExtenders(textSpinesStartList); + } + + infile.createLinesFromTokens(); + + m_humdrum_text << infile; +} + + + +////////////////////////////// +// +// Tool_worex::addWordExtenders -- +// + +void Tool_worex::addWordExtenders(vector spineStartList) { + for (HTp token : spineStartList) { + if (!token->isDataType("**text")) { + continue; + } + HTp currentToken = token; + while (currentToken) { + HTp parallelNoteToken = getParallelNote(currentToken); + HTp nextToken = currentToken->getNextToken(); + // get token of next syllable + while (nextToken != NULL && !nextToken->isNonNullData()) { + nextToken = nextToken->getNextToken(); + } + if (nextToken == NULL) { + // ignore current token if there is no next + break; + } + if (parallelNoteToken != NULL) { + // if next syllable if not direclty after the duration of the current parallel note token + if (nextToken->getDurationFromStart() > (parallelNoteToken->getDurationFromStart() + parallelNoteToken->getDuration())) { + // check if parallel note of current track is not followed by a rest + HTp nextNonNullDataToken = parallelNoteToken->getNextNonNullDataToken(); + if (!nextNonNullDataToken->isRest()) { + string syllableExtender = "-"; + bool isWordEnd = equal(syllableExtender.rbegin(), syllableExtender.rend(), currentToken->getText().rbegin()) == false; + string wordEndExtender = "_"; + bool endsWithUnderscore = equal(wordEndExtender.rbegin(), wordEndExtender.rend(), currentToken->getText().rbegin()) == true; + // if current syllable is the end end of a word + // and the token does not alredy end with a underscore + if(isWordEnd && !endsWithUnderscore) { + currentToken->setText(currentToken->getText() + "_"); + } + } + } + } + currentToken = nextToken; + } + } +} + + + +////////////////////////////// +// +// Tool_worex::removeWordExtenders -- +// + +void Tool_worex::removeWordExtenders(vector spineStartList) { + for (HTp token : spineStartList) { + if (!token->isDataType("**text")) { + continue; + } + HTp currentToken = token; + while (currentToken) { + if (currentToken->isNonNullData()) { + string wordEndExtender = "_"; + bool endsWithUnderscore = equal(wordEndExtender.rbegin(), wordEndExtender.rend(), currentToken->getText().rbegin()) == true; + if (endsWithUnderscore) { + string text = currentToken->getText(); + text.pop_back(); + currentToken->setText(text); + } + } + currentToken = currentToken->getNextToken(); + } + } +} + + + +////////////////////////////// +// +// Tool_worex::getParallelNote -- Go backwards on the line and count any note +// attack (or tied note) on the first staff-like spine (track) found to the +// left. If there is a spine split in the text and or **kern data, then this +// algorithm needs to be refined further. +// + +HTp Tool_worex::getParallelNote(hum::HTp token) { + hum::HTp current = token; + int track = -1; + while (current) { + current = current->getPreviousField(); + if (!current) { + break; + } + if (current->isStaff()) { + int ctrack = current->getTrack(); + if (track < 0) { + track = ctrack; + } + if (track != ctrack) { + return NULL; + } + if (current->isNull()) { + continue; + } + if (current->isNote()) { + return current; + } + } + } + return NULL; +} + +// END_MERGE + +} // end namespace hum