Skip to content

Commit

Permalink
Feature/456 phrase rendermode stretch vs normal (#460)
Browse files Browse the repository at this point in the history
* impl parser

* rendering impl.
manual updated

* adding rendertest
rendered manual

* fixing wrong repeat type

---------

Co-authored-by: samba <samba@manjaro>
  • Loading branch information
SambaGodschynski and samba authored Nov 25, 2024
1 parent 8bb3c7e commit 9d825dc
Show file tree
Hide file tree
Showing 10 changed files with 128 additions and 7 deletions.
7 changes: 4 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ fe/package-lock.jso
.vscode
package.json

rendertests/lib/
rendertests/lib64
rendertests/pyvenv.cfg
lib/
lib64
pyvenv.cfg


# Created by
https://www.gitignore.io/api/c,c++,grunt,cmake,emacs,angular,visualstudio
Expand Down
14 changes: 14 additions & 0 deletions manual.in.md
Original file line number Diff line number Diff line change
Expand Up @@ -903,10 +903,24 @@ PHRASE_NAME = PHRASE_EVENTS;
```

**Use a phrase**

There are two ways to playback an phrase:

**playback streched**

If the phrase duration is unequal to the target duration, the phrase will be rendered streched to fit into the target.
```
>"PHRASE_NAME"DURATION_VALUE
```

**playback cut off**
If If the phrase duration is unequal to the target duration, the phrase will be rendered cut off or filled with rests to fit into the target.
```
>>"PHRASE_NAME"DURATION_VALUE
```



```language=Werckmeister,type=full
device: MyDevice _isType=webPlayer _useFont="FluidR3-GM";
instrumentDef: piano _onDevice=MyDevice _ch=0 _pc=1 _cc=8;
Expand Down
25 changes: 23 additions & 2 deletions manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -903,10 +903,24 @@ PHRASE_NAME = PHRASE_EVENTS;
```

**Use a phrase**

There are two ways to playback an phrase:

**playback streched**

If the phrase duration is unequal to the target duration, the phrase will be rendered streched to fit into the target.
```
>"PHRASE_NAME"DURATION_VALUE
```

**playback cut off**
If If the phrase duration is unequal to the target duration, the phrase will be rendered cut off or filled with rests to fit into the target.
```
>>"PHRASE_NAME"DURATION_VALUE
```



```language=Werckmeister,type=full
device: MyDevice _isType=webPlayer _useFont="FluidR3-GM";
instrumentDef: piano _onDevice=MyDevice _ch=0 _pc=1 _cc=8;
Expand Down Expand Up @@ -981,7 +995,7 @@ parameters = {
In the `perform` function you can implement your modification. Werckmeister expects a table with event informations to be returned from that function. This is the most minimalistic implementation you could write:

```lua
function perform(events, params, timeinfo)
function perform(events, params, timeinfo, context)
return events
end
```
Expand Down Expand Up @@ -1099,6 +1113,13 @@ Contains a table with informations about the current musical time.
### `context` argument
Contains an interface with some context related functions.

#### setDate
`setDate(key, stringValue)`
sets a global date to exchange data between mods and "perform functions".

#### getDate
`getDate(key)` returns the value for a key (see [setDate](#setdate))

#### getCurrentInstrument
returns information about the current instrument
```lua
Expand Down Expand Up @@ -1158,7 +1179,7 @@ instrumentConf: myInstrument
The `execute` function works the same way as the `perform` function does. Except the `peform` function modifies existing events, the `execute` function can be used to create new events. Therefore the function signature is slightly different:

```lua
function execute(params, timeinfo)
function execute(params, timeinfo, context)
return {
-- some events
}
Expand Down
Binary file added rendertests/references/456_phrases_normal.sheet.mid
Binary file not shown.
28 changes: 28 additions & 0 deletions rendertests/tests/456_phrases_normal.sheet
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

using "/chords/default.chords";

device: _usePort=17 _setName=MyDevice _isType=midi;
instrumentDef: _setName=piano _onDevice=MyDevice _ch=0 _pc=1 _cc=8;

tempo: 80;

myPhrase = c2 d4 e;
myPhraseII = >"myPhrase"2 f4 g;
myPhraseIII = c2;
myPhraseIV = c4 c, c c';

[
instrument: piano;
{
>"myPhrase"2 >"myPhrase"2 | >>"myPhrase"1 |
>>"myPhrase"2 >>"myPhrase"2 | >>"myPhrase"2. >>"myPhrase"4 |
>>"myPhraseII"1 | >>"myPhraseII"2. >>"myPhraseII"4 |
>>"myPhraseII"1 |
/signature: 3 4/
c4 g g |
>>"myPhraseIV"2.~ | &4 >>"myPhraseIV"2 |
/signature: 4 4/
>>"myPhraseIV"2 &2 | >"myPhraseIV"2 &2

}
]
1 change: 1 addition & 0 deletions src/compiler/Preprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ namespace compiler
else if (processData.lastNoRepeat.isPhrase())
{
ev.stringValue = processData.lastNoRepeat.stringValue;
ev.isPhraseStrechedPlayback = processData.lastNoRepeat.isPhraseStrechedPlayback;
}
else
{
Expand Down
19 changes: 18 additions & 1 deletion src/compiler/SheetEventRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,11 +342,21 @@ namespace compiler
const auto &phraseEvents = *phraseInfo.events;
logger_->babble(WMLogLambda(log << "phrase found: " << phraseEvents.size() << " events"));
com::Ticks phraseEventLength = isTiedEvent ? phraseEvent.tiedDurationTotal : phraseEvent.duration;
com::Ticks totalRenderLength = phraseEventLength;
std::list<com::String> phraseTags(phraseEvent.tags.begin(), phraseEvent.tags.end());
for(const auto &event : phraseEvents)
{
auto copy = event;
copy.duration = event.duration * (phraseEventLength / phraseInfo.duration);
if (phraseEvent.isPhraseStrechedPlayback)
{
copy.duration = event.duration * (phraseEventLength / phraseInfo.duration);
} else
{
if (totalRenderLength < event.duration) {
copy.duration = totalRenderLength;
}
totalRenderLength -= event.duration;
}
addTagsRecursive(copy, phraseTags);
if (event.isPhrase())
{
Expand All @@ -361,7 +371,14 @@ namespace compiler
} else {
addEvent(copy);
}
if (totalRenderLength <= 0) {
break;
}
}
if (phraseEvent.isPhraseStrechedPlayback == false && totalRenderLength > 0)
{
ctx_->seek(totalRenderLength);
}
if (isTiedEvent)
{
ctx_->seek(-(phraseEventLength - phraseEvent.duration));
Expand Down
1 change: 1 addition & 0 deletions src/documentModel/objects/Event.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ namespace documentModel
double pitchBendValue = 0;
int controllerNumber = 0;
int controllerValue = 0;
bool isPhraseStrechedPlayback = true;

bool isTimeConsuming() const;

Expand Down
15 changes: 14 additions & 1 deletion src/parser/sheetParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ BOOST_FUSION_ADAPT_STRUCT(
(documentModel::ASheetObjectWithSourceInfo::SourceId, sourceId)
(documentModel::Event::Type, type)
(documentModel::Event::Tags, tags)
(bool, isPhraseStrechedPlayback)
(com::String, stringValue)
(documentModel::Event::Duration, duration)
(unsigned int, sourcePositionEnd))
Expand Down Expand Up @@ -125,6 +126,17 @@ namespace
DcArgs,
DcEvents
};
enum PhraseConfigFields
{
PhSourceBegin,
PhSourceId,
PhEvType,
PhEvTag,
PhIsStrechedPlayback,
PhStringValue,
PhDuration,
PhSourceEnd
};
const int DefaultNumberOfBarRepeats = 0;
}

Expand Down Expand Up @@ -407,7 +419,8 @@ namespace parser
>> attr(sourceId_)
>> attr(Event::Phrase)
>> (("\"" >> +(lexeme[+char_(ALLOWED_EVENT_TAG_ARGUMENT)]) >> "\"" >> "@") | attr(Event::Tags()))
>> ">" >> lexeme["\"" >> +char_(ALLOWED_PHRASE_NAME) >> "\""]
>> (lit(">>") >> attr(false) | lit(">") >> attr(true))
>> lexeme["\"" >> +char_(ALLOWED_PHRASE_NAME) >> "\""]
>> (durationSymbols_ | attr(Event::NoDuration))
>> current_pos_.current_pos
>> -(
Expand Down
25 changes: 25 additions & 0 deletions src/tests/test_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2114,6 +2114,7 @@ BOOST_AUTO_TEST_CASE(test_use_phrase)
BOOST_CHECK_EQUAL(defs.tracks[0].voices[0].events.size(), size_t(2));
BOOST_CHECK_EQUAL(defs.tracks[0].voices[0].events[0].type, Event::Phrase);
BOOST_CHECK_EQUAL(defs.tracks[0].voices[0].events[0].phraseName(), com::String("myPhrase"));
BOOST_CHECK_EQUAL(defs.tracks[0].voices[0].events[0].isPhraseStrechedPlayback, true);
BOOST_CHECK_EQUAL(defs.tracks[0].voices[0].events[0].duration, 1.0_N8);
}
BOOST_AUTO_TEST_CASE(test_use_tied_phrase)
Expand Down Expand Up @@ -2222,4 +2223,28 @@ myPhrase = c d e f; \
BOOST_CHECK_EQUAL(defs.documentConfigs.size(), size_t(2));
BOOST_CHECK_EQUAL(defs.tracks.size(), size_t(2));
}
}


BOOST_AUTO_TEST_CASE(test_use_phrase_normal_mode)
{
using namespace com;
using namespace documentModel;
using documentModel::PitchDef;
com::String text = FM_STRING("\
[\n\
{\n\
>> \"myPhrase\"8 |\n\
}\n\
]\n\
");
SheetDefParser parser;
auto defs = parser.parse(text);
BOOST_CHECK(defs.tracks.size() == 1);
BOOST_CHECK(defs.tracks[0].voices.size() == 1);
BOOST_CHECK_EQUAL(defs.tracks[0].voices[0].events.size(), size_t(2));
BOOST_CHECK_EQUAL(defs.tracks[0].voices[0].events[0].type, Event::Phrase);
BOOST_CHECK_EQUAL(defs.tracks[0].voices[0].events[0].phraseName(), com::String("myPhrase"));
BOOST_CHECK_EQUAL(defs.tracks[0].voices[0].events[0].isPhraseStrechedPlayback, false);
BOOST_CHECK_EQUAL(defs.tracks[0].voices[0].events[0].duration, 1.0_N8);
}

0 comments on commit 9d825dc

Please sign in to comment.