Giter Club home page Giter Club logo

mugene's Introduction

en

mugene is a music macro language (MML) compiler to generate standard midi format files (SMFs). It has been somewhat extended to also generate Vocaloid song files.

The MML syntax is somewhat formalized in MMLSpec.txt included in dists, and also briefly explained at Introduction to mugene MML.

The source package is tailored for GNU/Linux or Mac platform, but also available as Windows runnable (depends on .NET Framework). On GNU/Linux platform, configure/make/make install and run “mugene” [yourmmlfilename.mml]. On Windows, download binary archive, expand it and run mugene.exe ..\mml\default-macro.mml ..\mml\gs-sysex.mml ..\mml\drum-part.mml ..\nrpn-gs-xg.mml [yourmmlfilename.mml]. You might want to create a .bat file to shorten this lengthy command line.

If you want to use it as vocaloid “VSQ” generator, also add “—vsq” and “path/to/mml/vsq-support.mml” (replace / with \ on Windows) as arguments before your mml filename. mugene always takes the final non-option argument file name as the output filename basis, so if you don’t specify output files, it will try to create like “/usr/local/lib/mugene/mml/nrpn-gs-xg.mid” (and will fail depending on the permission).

VSQ support is almost only for Japanese, but if you are interested, a brief syntax is available on “vsq-support.mml” (included). I also wrote some research entry (in Japanese) for VSQ lyrics macro.

ja

mugeneは標準MIDIフォーマット(SMF)のファイルを生成するmusic macro language (MML)コンパイラです。また、"Vocaloid"の歌唱ファイルを作成できるよう、多少機能拡張されています。

MML文法は、配布アーカイブ内の MMLSpec.txt で多少formal syntaxとして定義されており、また mugene-users-guide-ja でも簡単に説明されています。

ソースパッケージはGNU/LinuxあるいはMacのプラットフォーム用に作られていますが、Windows上でも実行可能です(.NET Frameworkに依存)。GNU/Linuxプラットフォームでは、configure/make/make install を行って、"mugene" [mmlファイル名] を実行します。Windows上では、バイナリアーカイブをダウンロードして展開し、mugene.exe ..\mml\default-macro.mml ..\mml\gs-sysex.mml ..\mml\drum-part.mml ..\nrpn-gs-xg.mml [mmlファイル名] を実行します。長ったらしいコマンドラインを省略するバッチファイルを作った方がいいかもしれません。

vocaloidの"VSQ"ジェネレータとして使用したい場合は、引数に"—vsq"と"path/to/mml/vsq-support.mml" (Windowsの場合は\で区切る)をあなたのMMLファイル名の前に指定して下さい。mugeneでは常に最後の非オプション引数であるファイル名を出力ファイル名の本体部分に使います。なのでもしファイル名を指定しなければ、"/usr/local/lib/mugene/mml/nrpn-gs-xg.mid"のようなファイルを生成しようとします(そしてアクセス許可が無ければ失敗するでしょう)。

VSQサポートはほぼ日本語専用ですが、その簡単な説明は英語で(!) vsq-support.mml の冒頭に書いてあります。また、簡単な研究エントリを書いて、そこにサンプルを載せておきました。

mugene's People

Contributors

atsushieno avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

Forkers

jtone123

mugene's Issues

':' (__LOOP_BREAK) operator is processed incorrectly across multiple loops

Consider this kind of loop:

[[ c4 :1 d :2 e :3 f :4 g  ]2 ]2

This has two loops and branches (:1 to :4) within the loop.

It somehow does not compile:

Commons.Music.Midi.Mml.MmlException : Loop break specified beyond the loop count (fakefilename.mml line 1 column 38)

Here is the reason. When processing this MML, the compiler tries to simply iterate the innermost loop and it will be interpreted as:

[ c4 :1 d :2 e :3 f :4 g     c4 :1 d :2 e :3 f :4 g ]2

Then it finds duplicate branch operators (two of those :1 ~ :4 operators for each) and thus causing the compilation error.

We need decent loop expansion to not cause this kind of issue.

negative note length should not result in compiler crash

If we have something like:

    GATE_DENOM8 Q4 q6 c16

The resulting c8 is equivalent to c32r32 = c%6r%6, and once q6 is applied it becomes c%0 which is not valid anymore. mugene should skip such a note-on/off events.

However, this is what actually happens:

System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: Length must be non-negative integer: -232
  at Commons.Music.Midi.SmfWriter.GetVariantLength (System.Int32 value) [0x00019] in <b0250cf608614f72b4a436a6d02a37f7>:0 
  at Commons.Music.Midi.SmfWriter.GetTrackDataSize (Commons.Music.Midi.MidiTrack track) [0x0001f] in <b0250cf608614f72b4a436a6d02a37f7>:0 
  at Commons.Music.Midi.SmfWriter.WriteTrack (Commons.Music.Midi.MidiTrack track) [0x0001e] in <b0250cf608614f72b4a436a6d02a37f7>:0 
  at Commons.Music.Midi.SmfWriter.WriteMusic (Commons.Music.Midi.MidiMusic music) [0x00036] in <b0250cf608614f72b4a436a6d02a37f7>:0 
  at Commons.Music.Midi.Mml.SmfExtensions.Save (Commons.Music.Midi.MidiMusic music, System.IO.Stream output, System.Boolean disableRunningStatus, System.Func`4[T1,T2,T3,TResult] metaWriter) [0x00020] in /sources/commons-music-prog/mugene/mugenelib/src/mml_compiler_main.cs:380 
  at Commons.Music.Midi.Mml.MmlCompiler.Compile (System.Boolean skipDefaultMmlFiles, System.Collections.Generic.IList`1[T] inputs, System.Func`4[T1,T2,T3,TResult] metaWriter, System.IO.Stream output, System.Boolean disableRunningStatus) [0x0000f] in /sources/commons-music-prog/mugene/mugenelib/src/mml_compiler_main.cs:211 
  at Commons.Music.Midi.Mml.MmlCompiler.CompileCore (System.String[] args) [0x0034e] in /sources/commons-music-prog/mugene/mugenelib/src/mml_compiler_main.cs:196 
  at Commons.Music.Midi.Mml.MmlCompiler.Compile (System.String[] args) [0x00002] in /sources/commons-music-prog/mugene/mugenelib/src/mml_compiler_main.cs:78 

handling of // inside string literal

Current parser implementation blindly looks for // and trims the remaining of lines after it. When there is // in the middle of a string literal, it cuts // and the string literal (which should be enclosed by double-quot " ) is regarded as terminated incompletely.

It could often happen when a meta text contains an URL (http://...)

There is a workaround that the parser handles / as escaped / .

weird drum part processing: note on velocity ignored

Within this MML, when compiled into an SMF, the second n36 does not result in velocity 64. Instead, its velocity becomes 127.

#define DRUMTRACKS 10

#macro DRUMTRACKS Ba { n36,0,127 r }
#macro DRUMTRACKS Bb { n36,0,112 r }
#macro DRUMTRACKS Bc { n36,0,96 r }
#macro DRUMTRACKS Bd { n36,0,80 r }
#macro DRUMTRACKS Be { n36,0,64 r }
#macro DRUMTRACKS Sa { n38,0,127 r }
#macro DRUMTRACKS Sb { n38,0,112 r }
#macro DRUMTRACKS Sc { n38,0,96 r }
#macro DRUMTRACKS Sd { n38,0,80 r }
#macro DRUMTRACKS Se { n38,0,64 r }

10	t120

10	TRACKNAME "SF2_909" V120 l16
	v127 n36,1  n36,1,64

This does not happen to non-drum tracks, so there is something glitchy here.

change processing model for bugfixing loop

There are couple of source conditions defined as UNHACK_LOOP. Right now the compiler treats the loop controllers ('[', ']', ':' and '/') as predefined operators. They are wrong. They must be defined as a mere macro for each.

Currently UNHACK_LOOP cannot be enabled because of the current processing model of MmlOperationUses.
When resolving macros into flatten stream of MIDI events, they are converted from within the list of MmlOperationUse which are either from the track MML or macro definitions.
When those loop controllers are being expanded as macro, the content is nothing and no content of the loop will be iterated.

To fix this issue, the MmlOperationUses must be stored first, and then they have to be expanded.

There is another source condition labeled as LOOP_BY_RESULT, which actually does somewhat similar to the desired model explained above. But it expands the loop contents as the result of first iteration of MML processing. It will break operators that depend on loop, e.g. spectra. So it is actually no-go.

There is another difficulty in the processing model switch.
A simple desired processing model would be that Loop class structure stores a list of source MmlOperationUses while processing them, and at the end of the loop it expands the stored ones just like the compiler does right now (but remember that current list does not work across macros i.e. macro ']' will break that).
It seems simple but doesn't work... When expanding macros we need to resolve variables and macro arguments (call it "context" here), but this context information is lost after "flattening" macros and those operators cannot be re-processed afterwards. To make it doable, we need to preserve the context changes (which I'm afraid that it's going to be too much to process).

Or somehow change the way how context list of MmlOperationUses are resolved. That might be easier.

in-advance specification of variables

Text music sakura has a cool feature that lets you specify verlocity, gatetime, length, key-on delay (TIMING in our syntax) or octave in advance e.g. v.onNote(100,90,80,70,60) cdefg (plays c to g with decreasing velocity). They can be .onNote(), .onTime(), .onCycle() (works like LFO) etc.

It is likely doable within current mugene syntax, but I want to have them within default-macro,mml.

too slow compilation

find out which causes it. For now, only 6000 bytes of MML causes more than 2 seconds to compile.

track number in floating point numbers

It would decrease mess if mugene accepts track numbers in floating points.

When we compose songs, we have to specify track number mostly based on the target channel number. But sometimes we want to split tracks so that phrasing attempt can become easily testable and/or switcheable. And channel numbers and track numbers are better related rather than randomly assigned. For example, if you are adding a new track to the existing song which has track 1 and 2.

1  CH1 @0 o5 l8
1 b1
11 CH1 o5 l8
11 e1
2 CH2 @48
2 c0e0g1

Here I assigned 11, instead of 3 because then the track for CH3 will be 4 or later, or can be some random-ish number. However if it goes up to channel 10 (drums) there will be more channels to be assigned to the rhythm part (typically one for bd/sd/tom, one for hihats and optionally cymbals etc.).

An intelligent solution here would be:

1.0,1.1  CH1 @0 o5 l8
1.0 b1
1.1 CH1 o5 l8
1.1 e1
2 CH2 @48
2 c0e0g1

There are various pieces of code in the overall compiler code that premises integral track numbers.

weird macro resolution error

The lines below fails to resolve ">c"

#macro 5 CRDA len:length=$__length { f0,,60>c0f$len< }

5 CRDA8

atsushi:/svn/commons-music-prog/mugene$ mono -O=-all --debug mugene/bin/Debug/mugene.exe ~/Desktop/test.mml
Macro >c was not found

Full migration to mugene-ng

mugene is in the process of migration to mugene-ng (in Kotlin). Any new development will happen there.

Having said that we are still missing a handful of features from this old repo:

  • Tests are only partially ported.
  • MML decompiler.
  • vscode extension.
    • Language server.
  • augene-vnext integration.
  • xmmk alternatives (most likely in Jetpack Compose).

preserving conditional compilation

Conditional compilation is useful when we want to start from anywhere in the song, but it brings in "bugs" in MML in that such conditionally compiled tracks especially with #conditional block results in unexpected velocity, octave, key shifts etc. No one wants inconsistent song outputs depending on whether conditional blocks are used or not.

A solution is to filter out only MIDI note on messages.

un-flatten macro processing (to reduce extra use of resources)

For now mugene expands macros by expanding everything to primitive operations and then processes them. There is however an exception "__APPLY" operation that allows recursive macro expansion.

The compiler should actually be able to avoid this expansion and process macros just recursively (and I have such a patch to eliminate macro flattener), to reduce extra use of resources. But there is a blocking issue on loop expansion that premises the flatten list of operations.

bogus operator priority handling

In an expression, it does not handle operator priority in derisable manner at all.

So far, a workaround is to wrap subexpressions with '{' and '}'.

possible need for note-off and note-on prioritizing

When I was authoring some phrase like this:

1   @30 o4 V110 v100 l8 RSD20 DSD40
    Kc+Kf+
    [ fg(50g)50g^2.b4a4f4 : fg(50g)50g^1. ]2  fg(50g)50g^1f2  [r-1]8
    [ de(50e)50e^2.g4f4d4 : de(50e)50e^1. ]2  de(50e)50e^1d2  [r-1]8
    < [ ab(50b)50b^2.>e4d4<a4 : ab(50b)50b^1. ]2  ab(50b)50b^1a2

It is like, I wanted to enter each note on the tritone (possibly quadtone, after this) chords respectively and entered MML like this, making use of [r-1] to roll back. However at the end of the fourth bar (at b4a4f4 bar), only a4 is noted on.

It is because the other chord notes emit note-offs, resulting that the first note-on events (e.g. b4a4f4) are suppressed by the following note-offs of the chord note sequence (e.g. g4f4d4, note that f4 is connected).

It can be easily workarounded if the song gives q operation e.g. q1 but that's not ideal.

isolate "channel" variables and unleash extensive output channel support

The biggest limitation in mugene to support non-MIDI output formats / devices / playback engines is that it stricttly limits to 16 channels to produce raw MIDI messages that contain channel as the status byte.

It is required so that an arbitrary track can contain messages that are scattered to more than one channel, as well as supporting multiple tracks bound to one single channel.

The latter is still required, but the former is not necessary for meaningful composition. If we can limit a track to be bound to only one channel, then things become much easier to extend support non-MIDI outputs.

Starting with "mugene 2", there will be some abstract music data structure with "channel mapping" which is generated from mapping definitions in the MML and then adjusted to specific output types. "Audio Processor players" can take the outputs along with the channel mapping and then split tracks and attach to each Audio Processor channel which also has separate instrumental settings (like "state" in VST). The existing SMF support is left as is - expect for channel changes in the middle.

dot without length should be supported

Right now . is treated just as "* 1.5" operator, and it hence requires explicit length argument. Thus, notation like "l4c.e.g8" is invalid (stuck at c.). It is often inconvenient.

To support this syntax, I likely have to treat __length as "predefined" variable like __timeline_position, to calculate length accordingly, and treat '.' as a length-omittable notation.

support arpeggio by '&' operation

"c&e&g" can be interpreted as noteon_c .. noteon_e .. noteon_g .. noteoff_c|e|g. This notation makes it easier to achieve arpeggio.

support XML output for Bopomofo

When we want to support Bopomofo, the text encoding must not be in Shift_JIS. Though .vsq format premises Shift_JIS (we can generate text event in any encodings, but there is no tool that can parse .vsq files in non-SJIS format). So, what we need is non-SMF format.

Though it is not likely suitable to support non-SMF output within this compiler. We could generate UTF8-based text events within standard SMF (.vsq) and then write some other tool to convert from .vsq to, say, .xvsq.

Documentable macro definition syntax

Macros (and probably variables) should be documentable so that their docs can be shown on hover or documentLink operations on language server protocols.

eliminate some hacky primitive operations

There are some "primitive operations" that make syntax hackily done but prevents live playing (kind of). Namely __ON_MIDI_NOTE_OFF that supports chord for 0-length notes, and __SYNC_NOFF_WITH_NEXT that supports chord for contiguous notes (arpeggio, used by "&").

They had better be reimplemented by other means.

Add support for "spectra for each note" operation

Right now spectra operation is valid only as a one-shot operation or a simply-repeating operation regardless of note on/offs. It is often very convenient to fire spectra on every note on (such as spectrum modulation changes by note on).

operator ^

Currently ^ is just defined as an alias of '+'. But it invalidates such syntax like g^4 (which should mean, note g of length 4 + default length) as note g+ of length 4. It is not acceptable.

arguments to macro without definition should be concatenated to macro text

It should be possible to define macro like this:

#macro CHORD_A { <b0>e0g-0b }
#macro CHORD_B { c0e0f0a }

and use it like this

A 5 CHORDA1  CHORDB1

Current MmlStreamGenerator.ProcessMacroCall() cannot handle it and fails to resolve 1+1+1+1, leading to unexpected compilation behavior (actually crashes).

It is because this length specification is not attached to the last note of each macro.

If we define this #macro as a #define, then it should work, but we want to define different set of chords on different tracks, that's why macro have track specification.

Current macro expansion semantics is like this:

  • parse macro argument specification from the definition
  • parse macro body text from the definition into operations.
  • when applying macro, get macro definition by name.
  • fill macro arguments with explicitly specified call parameters.

Extraneous arguments are not processed. That is problematic.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.