AutoPop<decltype(m_AttributeStack)> autoPop(m_AttributeStack);
Compile(ast.Block, index);
- return true;
+ return !HasErrors();
}
catch (const Exceptions::MessageException& e)
{
std::vector<IR::Block::EventType> Phrase2IRCompiler::operator()(const AST::NoteSequenceStatement& ast)
{
m_DefaultDuration = TickPerQuarter;
+ m_DefaultOctave = 5;
if (ast.Attributes.empty())
{
m_AttributeStack.push_back(ast.Attributes);
AutoPop<decltype(m_AttributeStack)> autoPop(m_AttributeStack);
- // with bounds checking
m_IR.Blocks[newIndex.ID].Attributes = m_AttributeStack.back();
if (ast.NoteSeq.is_initialized())
std::vector<IR::Block::EventType> Phrase2IRCompiler::operator()(const AST::NoteNumber& ast, int duration)
{
+ if (ast.Octave.is_initialized())
+ {
+ auto octave = ast.Octave.value();
+
+ if (0 <= octave.Value && octave.Value <= 10)
+ {
+ m_DefaultOctave = octave.Value;
+ }
+ else
+ {
+ AddMessage(
+ Message::MessageItem{
+ Message::MessageKind::Error,
+ Message::MessageID::OctaveOutOfRange,
+ m_IR.Name,
+ octave.Location,
+ {std::to_string(octave.Value)}
+ }
+ );
+ }
+ }
+
return {
IR::Event{
m_RelativeTime,
IR::Note{
- MIDI::NoteNumber(ast.Name.Name, ast.Name.Minor, ast.Octave.get_value_or(AST::NoteOctave{4, ast.Location}).Value),
+ MIDI::NoteNumber(ast.Name.Name, ast.Name.Minor, m_DefaultOctave),
100,
duration,
100
{Message::MessageID::TrackNumberIsOutOfSafeRange, "track number '{0}' is out of range (must be 0 <= # < {1})"},
{Message::MessageID::TrackNumberIsOutOfPreferredRange, "track number '{0}' is out of range (must be 0 <= # < {1})"},
{Message::MessageID::TooLargeRepeatCount, "repeat count '{0}' is too large (must be <= {1})"},
+ {Message::MessageID::OctaveOutOfRange, "octave value '{0}' is out of range (must be between 0 and 10)"},
// error_attribute.hpp
{Message::MessageID::GrammarAttributeArgument, "parse error: GrammarAttributeArgument"},