mirror of
https://github.com/vsariola/sointu.git
synced 2025-11-18 16:49:06 -05:00
drafting
This commit is contained in:
parent
fa7901c7c6
commit
f92ecb2e99
@ -22,8 +22,8 @@ type NativeSynth struct {
|
||||
cpuLoad sointu.CPULoad
|
||||
}
|
||||
|
||||
func (s NativeSynther) Name() string { return "Native" }
|
||||
func (s NativeSynther) SupportsParallelism() bool { return false }
|
||||
func (s NativeSynther) Name() string { return "Native" }
|
||||
func (s NativeSynther) SupportsMultithreading() bool { return false }
|
||||
|
||||
func (s NativeSynther) Synth(patch sointu.Patch, bpm int) (sointu.Synth, error) {
|
||||
synth, err := Synth(patch, bpm)
|
||||
@ -74,12 +74,12 @@ func Synth(patch sointu.Patch, bpm int) (*NativeSynth, error) {
|
||||
|
||||
func (s *NativeSynth) Close() {}
|
||||
|
||||
func (s *NativeSynth) NumCores() int { return 1 }
|
||||
func (s *NativeSynth) CPULoad(loads []sointu.CPULoad) {
|
||||
func (s *NativeSynth) CPULoad(loads []sointu.CPULoad) int {
|
||||
if len(loads) < 1 {
|
||||
return
|
||||
return 0
|
||||
}
|
||||
loads[0] = s.cpuLoad
|
||||
return 1
|
||||
}
|
||||
|
||||
// Render renders until the buffer is full or the modulated time is reached, whichever
|
||||
|
||||
@ -95,8 +95,8 @@ success:
|
||||
f.Read(su_sample_table[:])
|
||||
}
|
||||
|
||||
func (s GoSynther) Name() string { return "Go" }
|
||||
func (s GoSynther) SupportsParallelism() bool { return false }
|
||||
func (s GoSynther) Name() string { return "Go" }
|
||||
func (s GoSynther) SupportsMultithreading() bool { return false }
|
||||
|
||||
func (s GoSynther) Synth(patch sointu.Patch, bpm int) (sointu.Synth, error) {
|
||||
bytecode, err := NewBytecode(patch, AllFeatures{}, bpm)
|
||||
@ -120,12 +120,12 @@ func (s *GoSynth) Release(voiceIndex int) {
|
||||
|
||||
func (s *GoSynth) Close() {}
|
||||
|
||||
func (s *GoSynth) NumCores() int { return 1 }
|
||||
func (s *GoSynth) CPULoad(loads []sointu.CPULoad) {
|
||||
func (s *GoSynth) CPULoad(loads []sointu.CPULoad) int {
|
||||
if len(loads) < 1 {
|
||||
return
|
||||
return 0
|
||||
}
|
||||
loads[0] = s.cpuLoad
|
||||
return 1
|
||||
}
|
||||
|
||||
func (s *GoSynth) Update(patch sointu.Patch, bpm int) error {
|
||||
|
||||
@ -10,29 +10,29 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
ParallelSynth struct {
|
||||
MultithreadSynth struct {
|
||||
voiceMapping voiceMapping
|
||||
synths []sointu.Synth
|
||||
commands chan<- parallelSynthCommand // maxtime
|
||||
results <-chan parallelSynthResult // rendered buffer
|
||||
commands chan<- multithreadSynthCommand // maxtime
|
||||
results <-chan multithreadSynthResult // rendered buffer
|
||||
pool sync.Pool
|
||||
synther sointu.Synther
|
||||
}
|
||||
|
||||
ParallelSynther struct {
|
||||
MultithreadSynther struct {
|
||||
synther sointu.Synther
|
||||
name string
|
||||
}
|
||||
|
||||
voiceMapping [MAX_CORES][MAX_VOICES]int
|
||||
voiceMapping [MAX_THREADS][MAX_VOICES]int
|
||||
|
||||
parallelSynthCommand struct {
|
||||
multithreadSynthCommand struct {
|
||||
core int
|
||||
samples int
|
||||
time int
|
||||
}
|
||||
|
||||
parallelSynthResult struct {
|
||||
multithreadSynthResult struct {
|
||||
buffer *sointu.AudioBuffer
|
||||
samples int
|
||||
time int
|
||||
@ -40,16 +40,16 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
const MAX_CORES = 4
|
||||
const MAX_THREADS = 4
|
||||
|
||||
func MakeParallelSynther(synther sointu.Synther) ParallelSynther {
|
||||
return ParallelSynther{synther: synther, name: "Parallel " + synther.Name()}
|
||||
func MakeMultithreadSynther(synther sointu.Synther) MultithreadSynther {
|
||||
return MultithreadSynther{synther: synther, name: "Multithread " + synther.Name()}
|
||||
}
|
||||
|
||||
func (s ParallelSynther) Name() string { return s.name }
|
||||
func (s ParallelSynther) SupportsParallelism() bool { return true }
|
||||
func (s MultithreadSynther) Name() string { return s.name }
|
||||
func (s MultithreadSynther) SupportsMultithreading() bool { return true }
|
||||
|
||||
func (s ParallelSynther) Synth(patch sointu.Patch, bpm int) (sointu.Synth, error) {
|
||||
func (s MultithreadSynther) Synth(patch sointu.Patch, bpm int) (sointu.Synth, error) {
|
||||
patches, voiceMapping := splitPatchByCores(patch)
|
||||
synths := make([]sointu.Synth, 0, len(patches))
|
||||
for _, p := range patches {
|
||||
@ -59,7 +59,7 @@ func (s ParallelSynther) Synth(patch sointu.Patch, bpm int) (sointu.Synth, error
|
||||
}
|
||||
synths = append(synths, synth)
|
||||
}
|
||||
ret := &ParallelSynth{
|
||||
ret := &MultithreadSynth{
|
||||
synths: synths,
|
||||
voiceMapping: voiceMapping,
|
||||
pool: sync.Pool{New: func() any { ret := make(sointu.AudioBuffer, 0, 8096); return &ret }},
|
||||
@ -69,7 +69,7 @@ func (s ParallelSynther) Synth(patch sointu.Patch, bpm int) (sointu.Synth, error
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (s *ParallelSynth) Update(patch sointu.Patch, bpm int) error {
|
||||
func (s *MultithreadSynth) Update(patch sointu.Patch, bpm int) error {
|
||||
patches, voiceMapping := splitPatchByCores(patch)
|
||||
if s.voiceMapping != voiceMapping {
|
||||
s.voiceMapping = voiceMapping
|
||||
@ -93,37 +93,37 @@ func (s *ParallelSynth) Update(patch sointu.Patch, bpm int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ParallelSynth) startProcesses() {
|
||||
func (s *MultithreadSynth) startProcesses() {
|
||||
maxProcs := runtime.GOMAXPROCS(0)
|
||||
cmdChan := make(chan parallelSynthCommand, maxProcs)
|
||||
cmdChan := make(chan multithreadSynthCommand, maxProcs)
|
||||
s.commands = cmdChan
|
||||
resultsChan := make(chan parallelSynthResult, maxProcs)
|
||||
resultsChan := make(chan multithreadSynthResult, maxProcs)
|
||||
s.results = resultsChan
|
||||
for i := 0; i < maxProcs; i++ {
|
||||
go func(commandCh <-chan parallelSynthCommand, resultCh chan<- parallelSynthResult) {
|
||||
go func(commandCh <-chan multithreadSynthCommand, resultCh chan<- multithreadSynthResult) {
|
||||
for cmd := range commandCh {
|
||||
buffer := s.pool.Get().(*sointu.AudioBuffer)
|
||||
*buffer = append(*buffer, make(sointu.AudioBuffer, cmd.samples)...)
|
||||
samples, time, renderError := s.synths[cmd.core].Render(*buffer, cmd.time)
|
||||
resultCh <- parallelSynthResult{buffer: buffer, samples: samples, time: time, renderError: renderError}
|
||||
resultCh <- multithreadSynthResult{buffer: buffer, samples: samples, time: time, renderError: renderError}
|
||||
}
|
||||
}(cmdChan, resultsChan)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ParallelSynth) Close() {
|
||||
func (s *MultithreadSynth) Close() {
|
||||
close(s.commands)
|
||||
s.closeSynths()
|
||||
}
|
||||
|
||||
func (s *ParallelSynth) closeSynths() {
|
||||
func (s *MultithreadSynth) closeSynths() {
|
||||
for _, synth := range s.synths {
|
||||
synth.Close()
|
||||
}
|
||||
s.synths = s.synths[:0]
|
||||
}
|
||||
|
||||
func (s *ParallelSynth) Trigger(voiceIndex int, note byte) {
|
||||
func (s *MultithreadSynth) Trigger(voiceIndex int, note byte) {
|
||||
for core, synth := range s.synths {
|
||||
if ind := s.voiceMapping[core][voiceIndex]; ind >= 0 {
|
||||
synth.Trigger(ind, note)
|
||||
@ -131,7 +131,7 @@ func (s *ParallelSynth) Trigger(voiceIndex int, note byte) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ParallelSynth) Release(voiceIndex int) {
|
||||
func (s *MultithreadSynth) Release(voiceIndex int) {
|
||||
for core, synth := range s.synths {
|
||||
if ind := s.voiceMapping[core][voiceIndex]; ind >= 0 {
|
||||
synth.Release(ind)
|
||||
@ -139,27 +139,22 @@ func (s *ParallelSynth) Release(voiceIndex int) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ParallelSynth) NumCores() (coreCount int) {
|
||||
for i := range s.synths {
|
||||
coreCount += s.synths[i].NumCores()
|
||||
func (s *MultithreadSynth) CPULoad(loads []sointu.CPULoad) (elems int) {
|
||||
for _, synth := range s.synths {
|
||||
n := synth.CPULoad(loads)
|
||||
elems += n
|
||||
loads = loads[n:]
|
||||
if len(loads) <= 0 {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *ParallelSynth) CPULoad(loads []sointu.CPULoad) {
|
||||
for _, synth := range s.synths {
|
||||
synth.CPULoad(loads)
|
||||
if len(loads) <= synth.NumCores() {
|
||||
return
|
||||
}
|
||||
loads = loads[synth.NumCores():]
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ParallelSynth) Render(buffer sointu.AudioBuffer, maxtime int) (samples int, time int, renderError error) {
|
||||
func (s *MultithreadSynth) Render(buffer sointu.AudioBuffer, maxtime int) (samples int, time int, renderError error) {
|
||||
count := len(s.synths)
|
||||
for i := 0; i < count; i++ {
|
||||
s.commands <- parallelSynthCommand{core: i, samples: len(buffer), time: maxtime}
|
||||
s.commands <- multithreadSynthCommand{core: i, samples: len(buffer), time: maxtime}
|
||||
}
|
||||
clear(buffer)
|
||||
samples = math.MaxInt
|
||||
@ -187,15 +182,15 @@ func (s *ParallelSynth) Render(buffer sointu.AudioBuffer, maxtime int) (samples
|
||||
func splitPatchByCores(patch sointu.Patch) ([]sointu.Patch, voiceMapping) {
|
||||
cores := 1
|
||||
for _, instr := range patch {
|
||||
cores = max(bits.Len((uint)(instr.CoreMaskM1+1)), cores)
|
||||
cores = max(bits.Len((uint)(instr.ThreadMaskM1+1)), cores)
|
||||
}
|
||||
cores = min(cores, MAX_CORES)
|
||||
cores = min(cores, MAX_THREADS)
|
||||
ret := make([]sointu.Patch, cores)
|
||||
for c := 0; c < cores; c++ {
|
||||
ret[c] = make(sointu.Patch, 0, len(patch))
|
||||
}
|
||||
var voicemapping [MAX_CORES][MAX_VOICES]int
|
||||
for c := 0; c < MAX_CORES; c++ {
|
||||
var voicemapping [MAX_THREADS][MAX_VOICES]int
|
||||
for c := 0; c < MAX_THREADS; c++ {
|
||||
for j := 0; j < MAX_VOICES; j++ {
|
||||
voicemapping[c][j] = -1
|
||||
}
|
||||
@ -204,7 +199,7 @@ func splitPatchByCores(patch sointu.Patch) ([]sointu.Patch, voiceMapping) {
|
||||
coreVoice := 0
|
||||
curVoice := 0
|
||||
for _, instr := range patch {
|
||||
mask := instr.CoreMaskM1 + 1
|
||||
mask := instr.ThreadMaskM1 + 1
|
||||
if mask&(1<<c) != 0 {
|
||||
ret[c] = append(ret[c], instr)
|
||||
for j := 0; j < instr.NumVoices; j++ {
|
||||
Reference in New Issue
Block a user