Implement a bridge to call Sointu from Go language.

The main interface is render_samples function, which renders several samples in one call,
to limit the number of calls from Go to C. This is compiled into a library, which is then
linked and called from bridge.go.
This commit is contained in:
Veikko Sariola
2020-10-21 20:07:45 +03:00
committed by Veikko Sariola
parent af14cd310b
commit 7aac3917b7
13 changed files with 555 additions and 8 deletions

View File

@ -0,0 +1,18 @@
set(LIB sointu)
set(SOURCES sointu.asm)
# Headers
include_directories(${PROJECT_SOURCE_DIR}/include)
# Library target
add_library(${LIB} ${SOURCES})
set_target_properties(${LIB} PROPERTIES LINKER_LANGUAGE C)
target_link_libraries(${LIB})
target_compile_definitions(${LIB} PUBLIC SU_USE_INTROSPECTION)
# Generate cgo wrapper
add_custom_command(TARGET ${LIB}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -P ${PROJECT_SOURCE_DIR}/BindConfig.txt ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include $<TARGET_FILE:sointu>
)

View File

@ -3,14 +3,91 @@
; Various compile time definitions exported
SECT_DATA(introscn)
%ifdef SU_USE_16BIT_OUTPUT
EXPORT MANGLE_DATA(su_use_16bit_output) dd 1
EXPORT MANGLE_DATA(su_use_16bit_output)
dd 1
%else
EXPORT MANGLE_DATA(su_use_16bit_output) dd 0
EXPORT MANGLE_DATA(su_use_16bit_output)
dd 0
%endif
%ifdef MAX_SAMPLES
EXPORT MANGLE_DATA(su_max_samples) dd MAX_SAMPLES
%ifndef SU_DISABLE_PLAYER
%ifdef MAX_SAMPLES
EXPORT MANGLE_DATA(su_max_samples)
dd MAX_SAMPLES
%endif
%endif
; Arithmetic opcode ids
EXPORT MANGLE_DATA(su_add_id)
dd ADD_ID
EXPORT MANGLE_DATA(su_addp_id)
dd ADDP_ID
EXPORT MANGLE_DATA(su_pop_id)
dd POP_ID
EXPORT MANGLE_DATA(su_loadnote_id)
dd LOADNOTE_ID
EXPORT MANGLE_DATA(su_mul_id)
dd MUL_ID
EXPORT MANGLE_DATA(su_mulp_id)
dd MULP_ID
EXPORT MANGLE_DATA(su_push_id)
dd PUSH_ID
EXPORT MANGLE_DATA(su_xch_id)
dd XCH_ID
; Effect opcode ids
EXPORT MANGLE_DATA(su_distort_id)
dd DISTORT_ID
EXPORT MANGLE_DATA(su_hold_id)
dd HOLD_ID
EXPORT MANGLE_DATA(su_crush_id)
dd CRUSH_ID
EXPORT MANGLE_DATA(su_gain_id)
dd GAIN_ID
EXPORT MANGLE_DATA(su_invgain_id)
dd INVGAIN_ID
EXPORT MANGLE_DATA(su_filter_id)
dd FILTER_ID
EXPORT MANGLE_DATA(su_clip_id)
dd CLIP_ID
EXPORT MANGLE_DATA(su_pan_id)
dd PAN_ID
EXPORT MANGLE_DATA(su_delay_id)
dd DELAY_ID
EXPORT MANGLE_DATA(su_compres_id)
dd COMPRES_ID
; Flowcontrol opcode ids
EXPORT MANGLE_DATA(su_advance_id)
dd SU_ADVANCE_ID
EXPORT MANGLE_DATA(su_speed_id)
dd SPEED_ID
; Sink opcode ids
EXPORT MANGLE_DATA(su_out_id)
dd OUT_ID
EXPORT MANGLE_DATA(su_outaux_id)
dd OUTAUX_ID
EXPORT MANGLE_DATA(su_aux_id)
dd AUX_ID
EXPORT MANGLE_DATA(su_send_id)
dd SEND_ID
; Source opcode ids
EXPORT MANGLE_DATA(su_envelope_id)
dd ENVELOPE_ID
EXPORT MANGLE_DATA(su_noise_id)
dd NOISE_ID
EXPORT MANGLE_DATA(su_oscillat_id)
dd OSCILLAT_ID
EXPORT MANGLE_DATA(su_loadval_id)
dd LOADVAL_ID
EXPORT MANGLE_DATA(su_receive_id)
dd RECEIVE_ID
EXPORT MANGLE_DATA(su_in_id)
dd IN_ID
%endif ; SU_USE_INTROSPECTION

121
src/sointu.asm Normal file
View File

@ -0,0 +1,121 @@
; source file for compiling sointu as a library
%define SU_DISABLE_PLAYER
%include "sointu_header.inc"
; TODO: make sure compile everything in
USE_ENVELOPE
USE_OSCILLAT
USE_MULP
USE_PAN
USE_OUT
%define INCLUDE_TRISAW
%define INCLUDE_SINE
%define INCLUDE_PULSE
%define INCLUDE_GATE
%define INCLUDE_STEREO_OSCILLAT
%define INCLUDE_STEREO_ENVELOPE
%define INCLUDE_STEREO_OUT
%define INCLUDE_POLYPHONY
%define INCLUDE_MULTIVOICE_TRACKS
%include "sointu_footer.inc"
section .text
struc su_synth_state
.synth resb su_synth.size
.delaywrks resb su_delayline_wrk.size * 64
.commands resb 32 * 64
.values resb 32 * 64 * 8
.polyphony resd 1
.numvoices resd 1
.randseed resd 1
.globaltime resd 1
.rowtick resd 1
.rowlen resd 1
endstruc
SECT_TEXT(sursampl)
EXPORT MANGLE_FUNC(su_render_samples,12)
%if BITS == 32 ; stdcall
pushad ; push registers
mov ecx, [esp + 4 + 32] ; ecx = &synthState
mov esi, [esp + 8 + 32] ; esi = bufsize
mov edx, [esp + 12 + 32] ; edx = &buffer
%else
%ifidn __OUTPUT_FORMAT__,win64 ; win64 ABI: rdx = bufsize, r8 = &buffer, rcx = &synthstate
push_registers rdi, rsi, rbx, rbp ; win64 ABI: these registers are non-volatile
mov rsi, rdx ; rsi = bufsize
mov rdx, r8 ; rdx = &buffer
%else ; System V ABI: rsi = bufsize, rdx = &buffer, rdi = &synthstate
push_registers rbx, rbp ; System V ABI: these registers are non-volatile
mov rcx, rdi ; rcx = &Synthstate
%endif
%endif
push _SI ; push bufsize
push _DX ; push bufptr
push _CX ; this takes place of the voicetrack
mov eax, [_CX + su_synth_state.randseed]
push _AX ; randseed
mov eax, [_CX + su_synth_state.globaltime]
push _AX ; global tick time
mov eax, [_CX + su_synth_state.rowlen]
push _AX ; push the rowlength to stack so we can easily compare to it, normally this would be row
mov eax, [_CX + su_synth_state.rowtick]
su_render_samples_loop:
mov _CX, [_SP + PTRSIZE*3]
push _AX ; push rowtick
mov eax, [_CX + su_synth_state.polyphony]
push _AX ;polyphony
mov eax, [_CX + su_synth_state.numvoices]
push _AX ;numvoices
lea _DX, [_CX+ su_synth_state.synth]
lea COM, [_CX+ su_synth_state.commands]
lea VAL, [_CX+ su_synth_state.values]
lea WRK, [_DX + su_synth.voices]
lea _CX, [_CX+ su_synth_state.delaywrks - su_delayline_wrk.filtstate]
call MANGLE_FUNC(su_run_vm,0)
pop _AX
pop _AX
mov _DI, [_SP + PTRSIZE*5] ; edi containts buffer ptr
mov _CX, [_SP + PTRSIZE*4]
lea _SI, [_CX + su_synth_state.synth + su_synth.left]
movsd ; copy left channel to output buffer
movsd ; copy right channel to output buffer
mov [_SP + PTRSIZE*5], _DI ; save back the updated ptr
lea _DI, [_SI-8]
xor eax, eax
stosd ; clear left channel so the VM is ready to write them again
stosd ; clear right channel so the VM is ready to write them again
pop _AX
inc dword [_SP + PTRSIZE] ; increment global time, used by delays
inc eax
dec dword [_SP + PTRSIZE*5]
jz su_render_samples_finish
cmp eax, [_SP] ; compare current tick to rowlength
jl su_render_samples_loop
su_render_samples_finish:
pop _CX
pop _BX
pop _DX
pop _CX
mov [_CX + su_synth_state.randseed], edx
mov [_CX + su_synth_state.globaltime], ebx
mov [_CX + su_synth_state.rowtick], eax
pop _AX
pop _AX ; todo: return correct value based on this
%if BITS == 32 ; stdcall
popad
ret 12
%else
%ifidn __OUTPUT_FORMAT__,win64
pop_registers rdi, rsi, rbx, rbp ; win64 ABI: these registers are non-volatile
%else
pop_registers rbx, rbp ; System V ABI: these registers are non-volatile
%endif
ret
%endif

View File

@ -274,6 +274,8 @@ EXPORT MANGLE_FUNC(su_power,0)
fstp st1 ; 2^x
ret
%ifndef SU_DISABLE_PLAYER
;-------------------------------------------------------------------------------
; output_sound macro: used by the render function to write sound to buffer
;-------------------------------------------------------------------------------
@ -482,6 +484,8 @@ su_update_voices_skipadd:
%endif ;INCLUDE_MULTIVOICE_TRACKS
%endif ; SU_DISABLE_PLAYER
;-------------------------------------------------------------------------------
; Include the rest of the code
;-------------------------------------------------------------------------------