Nusedriver lite manual

Index

Overview

Nusedriver liteは、Nurv Cockymanが開発したファミコン用サウンドドライバ。
Nusedriver_20210717_r1をベースとして、音符情報1つを1Byteに収める為の設計変更・実装を施したもの。
以下のテーマについて、バランスを取りつつ追及していきたい。
アセンブルにはnesasm_x64.exeを使用する。

将来的にゲームに組み込んで使用したい。
実機での動作確認は随時実施。Write only register問題以外は未検出。(2021/8/15現在)
効果音に関しては未実装。
DPCMは使用しない。
拡張音源は使用しない。

Features

NoteLength

音符の長さは2Byteで表現される。
1frame毎にnote_lengthからbpm値が減算され、0以下になったら次の音符を読み込む。
note_lengthが負の数となってしまっても自動で補正される為、frameのガタツキについてユーザが意識する必要は無い。
NoteLengthはtableになっており、16Byte/1set、最大4set登録出来る。
4setの内訳は、normal, detted(付点), triplet(3連符), user_defined。
音符毎にindex(1-7) 7段階を指定する。
index:1234567
normal:4509001800360072001440028800
detted:675135027005400108002160043200
triplet:1503006001200240048009600

NoteScale

1音符1Byteを実現する上で最も重要な機能・概念。
Rootとなる音階からの差によって音階の高低を表現する。
1つのNote Scaleは、Rootからの差分8個からなる。
音符毎にindex(0-7) 8段階を指定する。

index:01234567
major_scale:$00$02$04$05$07$09$0B$0C
minor_scale:$00$02$03$05$07$08$0A$0C
index 0-7それぞれに、Rootからの差分(単位は半音階)が定義される。
NoteScaleは最大32個登録することが出来る。
PermanentNoteScaleによって曲中で切り替えることが可能。

NoteVelocity

音符毎に4段階(0-3)の強弱がつけられる。
NoteVelocityはtableになっており、64Byte/1set、最大4set登録出来る。
PermanentNoteVelocityによって曲中で切り替えることが可能。
1setの内容は、16Byte * 強弱4段階。
この16ByteはVolumeEnvelopeと関連している。

ex.下記条件の場合、.db 3行目の12番目である$08が最終的なchannel_volumeとなる。
note_velocity = 2
volume_envelope_decoded_data = 12
NOTE_VELOCITY_TABLE:

.note_velocity_0

    .db $00,$00,$00,$00,$00,$00,$00,$00,$01,$01,$01,$01,$01,$01,$01,$01 ; note_velocity = 0
    .db $00,$01,$01,$01,$02,$02,$02,$03,$03,$03,$04,$04,$04,$05,$05,$05 ; note_velocity = 1
    .db $00,$01,$02,$02,$03,$04,$04,$05,$05,$06,$07,$07,$08,$09,$09,$0A ; note_velocity = 2
    .db $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0A,$0B,$0C,$0D,$0E,$0F ; note_velocity = 3

NoiseVoice

Noise channelは登録済みVoiceを呼び出して鳴らす形となる。
NoiseVoiceは、VolumeEnvelopeAttackとPitchEnvelopeから構成される。
Noise channel向けPitchEnvelopeは他のchannelとは違い、周波数の相対変化ではなく、$400Eレジスタに書き込む値そのものである。

Others

その他、特徴的な機能として、NoteEnvelopeAbsolute, PitchEnvelopeDelay, VolumeLimitter等がある。

MusicProgram

曲データは、Nusedriver lite独自のMusicProgramによって記述する。
MusicProgramは、ControlChange, PerformanceChange, Noteの3種に大別される。

ControlChange

音色の変更や曲の進行に関する変更を担う。
$00 Tempo
  1. bpm (1~255)
Beats per Minuteを指定する。
全channelでひとつの変数を共有している。
0だと曲が進行しない。

ex. BPMを150にしたい場合
    .db CcTempo,150
$01 GateTime
  1. note_gate_time lo
  2. note_gate_time hi
note_gate_timeを指定する。
Note前方から数えてnote_gate_time分、NoteのReleaseが早まる。
スタッカートのような使い方を想定。

ex. GateTimeを16分音符分にしたい場合
    .db CcGateTime
    .dw WHOLE_NOTE_LENGTH/16
$02 ReleaseTime
  1. note_release_time lo
  2. note_release_time hi
note_release_timeを指定する。
Note後方から数えてnote_release_time分、NoteのReleaseが早まる。

ex. ReleaseTimeを4分音符分にしたい場合
    .db CcReleaseTime
    .dw WHOLE_NOTE_LENGTH/4
$03 DataEntry
  1. address lo
  2. address hi
  3. value
addressの番地にvalueを書き込む。
channelは自動的に判別される。
pitch_detuneやchannel_volume_limitter等、1Byteの変数に対して使用する。

ex. channel_volume_limitterに8を入れたい場合
    .db CcDataEntry
    .dw channel_volume_limitter
    .db 8
$04 VolumeEnvelopeAttack
  1. volume_envelope_attack_address lo
  2. volume_envelope_attack_address hi
Attack用VolumeEnvelopeのLabel Addressを指定する。
Label以降の記述で、volume_envelope値として使用可能な範囲は0~15.

ex. Attack用VolumeEnvelopeを指定する場合
    .db CcVolumeEnvelopeAttack
    .dw .volume_attack

.volume_attack
    .db Literal+3,$07,$0A,$0D,Fill+127,$0F,JumpTo,-2
$05 VolumeEnvelopeRelease
  1. volume_envelope_release_address lo
  2. volume_envelope_release_address hi
Release用VolumeEnvelopeのLabel Addressを指定する。
Label以降の記述で、volume_envelope値として使用可能な範囲は0~15.

ex. Release用VolumeEnvelopeを指定する場合
    .db CcVolumeEnvelopeAttack
    .dw .volume_release

.volume_release
    .db Fill+127,$02,JumpTo,-2
$06 DutyEnvelopeAttack
  1. duty_envelope_attack_address lo
  2. duty_envelope_attack_address hi
Attack用DutyEnvelopeのLabel Addressを指定する。
Label以降の記述で、duty_envelope値として使用可能な範囲は0~3.

ex. Attack用DutyEnvelopeを指定する場合
    .db CcDutyEnvelopeAttack
    .dw .duty_attack

.duty_attack
    .db Fill+3,$01,Fill+127,$02,JumpTo,-2
$07 DutyEnvelopeRelease
  1. duty_envelope_release_address lo
  2. duty_envelope_release_address hi
Release用DutyEnvelopeのLabel Addressを指定する。
Label以降の記述で、duty_envelope値として使用可能な範囲は0~3.

ex. Release用DutyEnvelopeを指定する場合
    .db CcDutyEnvelopeRelease
    .dw .duty_release

.duty_release
    .db Fill+127,$03,JumpTo,-2
$08 PitchEnvelope
  1. pitch_envelope_address lo
  2. pitch_envelope_address hi
PitchEnvelopeのLabel Addressを指定する。
Label以降の記述で、pitch_envelope値として使用可能な範囲は-128~127.
正の値だと周波数が下がり、負の値だと周波数が上がることに注意。

ex. PitchEnvelopeを指定する場合
    .db CcPitchEnvelope
    .dw .pitch

.pitch
    .db Literal+1,-1,Fill+2,0,Literal+1,-1,Fill+2,0,Literal+1,1,Fill+2,0,Literal+1,1,Fill+2,0,JumpTo,-16
$09 PitchEnvelopeDelay
  1. pitch_envelope_delay_time lo
  2. pitch_envelope_delay_time hi
pitch_envelope_delay_timeを指定する。
NoteOn以降、pitch_envelope_delay_time分、PitchEnvelopeの開始を遅延できる。

ex. PitchEnvelopeの開始を付点4分音符分遅延させる場合
    .db CcPitchEnvelopeDelay
    .dw WHOLE_NOTE_LENGTH/2*3/4
$0A NoteEnvelopeAbsolute
  1. note_envelope_absolute_address lo
  2. note_envelope_absolute_address hi
絶対NoteEnvelopeのLabel Addressを指定する。
NoteTranspose, PitchEnvelope, PitchDetuneと併用可能。
NoteEnvelopeRelativeとは排他制御であり、NoteEnvelopeAbsolute読込み時にNoteEnvelopeRelative無効となる。
Label以降の記述で、note_envelope値として使用可能な範囲は33~127.
note_envelope値として0を指定すると、NoteOn時のNoteNumberで周波数設定される。

ex. 絶対NoteEnvelopeを指定する場合(Noteの先頭のみKick、その後にBass音を鳴らす)
    .db CcNoteEnvelopeAbsolute
    .dw note_absolute

.note_absolute
    .db Literal+8,72,64,56,52,48,44,40,36,Fill+127,0,JumpTo,-2
$0B NoteEnvelopeRelative
  1. note_envelope_relative_address lo
  2. note_envelope_relative_address hi
相対NoteEnvelopeのLabel Addressを指定する。
NoteTranspose, PitchEnvelope, PitchDetuneと併用可能。
NoteEnvelopeAbsoluteとは排他制御であり、NoteEnvelopeRelative読込み時にNoteEnvelopeAbsolute無効となる。
Label以降の記述で、note_envelope値として使用可能な範囲は-95~95.
note_envelope値は、NoteOn時のNoteNumberに対し相対指定する。

ex. 相対NoteEnvelopeを指定する場合(NoteOn時のNoteNumberをroot音としてmaj7を鳴らす)
    .db CcNoteEnvelopeRelative
    .dw note_relative

.note_relative
    .db Literal+6,0,4,7,11,7,4,JumpTo,-7
$0C JumpWithRepeat
  1. jump_with_repeat_address lo
  2. jump_with_repeat_address hi
  3. jump_repetition (1-255)
Jump先のLabel Addressと繰返し回数を指定する。
Jump先でReturnFromJumpが実行される毎にjump_repetitionが減算され、0になるとJump元に戻る。
無限ループにしたい場合はReturnFromJumpを実効しなければ良い。

ex. 同じフレーズを2回繰返す場合
    .db CcJumpWithRepeat
    .dw .riff
    .db 2

.riff
    .db %01101010,%01101010,%01101010,%01101010,%01101010,%01101010,%01100010,%01100010,CcReturnFromJump
$0D ReturnFromJump
    no operand
JumpWithRepeat参照
$0E JumpToMacro
  1. music_macro_table_number (0-127)
Jump先のmusic_macro_table_numberを指定する。
$0F ReturnFromMacro
    no operand
Jump元に戻る。

Envelope

Switched Run Length Encoding
Envelopeの記述方法としてSwitched Run Length Encodingを参考にして実装した。
(一般的なSwitched Run Length Encodingとは異なると思われる)
先頭の1Byteでmode(Literal(不連続) or Fill(連続))とlength(modeの対象となるByte数)を指定する。
modeは7bit目で識別される。
下記のように定義されており、ex.に示すように記述することで視認性が上がる。
Literal = 0
Fill = $80
JumpTo
JumpTo = $80で定義してあり、続く1ByteでJump先のアドレスを相対指定できる。(正の値も指定可能)
ただし、Jump先及びEncoded Data長は、EnvelopeのLabel Addressから255Byteまでの範囲におさめる必要がある。

ex. 0,1,2,5,5,5,5,0,1,2,5,5,5,0,1,2...
.encoded_data
    .db Literal+3,0,1,2,Fill+4,5,JumpTo,-6

PerformanceChange

演奏方法に関する変更を担う。
効果が永続的なPermanentと、次のNoteのみに適用となるTemporaryの2つに大別される。

$10 PermanentNoteLength0
    no operand
永続的にlength_table指定を変更出来る。
0番目(normal)のlength_tableが指定される。
$11 PermanentNoteLength1
    no operand
永続的にlength_table指定を変更出来る。
1番目(dotted(付点))のlength_tableが指定される。
$12 PermanentNoteLength2
    no operand
永続的にlength_table指定を変更出来る。
2番目(triplet(3連符))のlength_tableが指定される。
$13 PermanentNoteLength3
    no operand
永続的にlength_table指定を変更出来る。
3番目(user_defined)のlength_tableが指定される。
ex.
    .db 
$14 PermanentNoteRootAbsolute
  1. note_number
永続的にRoot音を変更出来る。
(絶対指定)
ex.
    .db 
$15 PermanentNoteRootRelative
  1. transpose_value
永続的にRoot音を変更出来る。
(以前のRoot音からの相対指定)
ex.
    .db 
$16 PermanentNoteScale
  1. note_scale_table_number (0-31)
永続的にnote_scale_tableを変更出来る。
ex.
    .db 
$17 PermanentNoteVelocity
  1. note_velocity_table_number (0-3)
永続的にnote_velocity_tableを変更出来る。
ex.
    .db 
$18 TemporaryNoteLength0
    no operand
このCommandの次に現れるNoteのみ一時的にlength_table指定を変更出来る。
0番目(normal)のlength_tableが指定される。
$19 TemporaryNoteLength1
    no operand
このCommandの次に現れるNoteのみ一時的にlength_table指定を変更出来る。
1番目(dotted(付点))のlength_tableが指定される。
$1A TemporaryNoteLength2
    no operand
このCommandの次に現れるNoteのみ一時的にlength_table指定を変更出来る。
2番目(triplet(3連符))のlength_tableが指定される。
$1B TemporaryNoteLength3
    no operand
このCommandの次に現れるNoteのみ一時的にlength_table指定を変更出来る。
3番目(user_defined)のlength_tableが指定される。
ex.
    .db 
$1C TemporaryNoteRootPlus1
    no operand
このCommandの次に現れるNoteのみ一時的にRoot音を変更出来る。
Plus1なので半音上がる。
ex.
    .db 
$1D TemporaryNoteRootPlus12
    no operand
このCommandの次に現れるNoteのみ一時的にRoot音を変更出来る。
Plus12なので1オクターブ上がる。
ex.
    .db 
$1E TemporaryNoteRootMinus1
    no operand
このCommandの次に現れるNoteのみ一時的にRoot音を変更出来る。
Minus1なので半音下がる。
ex.
    .db 
$1F TemporaryNoteRootMinus12
    no operand
このCommandの次に現れるNoteのみ一時的にRoot音を変更出来る。
Minus12なので1オクターブ下がる。
ex.
    .db 

Note

$20-$FF Note Info (%lllsssvv)