LÖVE エンジンでのシンセサイズサンプル。

参考資料
https://pastebin.com/uu0hBkfW

これがなくなるのも辛いので、自分でもまとめておく。
ちなみにLuaです。

-- source
-- https://pastebin.com/uu0hBkfW

local SD -- SoundData, used as a short buffer
local QS -- Queueable Source
local phaseAccum
local samplerate
local frequency

local lfo_on=false
local note_on=false
 
 -- 準備
function love.load()
    phaseAccum = 0.0
    samplerate = 44100
    frequency = 490.0
    buf =512
    SD = love.sound.newSoundData(buf, samplerate, 16, 1) -- 2048 samplepoints, at a sampling rate of 44.1kHz, that's 46.44 milliseconds
    QS = love.audio.newQueueableSource(SD:getSampleRate(), SD:getBitDepth(), SD:getChannelCount()) -- one is enough to push data into it
    QS:play() -- start it up
end

local smp=0

-- 波形生成
function generate(buffer)

	-- 0-サンプルバッファの数値
    for i=0, buffer:getSampleCount()-1 do
    
    	-- 周波数修正
    	if lfo_on == true then
	        frequency = frequency + math.sin(phaseAccum/75) * 0.001
        end
        
        -- if you want to modify the frequency in realtime
        
        -- 位相の定義(書き込むステップサイズ)
        local phaseDelta = frequency / samplerate -- step size
        
        -- 最終的な波形の位置を定義
        if note_on == true then
	        phaseAccum = phaseAccum + phaseDelta

        	-- サイン波を生成する
        	-- make a sine wave
        	smp = math.sin(2.0 * math.pi * phaseAccum)
        	

        else
        	-- 無音を書き込む
        	smp=0
        end
        -- サンプルを配置する
        buffer:setSample(i, smp)
    end
end

function love.keypressed( key )
	if love.keyboard.isDown("space") then
	   note_on=true
	   print("key on")
	end
end

function love.keyreleased( key )
	if key == "space" then
		note_on= false
	   print("key off")
	   phaseAccum=0
	end
end
 
function love.update(dt)
    while QS:getFreeBufferCount() > 0 do -- timing
        generate(SD) -- make one buffer's worth of samplepoints
        QS:queue(SD) -- push buffer
    end
    QS:play() -- doesn't hurt to have, but kinda pointless
end