sfxr.lua 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229
  1. -- sfxr.lua
  2. -- original by Tomas Pettersson, ported to Lua by nucular
  3. --[[
  4. Permission is hereby granted, free of charge, to any person obtaining a copy
  5. of this software and associated documentation files (the "Software"), to deal
  6. in the Software without restriction, including without limitation the rights
  7. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. copies of the Software, and to permit persons to whom the Software is
  9. furnished to do so, subject to the following conditions:
  10. The above copyright notice and this permission notice shall be included in all
  11. copies or substantial portions of the Software.
  12. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  18. SOFTWARE.
  19. ]]--
  20. local sfxr = {}
  21. local bit = bit32 or require("bit")
  22. -- Constants
  23. sfxr.VERSION = "0.0.1"
  24. sfxr.SQUARE = 0
  25. sfxr.SAWTOOTH = 1
  26. sfxr.SINE = 2
  27. sfxr.NOISE = 3
  28. sfxr.FREQ_44100 = 44100
  29. sfxr.FREQ_22050 = 22050
  30. sfxr.BITS_FLOAT = 0
  31. sfxr.BITS_16 = 16
  32. sfxr.BITS_8 = 8
  33. -- Utilities
  34. -- Simulates a C int cast
  35. local function trunc(n)
  36. if n >= 0 then
  37. return math.floor(n)
  38. else
  39. return -math.floor(-n)
  40. end
  41. end
  42. -- Sets the random seed and initializes the generator
  43. local function setseed(seed)
  44. math.randomseed(seed)
  45. for i=0, 5 do
  46. math.random()
  47. end
  48. end
  49. -- Returns a random number between low and high
  50. local function random(low, high)
  51. return low + math.random() * (high - low)
  52. end
  53. -- Returns a random boolean weighted to false by n
  54. local function maybe(n)
  55. return trunc(random(0, n or 1)) == 0
  56. end
  57. -- Clamps n between min and max
  58. local function clamp(n, min, max)
  59. return math.max(min or -math.huge, math.min(max or math.huge, n))
  60. end
  61. -- Copies a table (shallow) or a primitive
  62. local function shallowcopy(t)
  63. if type(t) == "table" then
  64. local t2 = {}
  65. for k,v in pairs(t) do
  66. t2[k] = v
  67. end
  68. return t2
  69. else
  70. return t
  71. end
  72. end
  73. -- Merges table t2 into t1
  74. local function mergetables(t1, t2)
  75. for k, v in pairs(t2) do
  76. if type(v) == "table" then
  77. if type(t1[k] or false) == "table" then
  78. mergetables(t1[k] or {}, t2[k] or {})
  79. else
  80. t1[k] = v
  81. end
  82. else
  83. t1[k] = v
  84. end
  85. end
  86. return t1
  87. end
  88. -- Packs a number into a IEEE754 32-bit big-endian floating point binary string
  89. -- source: https://stackoverflow.com/questions/14416734/
  90. local function packIEEE754(number)
  91. if number == 0 then
  92. return string.char(0x00, 0x00, 0x00, 0x00)
  93. elseif number ~= number then
  94. return string.char(0xFF, 0xFF, 0xFF, 0xFF)
  95. else
  96. local sign = 0x00
  97. if number < 0 then
  98. sign = 0x80
  99. number = -number
  100. end
  101. local mantissa, exponent = math.frexp(number)
  102. exponent = exponent + 0x7F
  103. if exponent <= 0 then
  104. mantissa = math.ldexp(mantissa, exponent - 1)
  105. exponent = 0
  106. elseif exponent > 0 then
  107. if exponent >= 0xFF then
  108. return string.char(sign + 0x7F, 0x80, 0x00, 0x00)
  109. elseif exponent == 1 then
  110. exponent = 0
  111. else
  112. mantissa = mantissa * 2 - 1
  113. exponent = exponent - 1
  114. end
  115. end
  116. mantissa = math.floor(math.ldexp(mantissa, 23) + 0.5)
  117. return string.char(
  118. sign + math.floor(exponent / 2),
  119. (exponent % 2) * 0x80 + math.floor(mantissa / 0x10000),
  120. math.floor(mantissa / 0x100) % 0x100,
  121. mantissa % 0x100)
  122. end
  123. end
  124. -- Unpacks a IEEE754 32-bit big-endian floating point string to a number
  125. local function unpackIEEE754(packed)
  126. local b1, b2, b3, b4 = string.byte(packed, 1, 4)
  127. local exponent = (b1 % 0x80) * 0x02 + math.floor(b2 / 0x80)
  128. local mantissa = math.ldexp(((b2 % 0x80) * 0x100 + b3) * 0x100 + b4, -23)
  129. if exponent == 0xFF then
  130. if mantissa > 0 then
  131. return 0 / 0
  132. else
  133. mantissa = math.huge
  134. exponent = 0x7F
  135. end
  136. elseif exponent > 0 then
  137. mantissa = mantissa + 1
  138. else
  139. exponent = exponent + 1
  140. end
  141. if b1 >= 0x80 then
  142. mantissa = -mantissa
  143. end
  144. return math.ldexp(mantissa, exponent - 0x7F)
  145. end
  146. -- Constructor
  147. function sfxr.newSound(...)
  148. local instance = setmetatable({}, sfxr.Sound)
  149. instance:__init(...)
  150. return instance
  151. end
  152. -- The main Sound class
  153. sfxr.Sound = {}
  154. sfxr.Sound.__index = sfxr.Sound
  155. function sfxr.Sound:__init()
  156. -- Build tables to store the parameters in
  157. self.volume = {}
  158. self.envelope = {}
  159. self.frequency = {}
  160. self.vibrato = {}
  161. self.change = {}
  162. self.duty = {}
  163. self.phaser = {}
  164. self.lowpass = {}
  165. self.highpass = {}
  166. -- These won't be affected by Sound.resetParameters()
  167. self.supersamples = 8
  168. self.volume.master = 0.5
  169. self.volume.sound = 0.5
  170. self:resetParameters()
  171. end
  172. function sfxr.Sound:resetParameters()
  173. -- Set all parameters to the default values
  174. self.repeatspeed = 0.0
  175. self.wavetype = sfxr.SQUARE
  176. self.envelope.attack = 0.0
  177. self.envelope.sustain = 0.3
  178. self.envelope.punch = 0.0
  179. self.envelope.decay = 0.4
  180. self.frequency.start = 0.3
  181. self.frequency.min = 0.0
  182. self.frequency.slide = 0.0
  183. self.frequency.dslide = 0.0
  184. self.vibrato.depth = 0.0
  185. self.vibrato.speed = 0.0
  186. self.vibrato.delay = 0.0
  187. self.change.amount = 0.0
  188. self.change.speed = 0.0
  189. self.duty.ratio = 0.0
  190. self.duty.sweep = 0.0
  191. self.phaser.offset = 0.0
  192. self.phaser.sweep = 0.0
  193. self.lowpass.cutoff = 1.0
  194. self.lowpass.sweep = 0.0
  195. self.lowpass.resonance = 0.0
  196. self.highpass.cutoff = 0.0
  197. self.highpass.sweep = 0.0
  198. end
  199. function sfxr.Sound:sanitizeParameters()
  200. self.repeatspeed = clamp(self.repeatspeed, 0, 1)
  201. self.wavetype = clamp(self.wavetype, sfxr.SQUARE, sfxr.NOISE)
  202. self.envelope.attack = clamp(self.envelope.attack, 0, 1)
  203. self.envelope.sustain = clamp(self.envelope.sustain, 0, 1)
  204. self.envelope.punch = clamp(self.envelope.punch, 0, 1)
  205. self.envelope.decay = clamp(self.envelope.decay, 0, 1)
  206. self.frequency.start = clamp(self.frequency.start, 0, 1)
  207. self.frequency.min = clamp(self.frequency.min, 0, 1)
  208. self.frequency.slide = clamp(self.frequency.slide, -1, 1)
  209. self.frequency.dslide = clamp(self.frequency.dslide, -1, 1)
  210. self.vibrato.depth = clamp(self.vibrato.depth, 0, 1)
  211. self.vibrato.speed = clamp(self.vibrato.speed, 0, 1)
  212. self.vibrato.delay = clamp(self.vibrato.delay, 0, 1)
  213. self.change.amount = clamp(self.change.amount, -1, 1)
  214. self.change.speed = clamp(self.change.speed, 0, 1)
  215. self.duty.ratio = clamp(self.duty.ratio, 0, 1)
  216. self.duty.sweep = clamp(self.duty.sweep, -1, 1)
  217. self.phaser.offset = clamp(self.phaser.offset, -1, 1)
  218. self.phaser.sweep = clamp(self.phaser.sweep, -1, 1)
  219. self.lowpass.cutoff = clamp(self.lowpass.cutoff, 0, 1)
  220. self.lowpass.sweep = clamp(self.lowpass.sweep, -1, 1)
  221. self.lowpass.resonance = clamp(self.lowpass.resonance, 0, 1)
  222. self.highpass.cutoff = clamp(self.highpass.cutoff, 0, 1)
  223. self.highpass.sweep = clamp(self.highpass.sweep, -1, 1)
  224. end
  225. function sfxr.Sound:generate(freq, bits)
  226. -- Basically the main synthesizing function, yields the sample data
  227. freq = freq or sfxr.FREQ_44100
  228. bits = bits or sfxr.BITS_FLOAT
  229. assert(freq == sfxr.FREQ_44100 or freq == sfxr.FREQ_22050, "Invalid freq argument")
  230. assert(bits == sfxr.BITS_FLOAT or bits == sfxr.BITS_16 or bits == sfxr.BITS_8, "Invalid bits argument")
  231. -- Initialize ALL the locals!
  232. local fperiod, maxperiod
  233. local slide, dslide
  234. local square_duty, square_slide
  235. local chg_mod, chg_time, chg_limit
  236. local phaserbuffer = {}
  237. local noisebuffer = {}
  238. -- Reset the sample buffers
  239. for i=1, 1024 do
  240. phaserbuffer[i] = 0
  241. end
  242. for i=1, 32 do
  243. noisebuffer[i] = random(-1, 1)
  244. end
  245. local function reset()
  246. fperiod = 100 / (self.frequency.start^2 + 0.001)
  247. maxperiod = 100 / (self.frequency.min^2 + 0.001)
  248. period = trunc(fperiod)
  249. slide = 1.0 - self.frequency.slide^3 * 0.01
  250. dslide = -self.frequency.dslide^3 * 0.000001
  251. square_duty = 0.5 - self.duty.ratio * 0.5
  252. square_slide = -self.duty.sweep * 0.00005
  253. if self.change.amount >= 0 then
  254. chg_mod = 1.0 - self.change.amount^2 * 0.9
  255. else
  256. chg_mod = 1.0 + self.change.amount^2 * 10
  257. end
  258. chg_time = 0
  259. if self.change.speed == 1 then
  260. chg_limit = 0
  261. else
  262. chg_limit = trunc((1 - self.change.speed)^2 * 20000 + 32)
  263. end
  264. end
  265. local phase = 0
  266. reset()
  267. local second_sample = false
  268. local env_vol = 0
  269. local env_stage = 1
  270. local env_time = 0
  271. local env_length = {self.envelope.attack^2 * 100000,
  272. self.envelope.sustain^2 * 100000,
  273. self.envelope.decay^2 * 100000}
  274. local fphase = self.phaser.offset^2 * 1020
  275. if self.phaser.offset < 0 then fphase = -fphase end
  276. local dphase = self.phaser.sweep^2
  277. if self.phaser.sweep < 0 then dphase = -dphase end
  278. local ipp = 0
  279. local iphase = math.abs(trunc(fphase))
  280. local fltp = 0
  281. local fltdp = 0
  282. local fltw = self.lowpass.cutoff^3 * 0.1
  283. local fltw_d = 1 + self.lowpass.sweep * 0.0001
  284. local fltdmp = 5 / (1 + self.lowpass.resonance^2 * 20) * (0.01 + fltw)
  285. fltdmp = clamp(fltdmp, nil, 0.8)
  286. local fltphp = 0
  287. local flthp = self.highpass.cutoff^2 * 0.1
  288. local flthp_d = 1 + self.highpass.sweep * 0.0003
  289. local vib_phase = 0
  290. local vib_speed = self.vibrato.speed^2 * 0.01
  291. local vib_amp = self.vibrato.depth * 0.5
  292. local rep_time = 0
  293. local rep_limit = trunc((1 - self.repeatspeed)^2 * 20000 + 32)
  294. if self.repeatspeed == 0 then
  295. rep_limit = 0
  296. end
  297. -- Yay, the main closure
  298. local function next()
  299. -- Repeat when needed
  300. rep_time = rep_time + 1
  301. if rep_limit ~= 0 and rep_time >= rep_limit then
  302. rep_time = 0
  303. reset()
  304. end
  305. -- Update the change time and apply it if needed
  306. chg_time = chg_time + 1
  307. if chg_limit ~= 0 and chg_time >= chg_limit then
  308. chg_limit = 0
  309. fperiod = fperiod * chg_mod
  310. end
  311. -- Apply the frequency slide and stuff
  312. slide = slide + dslide
  313. fperiod = fperiod * slide
  314. if fperiod > maxperiod then
  315. fperiod = maxperiod
  316. -- XXX: Fail if the minimum frequency is too small
  317. if (self.frequency.min > 0) then
  318. return nil
  319. end
  320. end
  321. -- Vibrato
  322. local rfperiod = fperiod
  323. if vib_amp > 0 then
  324. vib_phase = vib_phase + vib_speed
  325. -- Apply to the frequency period
  326. rfperiod = fperiod * (1.0 + math.sin(vib_phase) * vib_amp)
  327. end
  328. -- Update the period
  329. period = trunc(rfperiod)
  330. if (period < 8) then period = 8 end
  331. -- Update the square duty
  332. square_duty = clamp(square_duty + square_slide, 0, 0.5)
  333. -- Volume envelopes
  334. env_time = env_time + 1
  335. if env_time > env_length[env_stage] then
  336. env_time = 0
  337. env_stage = env_stage + 1
  338. -- After the decay stop generating
  339. if env_stage == 4 then
  340. return nil
  341. end
  342. end
  343. -- Attack, Sustain, Decay/Release
  344. if env_stage == 1 then
  345. env_vol = env_time / env_length[1]
  346. elseif env_stage == 2 then
  347. env_vol = 1 + (1 - env_time / env_length[2])^1 * 2 * self.envelope.punch
  348. elseif env_stage == 3 then
  349. env_vol = 1 - env_time / env_length[3]
  350. end
  351. -- Phaser
  352. fphase = fphase + dphase
  353. iphase = clamp(math.abs(trunc(fphase)), nil, 1023)
  354. -- Filter stuff
  355. if flthp_d ~= 0 then
  356. flthp = clamp(flthp * flthp_d, 0.00001, 0.1)
  357. end
  358. -- And finally the actual tone generation and supersampling
  359. local ssample = 0
  360. for si = 0, self.supersamples-1 do
  361. local sample = 0
  362. phase = phase + 1
  363. -- fill the noise buffer every period
  364. if phase >= period then
  365. --phase = 0
  366. phase = phase % period
  367. if self.wavetype == sfxr.NOISE then
  368. for i = 1, 32 do
  369. noisebuffer[i] = random(-1, 1)
  370. end
  371. end
  372. end
  373. -- Tone generators ahead!!!
  374. local fp = phase / period
  375. -- Square, including square duty
  376. if self.wavetype == sfxr.SQUARE then
  377. if fp < square_duty then
  378. sample = 0.5
  379. else
  380. sample = -0.5
  381. end
  382. -- Sawtooth
  383. elseif self.wavetype == sfxr.SAWTOOTH then
  384. sample = 1 - fp * 2
  385. -- Sine
  386. elseif self.wavetype == sfxr.SINE then
  387. sample = math.sin(fp * 2 * math.pi)
  388. -- Pitched white noise
  389. elseif self.wavetype == sfxr.NOISE then
  390. sample = noisebuffer[trunc(phase * 32 / period) % 32 + 1]
  391. end
  392. -- Apply the lowpass filter to the sample
  393. local pp = fltp
  394. fltw = clamp(fltw * fltw_d, 0, 0.1)
  395. if self.lowpass.cutoff ~= 1 then
  396. fltdp = fltdp + (sample - fltp) * fltw
  397. fltdp = fltdp - fltdp * fltdmp
  398. else
  399. fltp = sample
  400. fltdp = 0
  401. end
  402. fltp = fltp + fltdp
  403. -- Apply the highpass filter to the sample
  404. fltphp = fltphp + (fltp - pp)
  405. fltphp = fltphp - (fltphp * flthp)
  406. sample = fltphp
  407. -- Apply the phaser to the sample
  408. phaserbuffer[bit.band(ipp, 1023) + 1] = sample
  409. sample = sample + phaserbuffer[bit.band(ipp - iphase + 1024, 1023) + 1]
  410. ipp = bit.band(ipp + 1, 1023)
  411. -- Accumulation and envelope application
  412. ssample = ssample + sample * env_vol
  413. end
  414. -- Apply the volumes
  415. ssample = (ssample / self.supersamples) * self.volume.master
  416. ssample = ssample * (2 * self.volume.sound)
  417. -- Hard limit
  418. ssample = clamp(ssample, -1, 1)
  419. -- Frequency conversion
  420. second_sample = not second_sample
  421. if freq == sfxr.FREQ_22050 and second_sample then
  422. -- hah!
  423. local nsample = next()
  424. if nsample then
  425. return (ssample + nsample) / 2
  426. else
  427. return nil
  428. end
  429. end
  430. -- bit conversions
  431. if bits == sfxr.BITS_FLOAT then
  432. return ssample
  433. elseif bits == sfxr.BITS_16 then
  434. return trunc(ssample * 32000)
  435. else
  436. return trunc(ssample * 127 + 128)
  437. end
  438. end
  439. return next
  440. end
  441. function sfxr.Sound:getEnvelopeLimit(freq)
  442. local env_length = {self.envelope.attack^2 * 100000,
  443. self.envelope.sustain^2 * 100000,
  444. self.envelope.decay^2 * 100000}
  445. local limit = trunc(env_length[1] + env_length[2] + env_length[3] + 2)
  446. if freq == nil or freq == sfxr.FREQ_44100 then
  447. return limit
  448. elseif freq == sfxr.FREQ_22050 then
  449. return math.ceil(limit / 2)
  450. else
  451. error("Invalid freq argument")
  452. end
  453. end
  454. function sfxr.Sound:generateTable(freq, bits)
  455. local t = {}
  456. local i = 1
  457. for v in self:generate(freq, bits) do
  458. t[i] = v
  459. i = i + 1
  460. end
  461. return t
  462. end
  463. function sfxr.Sound:generateString(freq, bits, endianness)
  464. assert(bits == sfxr.BITS_16 or bits == sfxr.BITS_8, "Invalid bits argument")
  465. assert(endianness == "big" or endianness == "little", "Invalid endianness")
  466. local s = ""
  467. local buf = {}
  468. buf[100] = 0
  469. local i = 1
  470. for v in self:generate(freq, bits) do
  471. if bits == sfxr.BITS_8 then
  472. buf[i] = v
  473. i = i + 1
  474. else
  475. if endianness == "big" then
  476. buf[i] = bit.rshift(v, 8)
  477. buf[i + 1] = bit.band(v, 0xFF)
  478. i = i + 2
  479. else
  480. buf[i] = bit.band(v, 0xFF)
  481. buf[i + 1] = bit.rshift(v, 8)
  482. i = i + 2
  483. end
  484. end
  485. if i >= 100 then
  486. s = s .. string.char(unpack(buf))
  487. i = 0
  488. end
  489. end
  490. s = s .. string.char(unpack(buf, i, 100))
  491. return s
  492. end
  493. function sfxr.Sound:generateSoundData(freq, bits)
  494. freq = freq or sfxr.FREQ_44100
  495. local tab = self:generateTable(freq, sfxr.BITS_FLOAT)
  496. if #tab == 0 then
  497. return nil
  498. end
  499. local data = love.sound.newSoundData(#tab, freq, bits, 1)
  500. for i = 0, #tab - 1 do
  501. data:setSample(i, tab[i + 1])
  502. end
  503. return data
  504. end
  505. function sfxr.Sound:play(freq, bits)
  506. local data = self:generateSoundData(freq, bits)
  507. if data then
  508. local source = love.audio.newSource(data)
  509. source:play()
  510. return source
  511. end
  512. end
  513. function sfxr.Sound:randomize(seed)
  514. if seed then setseed(seed) end
  515. local wavetype = self.wavetype
  516. self:resetParameters()
  517. self.wavetype = wavetype
  518. if maybe() then
  519. self.repeatspeed = random(0, 1)
  520. end
  521. if maybe() then
  522. self.frequency.start = random(-1, 1)^3 + 0.5
  523. else
  524. self.frequency.start = random(-1, 1)^2
  525. end
  526. self.frequency.limit = 0
  527. self.frequency.slide = random(-1, 1)^5
  528. if self.frequency.start > 0.7 and self.frequency.slide > 0.2 then
  529. self.frequency.slide = -self.frequency.slide
  530. elseif self.frequency.start < 0.2 and self.frequency.slide <-0.05 then
  531. self.frequency.slide = -self.frequency.slide
  532. end
  533. self.frequency.dslide = random(-1, 1)^3
  534. self.duty.ratio = random(-1, 1)
  535. self.duty.sweep = random(-1, 1)^3
  536. self.vibrato.depth = random(-1, 1)^3
  537. self.vibrato.speed = random(-1, 1)
  538. self.vibrato.delay = random(-1, 1)
  539. self.envelope.attack = random(-1, 1)^3
  540. self.envelope.sustain = random(-1, 1)^2
  541. self.envelope.punch = random(-1, 1)^2
  542. self.envelope.decay = random(-1, 1)
  543. if self.envelope.attack + self.envelope.sustain + self.envelope.decay < 0.2 then
  544. self.envelope.sustain = self.envelope.sustain + 0.2 + random(0, 0.3)
  545. self.envelope.decay = self.envelope.decay + 0.2 + random(0, 0.3)
  546. end
  547. self.lowpass.resonance = random(-1, 1)
  548. self.lowpass.cutoff = 1 - random(0, 1)^3
  549. self.lowpass.sweep = random(-1, 1)^3
  550. if self.lowpass.cutoff < 0.1 and self.lowpass.sweep < -0.05 then
  551. self.lowpass.sweep = -self.lowpass.sweep
  552. end
  553. self.highpass.cutoff = random(0, 1)^3
  554. self.highpass.sweep = random(-1, 1)^5
  555. self.phaser.offset = random(-1, 1)^3
  556. self.phaser.sweep = random(-1, 1)^3
  557. self.change.speed = random(-1, 1)
  558. self.change.amount = random(-1, 1)
  559. self:sanitizeParameters()
  560. end
  561. function sfxr.Sound:mutate(amount, seed, changeFreq)
  562. if seed then setseed(seed) end
  563. local amount = (amount or 1)
  564. local a = amount / 20
  565. local b = (1 - a) * 10
  566. local changeFreq = (changeFreq == nil) and true or changeFreq
  567. if changeFreq == true then
  568. if maybe(b) then self.frequency.start = self.frequency.start + random(-a, a) end
  569. if maybe(b) then self.frequency.slide = self.frequency.slide + random(-a, a) end
  570. if maybe(b) then self.frequency.dslide = self.frequency.dslide + random(-a, a) end
  571. end
  572. if maybe(b) then self.duty.ratio = self.duty.ratio + random(-a, a) end
  573. if maybe(b) then self.duty.sweep = self.duty.sweep + random(-a, a) end
  574. if maybe(b) then self.vibrato.depth = self.vibrato.depth + random(-a, a) end
  575. if maybe(b) then self.vibrato.speed = self.vibrato.speed + random(-a, a) end
  576. if maybe(b) then self.vibrato.delay = self.vibrato.delay + random(-a, a) end
  577. if maybe(b) then self.envelope.attack = self.envelope.attack + random(-a, a) end
  578. if maybe(b) then self.envelope.sustain = self.envelope.sustain + random(-a, a) end
  579. if maybe(b) then self.envelope.punch = self.envelope.punch + random(-a, a) end
  580. if maybe(b) then self.envelope.decay = self.envelope.decay + random(-a, a) end
  581. if maybe(b) then self.lowpass.resonance = self.lowpass.resonance + random(-a, a) end
  582. if maybe(b) then self.lowpass.cutoff = self.lowpass.cutoff + random(-a, a) end
  583. if maybe(b) then self.lowpass.sweep = self.lowpass.sweep + random(-a, a) end
  584. if maybe(b) then self.highpass.cutoff = self.highpass.cutoff + random(-a, a) end
  585. if maybe(b) then self.highpass.sweep = self.highpass.sweep + random(-a, a) end
  586. if maybe(b) then self.phaser.offset = self.phaser.offset + random(-a, a) end
  587. if maybe(b) then self.phaser.sweep = self.phaser.sweep + random(-a, a) end
  588. if maybe(b) then self.change.speed = self.change.speed + random(-a, a) end
  589. if maybe(b) then self.change.amount = self.change.amount + random(-a, a) end
  590. if maybe(b) then self.repeatspeed = self.repeatspeed + random(-a, a) end
  591. self:sanitizeParameters()
  592. end
  593. function sfxr.Sound:randomPickup(seed)
  594. if seed then setseed(seed) end
  595. self:resetParameters()
  596. self.frequency.start = random(0.4, 0.9)
  597. self.envelope.attack = 0
  598. self.envelope.sustain = random(0, 0.1)
  599. self.envelope.punch = random(0.3, 0.6)
  600. self.envelope.decay = random(0.1, 0.5)
  601. if maybe() then
  602. self.change.speed = random(0.5, 0.7)
  603. self.change.amount = random(0.2, 0.6)
  604. end
  605. end
  606. function sfxr.Sound:randomLaser(seed)
  607. if seed then setseed(seed) end
  608. self:resetParameters()
  609. self.wavetype = trunc(random(0, 3))
  610. if self.wavetype == sfxr.SINE and maybe() then
  611. self.wavetype = trunc(random(0, 1))
  612. end
  613. if maybe(2) then
  614. self.frequency.start = random(0.3, 0.9)
  615. self.frequency.min = random(0, 0.1)
  616. self.frequency.slide = random(-0.65, -0.35)
  617. else
  618. self.frequency.start = random(0.5, 1)
  619. self.frequency.min = clamp(self.frequency.start - random(0.2, 0.4), 0.2)
  620. self.frequency.slide = random(-0.35, -0.15)
  621. end
  622. if maybe() then
  623. self.duty.ratio = random(0, 0.5)
  624. self.duty.sweep = random(0, 0.2)
  625. else
  626. self.duty.ratio = random(0.4, 0.9)
  627. self.duty.sweep = random(-0.7, 0)
  628. end
  629. self.envelope.attack = 0
  630. self.envelope.sustain = random(0.1, 0.3)
  631. self.envelope.decay = random(0, 0.4)
  632. if maybe() then
  633. self.envelope.punch = random(0, 0.3)
  634. end
  635. if maybe(2) then
  636. self.phaser.offset = random(0, 0.2)
  637. self.phaser.sweep = random(-0.2, 0)
  638. end
  639. if maybe() then
  640. self.highpass.cutoff = random(0, 0.3)
  641. end
  642. end
  643. function sfxr.Sound:randomExplosion(seed)
  644. if seed then setseed(seed) end
  645. self:resetParameters()
  646. self.wavetype = sfxr.NOISE
  647. if maybe() then
  648. self.frequency.start = random(0.1, 0.5)
  649. self.frequency.slide = random(-0.1, 0.3)
  650. else
  651. self.frequency.start = random(0.2, 0.9)
  652. self.frequency.slide = random(-0.2, -0.4)
  653. end
  654. self.frequency.start = self.frequency.start^2
  655. if maybe(4) then
  656. self.frequency.slide = 0
  657. end
  658. if maybe(2) then
  659. self.repeatspeed = random(0.3, 0.8)
  660. end
  661. self.envelope.attack = 0
  662. self.envelope.sustain = random(0.1, 0.4)
  663. self.envelope.punch = random(0.2, 0.8)
  664. self.envelope.decay = random(0, 0.5)
  665. if maybe() then
  666. self.phaser.offset = random(-0.3, 0.6)
  667. self.phaser.sweep = random(-0.3, 0)
  668. end
  669. if maybe() then
  670. self.vibrato.depth = random(0, 0.7)
  671. self.vibrato.speed = random(0, 0.6)
  672. end
  673. if maybe(2) then
  674. self.change.speed = random(0.6, 0.9)
  675. self.change.amount = random(-0.8, 0.8)
  676. end
  677. end
  678. function sfxr.Sound:randomPowerup(seed)
  679. if seed then setseed(seed) end
  680. self:resetParameters()
  681. if maybe() then
  682. self.wavetype = sfxr.SAWTOOTH
  683. else
  684. self.duty.ratio = random(0, 0.6)
  685. end
  686. if maybe() then
  687. self.frequency.start = random(0.2, 0.5)
  688. self.frequency.slide = random(0.1, 0.5)
  689. self.repeatspeed = random(0.4, 0.8)
  690. else
  691. self.frequency.start = random(0.2, 0.5)
  692. self.frequency.slide = random(0.05, 0.25)
  693. if maybe() then
  694. self.vibrato.depth = random(0, 0.7)
  695. self.vibrato.speed = random(0, 0.6)
  696. end
  697. end
  698. self.envelope.attack = 0
  699. self.envelope.sustain = random(0, 0.4)
  700. self.envelope.decay = random(0.1, 0.5)
  701. end
  702. function sfxr.Sound:randomHit(seed)
  703. if seed then setseed(seed) end
  704. self:resetParameters()
  705. self.wavetype = trunc(random(0, 3))
  706. if self.wavetype == sfxr.SINE then
  707. self.wavetype = sfxr.NOISE
  708. elseif self.wavetype == sfxr.SQUARE then
  709. self.duty.ratio = random(0, 0.6)
  710. end
  711. self.frequency.start = random(0.2, 0.8)
  712. self.frequency.slide = random(-0.7, -0.3)
  713. self.envelope.attack = 0
  714. self.envelope.sustain = random(0, 0.1)
  715. self.envelope.decay = random(0.1, 0.3)
  716. if maybe() then
  717. self.highpass.cutoff = random(0, 0.3)
  718. end
  719. end
  720. function sfxr.Sound:randomJump(seed)
  721. if seed then setseed(seed) end
  722. self:resetParameters()
  723. self.wavetype = sfxr.SQUARE
  724. self.duty.value = random(0, 0.6)
  725. self.frequency.start = random(0.3, 0.6)
  726. self.frequency.slide = random(0.1, 0.3)
  727. self.envelope.attack = 0
  728. self.envelope.sustain = random(0.1, 0.4)
  729. self.envelope.decay = random(0.1, 0.3)
  730. if maybe() then
  731. self.highpass.cutoff = random(0, 0.3)
  732. end
  733. if maybe() then
  734. self.lowpass.cutoff = random(0.4, 1)
  735. end
  736. end
  737. function sfxr.Sound:randomBlip(seed)
  738. if seed then setseed(seed) end
  739. self:resetParameters()
  740. self.wavetype = trunc(random(0, 2))
  741. if self.wavetype == sfxr.SQUARE then
  742. self.duty.ratio = random(0, 0.6)
  743. end
  744. self.frequency.start = random(0.2, 0.6)
  745. self.envelope.attack = 0
  746. self.envelope.sustain = random(0.1, 0.2)
  747. self.envelope.decay = random(0, 0.2)
  748. self.highpass.cutoff = 0.1
  749. end
  750. function sfxr.Sound:exportWAV(f, freq, bits)
  751. freq = freq or sfxr.FREQ_44100
  752. bits = bits or sfxr.BITS_16
  753. assert(freq == sfxr.FREQ_44100 or freq == sfxr.FREQ_22050, "Invalid freq argument")
  754. assert(bits == sfxr.BITS_16 or bits == sfxr.BITS_8, "Invalid bits argument")
  755. local close = false
  756. if type(f) == "string" then
  757. f = io.open(f, "wb")
  758. close = true
  759. end
  760. -- Some utility functions
  761. function seek(pos)
  762. if io.type(f) == "file" then
  763. f:seek("set", pos)
  764. else
  765. f:seek(pos)
  766. end
  767. end
  768. function tell()
  769. if io.type(f) == "file" then
  770. return f:seek()
  771. else
  772. return f:tell()
  773. end
  774. end
  775. function bytes(num, len)
  776. local str = ""
  777. for i = 1, len do
  778. str = str .. string.char(num % 256)
  779. num = math.floor(num / 256)
  780. end
  781. return str
  782. end
  783. function w16(num)
  784. f:write(bytes(num, 2))
  785. end
  786. function w32(num)
  787. f:write(bytes(num, 4))
  788. end
  789. function ws(str)
  790. f:write(str)
  791. end
  792. -- These will hold important file positions
  793. local pos_fsize
  794. local pos_csize
  795. -- Start the file by writing the RIFF header
  796. ws("RIFF")
  797. pos_fsize = tell()
  798. w32(0) -- remaining file size, will be replaced later
  799. ws("WAVE") -- type
  800. -- Write the format chunk
  801. ws("fmt ")
  802. w32(16) -- chunk size
  803. w16(1) -- compression code (1 = PCM)
  804. w16(1) -- channel number
  805. w32(freq) -- sample rate
  806. w32(freq * bits / 8) -- bytes per second
  807. w16(bits / 8) -- block alignment
  808. w16(bits) -- bits per sample
  809. -- Write the header of the data chunk
  810. ws("data")
  811. pos_csize = tell()
  812. w32(0) -- chunk size, will be replaced later
  813. -- Aand write the actual sample data
  814. local samples = 0
  815. for v in self:generate(freq, bits) do
  816. samples = samples + 1
  817. if bits == sfxr.BITS_16 then
  818. -- wrap around a bit
  819. if v >= 256^2 then v = 0 end
  820. if v < 0 then v = 256^2 + v end
  821. w16(v)
  822. else
  823. f:write(string.char(v))
  824. end
  825. end
  826. -- Seek back to the stored positions
  827. seek(pos_fsize)
  828. w32(pos_csize - 4 + samples * bits / 8) -- remaining file size
  829. seek(pos_csize)
  830. w32(samples * bits / 8) -- chunk size
  831. if close then
  832. f:close()
  833. end
  834. end
  835. function sfxr.Sound:save(f, compressed)
  836. local close = false
  837. if type(f) == "string" then
  838. f = io.open(f, "w")
  839. close = true
  840. end
  841. local code = "local "
  842. -- we'll compare the current parameters with the defaults
  843. local defaults = sfxr.newSound()
  844. -- this part is pretty awful but it works for now
  845. function store(keys, obj)
  846. local name = keys[#keys]
  847. if type(obj) == "number" then
  848. -- fetch the default value
  849. local def = defaults
  850. for i=2, #keys do
  851. def = def[keys[i]]
  852. end
  853. if obj ~= def then
  854. local k = table.concat(keys, ".")
  855. if not compressed then
  856. code = code .. "\n" .. string.rep(" ", #keys - 1)
  857. end
  858. code = code .. string.format("%s=%s;", name, obj)
  859. end
  860. elseif type(obj) == "table" then
  861. local spacing = compressed and "" or "\n" .. string.rep(" ", #keys - 1)
  862. code = code .. spacing .. string.format("%s={", name)
  863. for k, v in pairs(obj) do
  864. local newkeys = shallowcopy(keys)
  865. newkeys[#newkeys + 1] = k
  866. store(newkeys, v)
  867. end
  868. code = code .. spacing .. "};"
  869. end
  870. end
  871. store({"s"}, self)
  872. code = code .. "\nreturn s, \"" .. sfxr.VERSION .. "\""
  873. f:write(code)
  874. if close then
  875. f:close()
  876. end
  877. end
  878. function sfxr.Sound:load(f)
  879. local close = false
  880. if type(f) == "string" then
  881. f = io.open(f, "r")
  882. close = true
  883. end
  884. local code
  885. if io.type(f) == "file" then
  886. code = f:read("*a")
  887. else
  888. code = f:read()
  889. end
  890. local params, version = assert(loadstring(code))()
  891. -- check version compatibility
  892. if version > sfxr.VERSION then
  893. return version
  894. end
  895. self:resetParameters()
  896. -- merge the loaded table into the own
  897. mergetables(self, params)
  898. if close then
  899. f:close()
  900. end
  901. end
  902. function sfxr.Sound:saveBinary(f)
  903. local close = false
  904. if type(f) == "string" then
  905. f = io.open(f, "w")
  906. close = true
  907. end
  908. function writeFloat(x)
  909. local packed = packIEEE754(x):reverse()
  910. assert(packed:len() == 4)
  911. f:write(packed)
  912. end
  913. f:write('\x66\x00\x00\x00') -- version 102
  914. assert(self.wavetype < 256)
  915. f:write(string.char(self.wavetype) .. '\x00\x00\x00')
  916. writeFloat(self.volume.sound)
  917. writeFloat(self.frequency.start)
  918. writeFloat(self.frequency.min)
  919. writeFloat(self.frequency.slide)
  920. writeFloat(self.frequency.dslide)
  921. writeFloat(self.duty.ratio)
  922. writeFloat(self.duty.sweep)
  923. writeFloat(self.vibrato.depth)
  924. writeFloat(self.vibrato.speed)
  925. writeFloat(self.vibrato.delay)
  926. writeFloat(self.envelope.attack)
  927. writeFloat(self.envelope.sustain)
  928. writeFloat(self.envelope.decay)
  929. writeFloat(self.envelope.punch)
  930. f:write('\x00') -- unused filter_on boolean
  931. writeFloat(self.lowpass.resonance)
  932. writeFloat(self.lowpass.cutoff)
  933. writeFloat(self.lowpass.sweep)
  934. writeFloat(self.highpass.cutoff)
  935. writeFloat(self.highpass.sweep)
  936. writeFloat(self.phaser.offset)
  937. writeFloat(self.phaser.sweep)
  938. writeFloat(self.repeatspeed)
  939. writeFloat(self.change.speed)
  940. writeFloat(self.change.amount)
  941. if close then
  942. f:close()
  943. end
  944. end
  945. function sfxr.Sound:loadBinary(f)
  946. local close = false
  947. if type(f) == "string" then
  948. f = io.open(f, "r")
  949. close = true
  950. end
  951. local s
  952. if io.type(f) == "file" then
  953. s = f:read("*a")
  954. else
  955. s = f:read()
  956. end
  957. if close then
  958. f:close()
  959. end
  960. self:resetParameters()
  961. local off = 1
  962. local function readFloat()
  963. local f = unpackIEEE754(s:sub(off, off+3):reverse())
  964. off = off + 4
  965. return f
  966. end
  967. -- Start reading the string
  968. local version = s:byte(off)
  969. off = off + 4
  970. if version < 100 or version > 102 then
  971. return nil, "unknown version number "..version
  972. end
  973. self.wavetype = s:byte(off)
  974. off = off + 4
  975. self.volume.sound = version==102 and readFloat() or 0.5
  976. self.frequency.start = readFloat()
  977. self.frequency.min = readFloat()
  978. self.frequency.slide = readFloat()
  979. self.frequency.dslide = version>=101 and readFloat() or 0
  980. self.duty.ratio = readFloat()
  981. self.duty.sweep = readFloat()
  982. self.vibrato.depth = readFloat()
  983. self.vibrato.speed = readFloat()
  984. self.vibrato.delay = readFloat()
  985. self.envelope.attack = readFloat()
  986. self.envelope.sustain = readFloat()
  987. self.envelope.decay = readFloat()
  988. self.envelope.punch = readFloat()
  989. off = off + 1 -- filter_on - seems to be ignored in the C++ version
  990. self.lowpass.resonance = readFloat()
  991. self.lowpass.cutoff = readFloat()
  992. self.lowpass.sweep = readFloat()
  993. self.highpass.cutoff = readFloat()
  994. self.highpass.sweep = readFloat()
  995. self.phaser.offset = readFloat()
  996. self.phaser.sweep = readFloat()
  997. self.repeatspeed = readFloat()
  998. if version >= 101 then
  999. self.change.speed = readFloat()
  1000. self.change.amount = readFloat()
  1001. end
  1002. assert(off-1 == s:len())
  1003. end
  1004. return sfxr