Skip to content

Instantly share code, notes, and snippets.

@RSDuck
Created June 1, 2017 18:10
Show Gist options
  • Save RSDuck/0349b59cfcce0721a1014b6cf2c46dc7 to your computer and use it in GitHub Desktop.
Save RSDuck/0349b59cfcce0721a1014b6cf2c46dc7 to your computer and use it in GitHub Desktop.
#based of this: https://github.com/yglukhov/sound
#[
The MIT License (MIT)
Copyright (c) 2015 Yuriy Glukhov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]#
type
ALuint* = cuint
ALint* = cint
ALsizei* = cint
ALenum* = cint
ALfloat* = cfloat
when defined(linux):
{.passL: "-lopenal"}
{.pragma: alimport, importc.}
elif defined(windows):
{.pragma: alimport, cdecl, dynlib: "OpenAL32.dll", importc.}
else:
when defined(macosx) or defined(ios):
{.passL: "-framework OpenAL".}
{.pragma: alimport, importc.}
const
AL_FORMAT_MONO8* : cint = 0x1100
AL_FORMAT_MONO16* : cint = 0x1101
AL_FORMAT_STEREO8* : cint = 0x1102
AL_FORMAT_STEREO16* : cint = 0x1103
AL_BUFFER* : ALenum = 0x1009
AL_PITCH*: ALenum = 0x1003
AL_POSITION* : ALenum = 0x1004
AL_DIRECTION* : ALenum = 0x1005
AL_VELOCITY* : ALenum = 0x1006
AL_ORIENTATION* : ALenum = 0x100F
AL_LOOPING* : ALenum = 0x1007
AL_FREQUENCY* : ALenum = 0x2001
AL_BITS* : ALenum = 0x2002
AL_CHANNELS* : ALenum = 0x2003
AL_SIZE* : ALenum = 0x2004
AL_GAIN* : ALenum = 0x100A
AL_SOURCE_STATE* : ALenum = 0x1010
AL_INITIAL* : ALenum = 0x1011
AL_PLAYING* : ALenum = 0x1012
AL_PAUSED* : ALenum = 0x1013
AL_STOPPED* : ALenum = 0x1014
proc alGenBuffers*(n: ALsizei , buffers: ptr ALuint) {.alimport.}
proc alGenSources*(n: ALsizei, sources: ptr ALuint) {.alimport.}
proc alSourcei*(sid: ALuint, param: ALenum, value: ALint) {.alimport.}
proc alSourcef*(sid: ALuint, param: ALenum, value: ALfloat) {.alimport.}
proc alGetSourcef*(sid: ALuint, param: ALenum, value: ptr ALfloat) {.alimport.}
proc alGetSourcei*(sid: ALuint, param: ALenum, value: ptr ALint) {.alimport.}
proc alSourcePlay*(sid: ALuint) {.alimport.}
proc alSourceStop*(sid: ALuint) {.alimport.}
proc alGetBufferi*(bid: ALuint, param: ALenum, value: ptr ALint) {.alimport.}
proc alBufferData*(bid: ALuint, format: ALenum, data: pointer, size: ALsizei, freq: ALsizei) {.alimport.}
proc alListenerfv*(param: ALenum, values: ptr ALfloat) {.alimport.}
proc alDeleteSources*(n: ALsizei, sources: ptr ALuint) {.alimport.}
proc alDeleteBuffers*(n: ALsizei, buffers: ptr ALuint) {.alimport.}
# ALC
type
ALCint* = cint
ALCdevice* = pointer
ALCcontext* = pointer
ALCboolean* = int8
when defined(windows):
{.pragma: alcimport, cdecl, dynlib: "OpenAL32.dll", importc.}
else:
{.pragma: alcimport, importc.}
proc alcOpenDevice*(devicename: cstring): ALCdevice {.alcimport.}
proc alcCreateContext*(device: ALCdevice, attrlist: ptr ALCint): ALCcontext {.alcimport.}
proc alcMakeContextCurrent*(context: ALCcontext): ALCboolean {.alcimport.}
import openal, os, math, random
let device = alcOpenDevice(nil)
let ctx = device.alcCreateContext(nil)
discard alcMakeContextCurrent(ctx)
var
listener = [
ALfloat 0'f32, 0'f32, 0'f32,
0'f32, 0'f32, 1'f32, 0'f32, 1'f32, 0'f32
]
source = ALuint(0)
buffer = ALuint(0)
alListenerfv(AL_POSITION, addr listener[0])
alListenerfv(AL_VELOCITY, addr listener[0])
alListenerfv(AL_ORIENTATION, addr listener[3])
alGenSources(ALsizei 1, addr source)
alSourcef(source, AL_LOOPING, AlFloat 1'f32)
alSourcef(source, AL_GAIN, 1'f32)
alSourcef(source, AL_PITCH, 1'f32)
proc funcToWave(samplesPerSecond, length, frequency: int, f: proc(x: float): float): seq[int16] =
result = newSeq[int16](samplesPerSecond * length)
var x = 0.0
for i in 0..samplesPerSecond * length - 1:
let
v = f(x)
p = float(i) / float(samplesPerSecond * length)
result[i] = int16(v * float(32767.0/2.0) * (1.0 - p))
x += 1.0 / float(samplesPerSecond) * float(frequency)
type Note = tuple[length: int, value: int]
proc notesToWave(samplesPerSecond: int, notes: openArray[Note]): seq[int16] =
const frequencies = [261, 293, 329, 349, 391, 440, 493, 523]
result = newSeqOfCap[int16](samplesPerSecond * notes.len)
for note in notes:
let buffer = funcToWave(samplesPerSecond, 1, frequencies[note.value]) do (x: float) -> float:
if x.splitDecimal().floatpart - 0.1 < 0.0: -1 else: 1
result.add(buffer)
let
samplesPerSecond = 44100
sineWave = funcToWave(samplesPerSecond, 2, 440) do (x: float) -> float:
sin(TAU * x) * 0.5
triangleWave = funcToWave(samplesPerSecond, 10, 261) do (x: float) -> float:
abs(x.splitDecimal().floatpart - 0.5) * 4 - 1
sawWave = funcToWave(samplesPerSecond, 10, 440) do (x: float) -> float:
-1 + 2 * x.splitDecimal().floatpart
pulseWave = funcToWave(samplesPerSecond, 10, 440) do (x: float) -> float:
if x.splitDecimal().floatpart - 0.1 < 0.0: -1 else: 1
noiseWave = funcToWave(samplesPerSecond, 10, 440) do (x: float) -> float:
random(2.0) - 1.0
ladder = notesToWave(samplesPerSecond, [
(1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 4), (1, 5), (1, 5), (1, 5), (1, 5), (1, 4), (1, 5), (1, 5), (1, 5), (1, 5), (1, 4), (1, 3), (1, 3), (1, 3), (1, 3), (1, 2), (1, 2), (1, 1), (1, 1), (1, 1), (1, 1), (1, 0)])
#for v in sineWave:
# echo v
alGenBuffers(ALsizei 1, addr buffer)
alBufferData(buffer, AL_FORMAT_MONO16, unsafeAddr ladder[0], ALsizei ladder.len * 2, ALsizei samplesPerSecond)
alSourcei(source, AL_BUFFER, Alint buffer)
alSourcePlay(source)
sleep(ladder.len div samplesPerSecond * 1000)
alDeleteSources(1, addr source)
alDeleteBuffers(1, addr buffer)
@treeform
Copy link

treeform commented Sep 1, 2018

Hey RSDuck, I really like your openAL test sample, can I include this in my openAL wrapper in the test dir? Can I include it as MIT licensed?

@treeform
Copy link

treeform commented Sep 1, 2018

This is what I have so far: https://github.com/treeform/openal

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment