Implement sample-based oscillators, with sample import from gm.dls.

This commit is contained in:
Veikko Sariola
2020-05-19 18:29:47 +03:00
parent 77b989d88d
commit adc4a6e45f
13 changed files with 280 additions and 6 deletions

42
src/gmdls.asm Normal file
View File

@ -0,0 +1,42 @@
%ifdef INCLUDE_GMDLS
%define SAMPLE_TABLE_SIZE 3440660 ; size of gmdls
extern _OpenFile@12 ; requires windows
extern _ReadFile@20 ; requires windows
SECT_TEXT(sugmdls)
su_gmdls_load:
mov edi, MANGLE_DATA(su_sample_table)
mov esi, su_gmdls_path1
su_gmdls_pathloop:
push 0 ; OF_READ
push edi ; &ofstruct, blatantly reuse the sample table
push esi ; path
call _OpenFile@12 ; eax = OpenFile(path,&ofstruct,OF_READ)
add esi, su_gmdls_path2 - su_gmdls_path1 ; if we ever get to third, then crash
cmp eax, -1 ; eax == INVALID?
je su_gmdls_pathloop
push 0 ; NULL
push edi ; &bytes_read, reusing sample table again; it does not matter that the first four bytes are trashed
push SAMPLE_TABLE_SIZE ; number of bytes to read
push edi ; here we actually pass the sample table to readfile
push eax ; handle to file
call _ReadFile@20 ; Readfile(handle,&su_sample_table,SAMPLE_TABLE_SIZE,&bytes_read,NULL)
ret
SECT_DATA(sugmpath)
su_gmdls_path1:
db 'drivers/gm.dls',0
su_gmdls_path2:
db 'drivers/etc/gm.dls',0
SECT_DATA(suconst)
c_samplefreq_scaling dd 84.28074964676522 ; o = 0.000092696138, n = 72, f = 44100*o*2**(n/12), scaling = 22050/f <- so note 72 plays at the "normal rate"
SECT_BSS(susamtbl)
EXPORT MANGLE_DATA(su_sample_table) resb SAMPLE_TABLE_SIZE ; size of gmdls.
%endif

View File

@ -136,6 +136,13 @@ su_op_oscillat_normalized:
fadd dword [WRK+su_osc_wrk.phase]
fst dword [WRK+su_osc_wrk.phase]
fadd dword [edx+su_osc_ports.phaseofs]
%ifdef INCLUDE_SAMPLES
test al, byte SAMPLE
jz short su_op_oscillat_not_sample
call su_oscillat_sample
jmp su_op_oscillat_shaping ; skip the rest to avoid color phase normalization and colorloading
su_op_oscillat_not_sample:
%endif
fld1
fadd st1, st0
fxch
@ -168,6 +175,7 @@ su_op_oscillat_not_pulse:
jmp su_op_oscillat_gain ; skip waveshaping as the shape parameter is reused for gateshigh
su_op_oscillat_not_gate:
%endif
su_op_oscillat_shaping:
; finally, shape the oscillator and apply gain
fld dword [edx+su_osc_ports.shape]
call su_waveshaper
@ -285,6 +293,42 @@ SECT_DATA(suconst)
%endif
; SAMPLES
%ifdef INCLUDE_SAMPLES
SECT_TEXT(suoscsam)
su_oscillat_sample: ; p
pushad ; edx must be saved, eax & ecx if this is stereo osc
push edx
mov al, byte [VAL-4] ; reuse "color" as the sample number
lea edi, [MANGLE_DATA(su_sample_offsets) + eax*8] ; edi points now to the sample table entry
fmul dword [c_samplefreq_scaling] ; p*r
fistp dword [esp]
pop edx ; edx is now the sample number
movzx ebx, word [edi + su_sample_offset.loopstart] ; ecx = loopstart
sub edx, ebx ; if sample number < loop start
jl su_oscillat_sample_not_looping ; then we're not looping yet
mov eax, edx ; eax = sample number
movzx ecx, word [edi + su_sample_offset.looplength] ; edi is now the loop length
xor edx, edx ; div wants edx to be empty
div ecx ; edx is now the remainder
su_oscillat_sample_not_looping:
add edx, ebx ; sampleno += loopstart
add edx, dword [edi + su_sample_offset.start]
fild word [MANGLE_DATA(su_sample_table) + edx*2]
fdiv dword [c_32767]
popad
ret
SECT_DATA(suconst)
%ifndef C_32767
c_32767 dd 32767.0
%define C_32767
%endif
%endif
;-------------------------------------------------------------------------------
; LOADVAL opcode
;-------------------------------------------------------------------------------

View File

@ -64,6 +64,7 @@ endstruc
%endif
%endmacro
%define SAMPLE 0x80 ; in this case, all the rest of the bits is the sample index
%define SINE 0x40
%define TRISAW 0x20
%define PULSE 0x10
@ -95,6 +96,9 @@ endstruc
%if (%8) & GATE == GATE
%define INCLUDE_GATE
%endif
%if (%8) & SAMPLE == SAMPLE
%define INCLUDE_SAMPLES
%endif
%endmacro
struc su_osc_ports
@ -119,9 +123,39 @@ endstruc
%define GATESLOW(val) val
%define GATESHIGH(val) val
%define COLOR(val) val
%define SAMPLENO(val) val
%define SHAPE(val) val
%define FLAGS(val) val
;-------------------------------------------------------------------------------
; Sample related defines
;-------------------------------------------------------------------------------
%macro SU_BEGIN_SAMPLE_OFFSETS 0
SECT_DATA(susamoff)
EXPORT MANGLE_DATA(su_sample_offsets)
%endmacro
%macro SAMPLE_OFFSET 3
dd %1
dw %2
dw %3
%endmacro
%define START(val) val
%define LOOPSTART(val) val
%define LOOPLENGTH(val) val
%define SU_END_SAMPLE_OFFSETS
struc su_sample_offset ; length conveniently 8, so easy to index
.start resd 1
.loopstart resw 1
.looplength resw 1
.size
endstruc
;-------------------------------------------------------------------------------
; NOISE structs
;-------------------------------------------------------------------------------

View File

@ -19,7 +19,10 @@ su_voicetrack_bitmask dd VOICETRACK_BITMASK; does the following voice bel
SECT_DATA(suconst)
%ifdef SU_USE_16BIT_OUTPUT
c_32767 dd 32767.0
%ifndef C_32767
c_32767 dd 32767.0
%define C_32767
%endif
%endif
;-------------------------------------------------------------------------------
@ -86,6 +89,9 @@ SECT_TEXT(surender)
EXPORT MANGLE_FUNC(su_render,4) ; Stack: ptr
pushad ; Stack: pushad ptr
%ifdef INCLUDE_GMDLS
call su_gmdls_load
%endif
xor eax, eax ; ecx is the current row
su_render_rowloop: ; loop through every row in the song
push eax ; Stack: row pushad ptr

View File

@ -191,3 +191,4 @@ EXPORT MANGLE_FUNC(su_power,0)
%include "opcodes/effects.asm"
%include "player.asm"
%include "introspection.asm"
%include "gmdls.asm"