 | Code: All effects marked with * completed 1oo% ! All marked with a ! instead need a change later, and all marked with a ? aren't tested yet but should work. But you never know: Bug rulez ! :-)))))
Volume formula (I use 64-bit multiply and divide for them) ---------------------------------------------------------- For 8-bit, use: Vol * TVol * RVol * VEnv * Fde * GVol OutVol = ------------------------------------- 255 * 255 * 255 * 255 * 65535 * 255
SUB VOLUMES ARE USED ONLY BY SLIDES ! DO NOT USE IT IN FINAL CALCULATION !
OutVol = Output volume to mixing device (0 - 255) Vol = Volume, TVol = Track volume, RVol = Random volume (look below) VEnv = Volume envelope volume, Fde = Fadeout count (set to 65535 on new note), IVol = Instrument volume, SVol = Sample volume, VSw = Volume swing GVol = Global volume
Random volume variation formula (looks little complicated but can be easily implemented on an assembler): RVol = ((IVol * SVol) - (IVol * SVol * VSw / 256)) + Rnd(((IVol * SVol * VSw / 256) * 2) + 1)
Clip values < 0 to 0 and values greater than 255*255 to 255*255 (this assumes that e.g. Rnd(10) returns a random value from 0 - 9)
The following QUITE VERY SIMPLE routine is used for the final volume calculation by the player in the tucomposer.library (for Asm-coders) D7 points to current host channel, A2 points to virtual channel structure, A3 points to host channel structure and A6 to the tucomposer.library base Code (c) by Basty/TuC in 1997: moveq #0,d0 ; Clear for MULU move.b pc_Volume(a2),d0 ; Vol (Note volume) tst.b pc_Flags(a2) ; Running backgrnd channel ? bmi.s RunBackChan ; No -> Jump cmp.w phc_VirtualChannel(a3),d7 ; Virtual channel - Host ch ? bne.s RunBackChan ; No -> Jump btst #PHCB_TremorExec-8,phc_Flags+2(a3) ; Tremor running ? beq.s RunBackChan ; No -> Jump btst #PHCB_TremorOff-8,phc_Flags+2(a3) ; Tremor off currently ? beq.s RunBackChan ; No -> Jump moveq #0,d0 ; Set volume to zero RunBackChan: moveq #0,d2 ; Clear D2 for MULU move.b phc_TrackVolume(a3),d2 ; TVol (Track volume) mulu.w d2,d0 ; Multiple mulu.w pc_InstrVolume(a2),d0 ; * RVol (look code below) move.w pc_VolEnvelopeVolume(a2),d2 ; Volume envelope volume lsr.w #8,d2 ; scale down to 0-255 moveq #0,d1 ; Clear D1 for MULU move.b pc_GlobalVolume(a2),d1 ; * GVol (Global volume) mulu.w d1,d2 ; Multiple them mulu.w pc_FadeOutCount(a2),d2 ; * Fde (Fadeout count) mulu.l d2,d1:d0 ; Final multiply (64 bit) divu.l #255*255*255*255,d1:d0 ; Divide to scale to 255 divu.l #65535*255,d0 ; 2 steps needed (no 64/64)... move.b d0,pc_FinalVolume(a2) ; Store OutVol move.b d0,ms_Volume(a2) ; Output volume for mixer ... ; Other code (panning & co.)
Here the routine I use for calculating the random volume variation: moveq #0,d0 ; Clear D0 for MULU move.b tcs_GlobalVolume(a1),d0 ; SVol (Global sample volume) moveq #0,d4 ; Same for D4 move.b tci_GlobalVolume(a0),d4 ; IVol (Global instr volume) mulu.w d0,d4 ; SVol * IVol move.l d4,d2 ; Store for later use mulu.w tci_VolumeSwing(a0),d4 ; * VSw (Volume swing) lsr.l #8,d4 ; / 256 move.l d4,d5 ; Store again for Rnd add.l d5,d5 ; * 2 addq.l #1,d5 ; + 1 move.l tcb_RandomSeed(a6),d0 ; Randomize seed move.l d0,d1 ; Store swap d0 ; Swap words for OR clr.w d0 ; Clear to remove trash or.l d0,d1 ; OR them for new value muls.l #-1153374675,d1 ; Multiply (68020+ !!!) addq.l #1,d1 ; Add one for case of 0 move.l d1,tcb_RandomSeed(a6) ; Store new seed mulu.l d5,d0:d1 ; Scale seed for rnd value sub.l d4,d2 ; Subtract VSwing scale add.l d2,d0 ; Add to volume bpl.s VolSwingLowValOk ; Is positive ? moveq #0,d0 ; No -> set to zero VolSwingLowValOk: move.l #255*255,d1 ; May not exceed 255*255 cmp.l d1,d0 ; Compare random result bls.s VolSwingHiValOk ; Less or same ? move.l d1,d0 ; No -> set to 255*255 VolSwingHiValOk: move.w d0,pc_InstrVolume(a2) ; Store RVol ... ; Other routines (I don't ; print the whole play routine ; here :-)))
You see, actually quite a simple process. Similar routine is used for pitch swing, except that it's limited to 1 to 2^32-1 and is a little bit faster due to / 65536 which can be written with SWAP which is faster as LSR...
Panning formula --------------- Set any panning values of 255 to 256 (i.e. Pan = Pan * 256 / 255) !
FinalPan = (PEnv - 128) * (128 - Abs(Pan - 128)) / 128 If Stereo Then If Surround Or Track Surround Or Global Surround Then OutPan = Surround (or 128 when not supported) Else ChPan = (((128 - FinalPan) * (TPan - 128)) / 128) + 128 OutPan = (((128 - ChPan) * (GPan - 128)) / 128) + 128 If OutPan = 256 Then OutPan = 255 (I used this one due to byte-pan var) End If Else OutPan = 128 (central pan) End If
Note that 128 = 2^7 so that arithmetic (ASL, ASR) bit shifting can be done...
SUB PANNING IS ONLY USED BY SLIDES ! DO NOT USE IT IN FINAL CALCULATION !
OutPan = Output panning to mixing device (0 - 255) Pan = Panning or Track panning, TPan = Track panning, GPan = Global panning ChPan = Channel panning, FinalPan = Final panning (pan with envelope)
Frequency formula ----------------- Frequency = (8363*1712*4) / Period ST3Period = Period / 4 (also for FT2 & IT) AmigaPeriod = ST3Period / 4 (MOD, MED, etc.)
Linear frequence formula: NewFrequency = OldFrequency*2^(FineSlide/3072) DownFineSlide = -FineSlide NormalSlide = FineSlide * 16
NTSC Note frequencies (in Hz), used by FT2, ST3 and IT: C-4 C#4 D-4 D#4 E-4 F-4 F#4 G-4 G#4 A-4 A#4 B-4 8363 8860 9395 9943 10559 11186 11852 12559 13306 14092 14914 15786
Final note formula: Frequency = (NoteFreq[Note] * 2^Octave) / 2^4 (base is C-4)
|  |