Implement player speed modulation opcode for triplets and such.

This commit is contained in:
Veikko Sariola 2020-05-17 09:51:20 +03:00
parent 15717557f1
commit 71a5a18257
7 changed files with 93 additions and 4 deletions

View File

@ -56,8 +56,10 @@ New features since fork
- **Test-driven development**. Given that 4klang was already a mature project,
the first thing actually implemented was a set of regression tests to avoid
breaking everything beyond any hope of repair. Done, using CTest.
- **New units**. Bit-crusher, gain, inverse gain, clip. As always, if you
don't use them, they won't be compiled into the code.
- **New units**. Bit-crusher, gain, inverse gain, clip, modulate bpm
(proper triplets!)... As always, if you don't use them, they won't be
compiled into the code.
- **Pattern length does not have to be a power of 2**.
Future goals
------------
@ -66,8 +68,8 @@ Future goals
on CMake and compiles on Windows. Cross-platform NASM/YASM macros have been
drafted and remain to be tested. Once the project is more mature, I will
try compiling on other platforms.
- **Even more opcodes**. At least: compressor (with side-chaining), change
bpm. Maybe also equalizer.
- **Even more opcodes**. At least: compressor (with side-chaining). Maybe
also equalizer.
- **Support for 64-bit targets**.
- **Browser-based GUI and MIDI instrument**. Modern browsers support WebMIDI,
WebAudio and, most importantly, they are cross-platform and come installed

View File

@ -49,6 +49,33 @@ EXPORT MANGLE_FUNC(su_op_advance,0) ; Stack: addr voice wrkptr valptr comptr
%endif
;-------------------------------------------------------------------------------
; SPEED tick
;-------------------------------------------------------------------------------
%if SPEED_ID > -1
SECT_TEXT(suspeed)
EXPORT MANGLE_FUNC(su_op_speed,0)
fsub dword [c_0_5] ; s-.5
fadd st0, st0 ; 2*s-1
fmul dword [c_bpmscale] ; (2*s-1)*64/24, let's call this p from now on
call MANGLE_FUNC(su_power,0) ; 2^p, this is how many ticks we should be taking
fld1 ; 1 2^p
fsubp st1, st0 ; 2^p-1, the player is advancing 1 tick by its own
fadd dword [WRK+su_speed_wrk.remainder] ; t+2^p-1, t is the remainder from previous rounds as ticks have to be rounded to 1
push eax
fist dword [esp] ; Main stack: k=int(t+2^p-1)
fisub dword [esp] ; t+2^p-1-k, the remainder
pop eax
add dword [esp+24], eax ; add the whole ticks to song tick count, [esp+24] is the current tick in the row
fstp dword [WRK+su_speed_wrk.remainder] ; save the remainder for future
ret
SECT_DATA(suconst)
c_bpmscale dd 2.666666666666 ; 64/24, 24 values will be double speed, so you can go from ~ 1/2.5 speed to 2.5x speed
%endif
;-------------------------------------------------------------------------------
; Constants

View File

@ -0,0 +1,21 @@
;-------------------------------------------------------------------------------
; SPEED related defines
;-------------------------------------------------------------------------------
%assign SPEED_ID -1
%macro USE_SPEED 0
%if SPEED_ID == -1
%assign SPEED_ID CUR_ID
%assign CUR_ID CUR_ID + 2
%xdefine OPCODES OPCODES MANGLE_FUNC(su_op_speed,0),
%xdefine NUMPARAMS NUMPARAMS 0,
%endif
%endmacro
%macro SU_SPEED 0
USE_SPEED
%xdefine CMDS CMDS SPEED_ID, ; there is no stereo variant I can think of
%endmacro
struc su_speed_wrk
.remainder resd 1
endstruc

View File

@ -127,6 +127,7 @@
%define MONO 0
%define STEREO 1
%include "opcodes/flowcontrol.inc"
%include "opcodes/arithmetic.inc"
%include "opcodes/effects.inc"
%include "opcodes/sources.inc"

View File

@ -123,3 +123,4 @@ target_compile_definitions(test_envelope_16bit PUBLIC SU_USE_16BIT_OUTPUT)
regression_test(test_polyphony "ENVELOPE;VCO_SINE")
regression_test(test_chords "ENVELOPE;VCO_SINE")
regression_test(test_speed "ENVELOPE;VCO_SINE")

Binary file not shown.

37
tests/test_speed.asm Normal file
View File

@ -0,0 +1,37 @@
%define BPM 100
%define USE_SECTIONS
%include "../src/sointu.inc"
; warning: crashes ahead. Now that the bpm could be changed and even modulated by other
; signals, there is no easy way to figure out how many ticks your song is. Either
; allocate some extra memory of the output just in case or simulate exactly how many
; samples are outputted. Here the triplets are slightly faster than the original so
; they fit the default MAX_TICKS that is calculated using the simple bpm assumption.
SU_BEGIN_PATTERNS
PATTERN 64, 0, 64, 64, 64, 0, 64, 64, 64, 0, 64, 64, 65, 0, 65, 65,
PATTERN 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ; 4-rows
PATTERN 78, 0, 54, 0, 78, 0, 54, 0, 78, 0, 54, 0, 78, 0, 54, 0, ; triplets
SU_END_PATTERNS
SU_BEGIN_TRACKS
TRACK VOICES(1),0,0
TRACK VOICES(1),1,2
SU_END_TRACKS
SU_BEGIN_PATCH
SU_BEGIN_INSTRUMENT VOICES(1) ; Instrument0
SU_ENVELOPE MONO,ATTAC(64),DECAY(64),SUSTAIN(0),RELEASE(64),GAIN(128)
SU_ENVELOPE MONO,ATTAC(64),DECAY(64),SUSTAIN(0),RELEASE(64),GAIN(128)
SU_OSCILLAT MONO,TRANSPOSE(64),DETUNE(32),PHASE(0),COLOR(96),SHAPE(64),GAIN(128), FLAGS(TRISAW)
SU_OSCILLAT MONO,TRANSPOSE(72),DETUNE(64),PHASE(64),COLOR(64),SHAPE(96),GAIN(128), FLAGS(TRISAW)
SU_MULP STEREO
SU_OUT STEREO,GAIN(128)
SU_END_INSTRUMENT
SU_BEGIN_INSTRUMENT VOICES(1) ; Speed changer
SU_LOADNOTE MONO
SU_SPEED
SU_END_INSTRUMENT
SU_END_PATCH
%include "../src/sointu.asm"