kuma4649 / mml2vgm

GNU General Public License v3.0
105 stars 10 forks source link

allow dynamic length adjustment within part arp #145

Open ultrasound1372 opened 8 months ago

ultrasound1372 commented 8 months ago

Problem

The example for the part arp is to play the Final Fantasy prelude, which is a useful example. however, I was transcribing something that required some polyphony recently and wanted to automatically switch between the assigned polyphony channels to maximize polyphony. The trouble is that this does not use the same lengths everywhere, in fact not even within the same small note phrase, which required me to do very careful calibration of note lengths and rests among the channels. The fact that the part arp exists already puts this compiler above most others, where automatic channel-swapping is reserved for sophisticated trackers with an instrument mode. But I think you could take it even further.

Proposed Solution

Extend the syntax available inside part arps to allow for two new commands. l`n and `n, where n is a note length.
The first sets the default length for the part arp's switcher, as note length is already going to the actual channel and does not factor into the arp. I believe the current behavior is to derive this from the existing default length when the arp is opened? Say I wanted to do an arp with all the waits being the same length, but wanted to have the notes be twice as long. I could do something like this.

'S1-3 o2 [` l`8 l4 [cd+g>]4 [d+c<g]2 d+c `]

Which would play a new note on a new channel every 8th note, but all the notes themselves would have the length of a quarter note, letting them ring out even after the part arp has switched away. Bonus of this is that the actual note length can be different, meaning you don't have to specify explicit quarter note lengths on every note, or abuse quantization to do something like q*4 to achieve the same effect. I think the engine can already write data like this so the only trick is to make the switching length adjustable. Backward compatibility would dictate it inherits the note length if not specified.
The second command would allow me to use specific wait lengths without having to change the default one, which would allow me to use this for passages that are not all the same length. It is an analogue of note default length versus individual note lengths. Whether this would be a note decorator that only works inside part arps is up to you, it would make sense if it were but also it being a standalone command would be fine. It would then look something like this, assume that using the same channel again would cut a previous note short.

'L03-05 o6 [` l2 l`8 >e< `4. b `4 aga `8 b `. ga >d< `4. b `4 aga f+ `. ga>d< `4. b `4 >dc<b `8 a `8 gae `]

Where the `n after a given note means play this note and then wait this long before going to the next one, overriding the default. It might make more sense as a note decoration. While in practice the length could be increased with integration of rests and wait commands causing it to pause there before switching, I don't think it could be meaningfully shortened below the default that way.

Additional context

This came up specifically due to this particular composition, where you can see how ugly and difficult the transcription of this polyphony ended up without this feature. Channels 1 and 2 are deliberately not used in this part, although the first transition where they are included could use them as well. You can also see I do use an actual part arp as you have them written later, but only because all the distances are the same. Heavily in progress of course.
marble.txt This is my attempt to transcribe the Marble Machine track using a YM2413.


問題

パートarpの例は、ファイナルファンタジーのプレリュードを演奏するもので、これは便利な例です。しかし、最近ポリフォニーを必要とするものをトランスクリプションしていて、ポリフォニーを最大化するために、割り当てられたポリフォニー・チャンネルを自動的に切り替えたいと思っていました。困ったことに、これはどこでも同じ長さを使うわけではなく、実際、同じ小さな音符のフレーズの中でさえも同じ長さを使うわけではないので、チャンネル間の音符の長さと休符を非常に注意深く校正する必要があった。arpというパートがすでに存在しているという事実が、このコンパイラを他のほとんどのコンパイラよりも優位に立たせる。しかし、私はそれをさらに進めることができると思う。

解決策の提案

パートarp内で使用可能な構文を拡張し、2つの新しいコマンドを使用できるようにする。l`n`n で、nは音符の長さです。 最初のコマンドはパートarpのスイッチャーのデフォルトの長さを設定する。現在の動作は、arpを開いたときに、既存のデフォルトの長さからこの長さを導き出すようになっているのではないでしょうか?例えば、すべてのウェイティングが同じ長さのarpを作りたいが、ノートの長さを2倍にしたいとします。このようにすることができます。

'S1-3 o2 [` l`8 l4 [cd+g>]4 [d+c<g]2 d+c `]

この場合、8分音符ごとに新しいチャンネルで新しい音を演奏することになるが、すべての音符は4分音符の長さを持ち、パートアープが切り替わった後も鳴り続ける。つまり、すべての音符に4分音符の長さを明示的に指定したり、同じ効果を得るためにクオンタイズを乱用してq*4のような処理をしたりする必要がないんだ。エンジンはすでにこのようなデータを書くことができるので、唯一のトリックはスイッチングの長さを調整できるようにすることだと思います。後方互換性があれば、指定がなければ音符の長さを継承することになる。 つ目のコマンドは、デフォルトの長さを変更することなく、特定の待機長を使用できるようにするものです。これは、音符のデフォルトの長さと個々の音符の長さのアナロジーです。これがパート譜の中だけで機能する音符の装飾になるかどうかは、あなた次第です。同じチャンネルをもう一度使うと、前のノートが短くなると仮定すると、次のようになります。

'L03-05 o6 [` l2 l`8 >e< `4. b `4 aga `8 b `. ga >d< `4. b `4 aga f+ `. ga>d< `4. b `4 >dc<b `8 a `8 gae `]

ここで、与えられたノートの後の `n は、このノートを演奏し、次のノートに移るまでこの時間待つことを意味し、デフォルトを上書きします。これは音符の装飾としてより理にかなっているかもしれない。実際には、休符やwaitコマンドを統合して、切り替える前にそこで一時停止するようにすれば、長さを長くすることができますが、そのようにすれば、デフォルトよりも有意義に短くできるとは思えません。

追加コンテキスト

このポリフォニーのトランスクリプションが、この機能なしでいかに醜く困難なものになったか、おわかりいただけると思います。チャンネル1とチャンネル2は、このパートでは意図的に使っていません。また、後で書いてもらうように、実際のパートのアープを使っているのがわかると思うが、すべての距離が同じだからだ。もちろん、現在進行中です。 marble.txt これはYM2413を使ってマーブルマシンのトラックを書き起こそうとしたものです。

kuma4649 commented 8 months ago

わかりにくいので、「記述するmml」と「実際に演奏されるmml」を提示していただけるとありがたいです。

仰りたいのはこういうことでしょうか? Case 1: 記述するmml

  'S1-3 o2 [` l`8 l4 [cd+g>]2 `]

実際に演奏されるmml

  'S1   o2    l8      c& c>  r   c& c>  r   r
  'S2   o2    l8      r  d+& d+> r  d+& d+> r 
  'S3   o2    l8      r  r   g&  g> r   g&  g>

Case 2: 記述するmml

  'L03-05 o6 [` l2 l`8 >e< `4. b `4 aga `8 b `]

実際に演奏されるmml

  'L03    o6       l8  >e& <e& e  g& g& g 
  'L04    o6       l8  >r  <b& b& b  a& a 
  'L05    o6       l8  >r  <r  a& a  r  b 

↑の理解であっているのであれば、以下の通りに記述できるようにしたほうが分かりやすいかもしれません。如何でしょうか。(実際に発音する音調をlコマンド、音符コマンドの修飾コマンドとして指定する) Case 1: 記述するmml

  'S1-3 o2 [` l8`4 [cd+g>]2 `]

実際に演奏されるmml

  'S1   o2    l8    c& c>  r   c& c>  r   
  'S2   o2    l8    r  d+& d+> r  d+& d+>  
  'S3   o2    l8    r  r   g&  g> r   g >
                                          ~~~~最後だけ違いが出る

Case 2: 記述するmml

  'L03-05 o6 [` l8`2 >e<  b`4. a`4 ga b`8 `]

実際に演奏されるmml

  'L03    o6    l8   >e& <e& e  g& g& g 
  'L04    o6    l8   >r  <b& b& b  a& a 
  'L05    o6    l8   >r  <r  a& a  r  b
                                        ~~この場合は違い無し
ultrasound1372 commented 8 months ago

I suppose I must have provided difficult data to start with, or maybe just incorrect. If we take it to be a note modifier, applied to the note that comes before the switch, the input for your second example would be:

'L03-05 o6 l2`8 [` >e1`4.< b.`2 ag a`4 b `]

Which says the default note length is a half note, and the default switch step is an eighth note. That would then give the output:

'L03 >e1< g2
'L04 r4. b2. a2
'L05 r4. r2 a2 b2

Or if it has to be modifying the note after the switch rather than before, shift all of the explicit `n modifications one to the right, which better matches your example. It still would require some careful timing by the composer if they wanted the notes to extend all the way up until the channel is to be used again, like I just did, but if the round-robin comes around and a note is still playing from a previous one it should just get cut off. As for the first case the sound is fine, the rests at the end are the only thing that's different aren't they? Do they make it so that all the channels will end at the same place in the overall tempo? That may or may not be desirable depending on if you want to put other things on the channels, like I did in the composition for the transitions, so the second idea you provided seems to be the better way to go.


私が最初に提供したデータが難しかったか、あるいは間違っていたのでしょう。スイッチの前の音に適用されるノートモディファイアだとすると、2番目の例の入力は次のようになります:

'L03-05 o6 l2`8 [` >e1`4.< b.`2 ag a`4 b `]

デフォルトの音符の長さは2分音符で、デフォルトのスイッチステップは8分音符です。そうすると、次のように出力される:

'L03 >e1< g2
'L04 r4. b2. a2
'L05 r4. r2 a2 b2

あるいは、スイッチの前ではなく、スイッチの後に音を修正する必要がある場合は、明示的な n の修正をすべて右に1つずらせば、あなたの例によりよくマッチします。 しかし、もしラウンドロビンが回ってきて、前の音符がまだ演奏されている場合は、その音符はカットされます。最初のケースに関しては、音は問題なく、最後の休符だけが違いますよね?全体のテンポの中で、すべてのチャンネルが同じところで終わるようにするのですか?それは、トランジション用のコンポジションでやったように、チャンネルに他のものを置くかどうかによって、望ましいかどうかが変わってくる。

kuma4649 commented 8 months ago

言いたいことはわかりました。 しかしmmlが読みにくい。

 'L03-05 [` l8`2 e4.`1 b2`. a g a4 b2 `]

妥協案としては↑ですね。。。

ultrasound1372 commented 8 months ago

So the existing note length specification determines the switch length, and the extra ` decorator controls the note's duration on that channel?
つまり、既存の音符の長さの指定がスイッチの長さを決定し、追加のデコレーターがそのチャンネルでの音符の長さをコントロールするということですか?

kuma4649 commented 7 months ago

Yes. そうです。

ultrasound1372 commented 7 months ago

Alright, that will work then. Thanks very much!
よし、それなら大丈夫だ。どうもありがとう!

kuma4649 commented 7 months ago

TAG715をお試しください。

ultrasound1372 commented 7 months ago

One last question. Will the tie decoration on a note cause it to play the next note on the next channel without waiting any time at all, thus allowing the creation of chords? I figured it would be tie rather than length 0 since length 0 is related to the tone doubling functionality.
最後の質問です。ある音符にtieの装飾があると、次のチャンネルで次の音符が待たずに演奏され、和音を作ることができるのでしょうか?長さ0は倍音機能に関係しているので、長さ0ではなくtieだろうと思いました。

kuma4649 commented 7 months ago

どのようなmmlですか?

ultrasound1372 commented 7 months ago

I just realized it would actually make more sense for it to be the existing chord modifier that you have for the MIDI mode :. So say I gave this MML.

'L01-05 o6 [` l8`2 g4:b4:>e4< egba4b `]

It would give something like this.

'L01 g b
'L02 b r8 a
'L03 >e< r4. b
'L04 r4 e
'L05 r4 r8 g

That is, the part arp would distribute the notes about the allocated channels without waiting between switches at all, making a chord.


MIDIモードのコード・モディファイア:を使う方が理にかなっていることに気づいたんだ。例えば、こんなMMLを作ったとしよう。

'L01-05 o6 [` l8`2 g4:b4:>e4< egba4b `]

このようになります。

'L01 g b
'L02 b r8 a
'L03 >e< r4. b
'L04 r4 e
'L05 r4 r8 g

つまり、パートアルペジオは、スイッチとスイッチの間をまったく待たずに、割り当てられたチャンネルにノートを分散させ、和音を作ることになる。

kuma4649 commented 7 months ago

今回はその機能は要らないです。 なぜなら、 ・似たような機能が既にある ・コマンドの本来の目的から外れる ・読みにくい からです。

ultrasound1372 commented 7 months ago

Fair enough, although as I can't see it's likely my MML will on the whole be less readable. What is the similar function you mention? I know there is the chord thing but that only applies to MIDI. Otherwise you have implemented this feature well and can close this issue.
そうだね。でも、僕は見えないから、僕のMMLは全体的に読みにくくなるだろうね。あなたがおっしゃる同様の機能とは何ですか?コードのことは知っていますが、それはMIDIにしか適用されません。そうでなければ、あなたはこの機能をうまく実装しているので、この問題を解決することができます。

kuma4649 commented 7 months ago

'[|'コマンドと '|]'コマンドです>似たような機能