Skip to content

Commit

Permalink
KOMODO-37: Add basic audio API
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesaorson committed Mar 8, 2021
1 parent da54090 commit ea694c7
Show file tree
Hide file tree
Showing 15 changed files with 233 additions and 22 deletions.
Binary file added examples/desktop/audio/not-the-bees.mp3
Binary file not shown.
10 changes: 10 additions & 0 deletions examples/desktop/src/desktop.nim
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,15 @@ proc addBrainlet(game: Game) =
assert not game.deregisterComponent(sprite)
assert game.registerComponent(sprite)

let sound = newSoundComponent(
parent,
"audio/not-the-bees.mp3",
)
assert game.registerComponent(sound)
assert game.deregisterComponent(sound)
assert not game.deregisterComponent(sound)
assert game.registerComponent(sound)

let text = newTextComponent(
parent,
"Hello from desktop!",
Expand Down Expand Up @@ -127,6 +136,7 @@ proc main() =
var game = newGame()
game.title = "Desktop Example"
game.clearColor = Blue
game.shouldCloseAudio = false

game.addCube()
game.addBrainlet()
Expand Down
31 changes: 30 additions & 1 deletion examples/desktop/src/move_system.nim
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import komodo/prelude
import strformat

import komodo/ecs/systems/system_macros
import komodo/lib/audio


func move(
Expand All @@ -25,6 +26,7 @@ system MoveSystem:
move_right_action: Action
move_up_action: Action
move_down_action: Action
sound_action: Action

create:
discard
Expand All @@ -35,6 +37,7 @@ system MoveSystem:
self.move_right_action = self.action_manager.newAction("move_right")
self.move_up_action = self.action_manager.newAction("move_up")
self.move_down_action = self.action_manager.newAction("move_down")
self.sound_action = self.action_manager.newAction("sound")
self.action_manager
.map(self.move_left_action, Keys.Left)
.map(self.move_left_action, Keys.A)
Expand All @@ -44,19 +47,28 @@ system MoveSystem:
.map(self.move_up_action, Keys.W)
.map(self.move_down_action, Keys.Down)
.map(self.move_down_action, Keys.S)
.map(self.sound_action, Keys.Space)

update:
for entity_id, components in pairs(self.entityToComponents):
if self.findComponentByParent[:SpriteComponent](entity_id).isNone:
continue

let textOpt = self.findComponentByParent[:TextComponent](entity_id)
if textOpt.isNone:
continue
let text = textOpt.unsafeGet()

let transformOpt = self.findComponentByParent[:TransformComponent](entityId)
if transformOpt.isNone:
continue
let transform = transformOpt.unsafeGet()

let soundOpt = self.findComponentByParent[:SoundComponent](entityId)
if soundOpt.isNone:
continue
let sound = soundOpt.unsafeGet()

if self.move_left_action.isDown():
move(transform, xDirection = -1, delta = delta,)
if self.move_right_action.isDown():
Expand All @@ -66,7 +78,24 @@ system MoveSystem:
if self.move_down_action.isDown():
move(transform, yDirection = 1, delta = delta,)

textOpt.get.text = fmt"Hello from Desktop: {getFps()} FPS"
text.text = fmt"Hello from Desktop: {getFps()} FPS"
if self.sound_action.isPressed():
if sound.sound.isPlaying():
sound.sound.pause()
else:
sound.sound.play()

destroy:
discard

method hasNecessaryComponents*(
self: MoveSystem;
entity: Entity;
components: seq[Component];
): bool =
not (
self.findComponentByParent[:SpriteComponent](entity).isNone or
self.findComponentByParent[:TextComponent](entity).isNone or
self.findComponentByParent[:TransformComponent](entity).isNone or
self.findComponentByParent[:SoundComponent](entity).isNone
)
4 changes: 4 additions & 0 deletions src/komodo/ecs/components.nim
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import ./components/[
component,
model_component,
music_component,
sound_component,
sprite_component,
text_component,
transform_component,
]

export component
export model_component
export music_component
export sound_component
export sprite_component
export text_component
export transform_component
18 changes: 18 additions & 0 deletions src/komodo/ecs/components/music_component.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import ../../lib/audio

import ./component_macros

component MusicComponent:
fields:
music: Music

create(musicPath: string):
result.music = newMusic(musicPath)

init:
discard

destroy:
self.music.destroy()

func music*(self: MusicComponent): auto = self.music
18 changes: 18 additions & 0 deletions src/komodo/ecs/components/sound_component.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import ../../lib/audio

import ./component_macros

component SoundComponent:
fields:
sound: Sound

create(soundPath: string):
result.sound = newSound(soundPath)

init:
discard

destroy:
self.sound.destroy()

func sound*(self: SoundComponent): auto = self.sound
10 changes: 4 additions & 6 deletions src/komodo/ecs/systems/render_model_system.nim
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,7 @@ method hasNecessaryComponents*(
entity: Entity;
components: seq[Component];
): bool =
if (
self.findComponentByParent[:ModelComponent](entity).isNone or
self.findComponentByParent[:TransformComponent](entity).isNone
):
return false
true
(
self.findComponentByParent[:ModelComponent](entity).isNone and
self.findComponentByParent[:TransformComponent](entity).isNone
)
10 changes: 4 additions & 6 deletions src/komodo/ecs/systems/render_sprite_system.nim
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,7 @@ method hasNecessaryComponents*(
entity: Entity;
components: seq[Component];
): bool =
if (
self.findComponentByParent[:SpriteComponent](entity).isNone or
self.findComponentByParent[:TransformComponent](entity).isNone
):
return false
true
(
self.findComponentByParent[:SpriteComponent](entity).isNone and
self.findComponentByParent[:TransformComponent](entity).isNone
)
10 changes: 4 additions & 6 deletions src/komodo/ecs/systems/render_text_system.nim
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,7 @@ method hasNecessaryComponents*(
entity: Entity;
components: seq[Component];
): bool =
if (
self.findComponentByParent[:TextComponent](entity).isNone or
self.findComponentByParent[:TransformComponent](entity).isNone
):
return false
true
(
self.findComponentByParent[:TextComponent](entity).isNone and
self.findComponentByParent[:TransformComponent](entity).isNone
)
16 changes: 14 additions & 2 deletions src/komodo/game.nim
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import ./ecs/[
ids,
systems,
]
import ./lib/audio/sound_device
import ./lib/graphics
import ./lib/graphics/window
import ./lib/math
import ./logging

Expand All @@ -36,6 +38,7 @@ type Game* = ref object
entityStore: Table[EntityId, Entity]
isRunning: bool
screenSize: Option[Vector2]
shouldCloseAudio: bool
systems: seq[System]
title: string

Expand All @@ -49,6 +52,10 @@ func `clearColor=`*(self: Game; value: Color) {.inline.} =

func isRunning*(self: Game): auto {.inline.} = self.isRunning

func shouldCloseAudio*(self: Game): auto {.inline.} = self.isRunning
func `shouldCloseAudio=`*(self: Game; value: bool) {.inline.} =
self.shouldCloseAudio = value

func title*(self: Game): auto {.inline.} = self.title
func `title=`*(self: Game; value: string) {.inline.} =
self.title = value
Expand All @@ -61,10 +68,12 @@ func newGame*(title: string = DefaultTitle): Game =
result = Game()
result.systems = @[]
result.title = title
initWindow(
window.initialize(
screenSize(result),
result.title,
)
if not sound_device.isReady():
sound_device.initialize()

func draw(self: Game) =
beginDraw()
Expand Down Expand Up @@ -162,7 +171,10 @@ func setClearColor*(self: Game; clearColor: Color) =
func quit*(self: Game) =
if self.isRunning:
self.isRunning = false
close()

if self.shouldCloseAudio:
sound_device.close()
window.close()

func run*(self: Game) =
if not self.isRunning:
Expand Down
9 changes: 9 additions & 0 deletions src/komodo/lib/audio.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import audio/[
music,
sound,
sound_device,
]

export music
export sound
export sound_device
54 changes: 54 additions & 0 deletions src/komodo/lib/audio/music.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import options

from ../private/raylib import nil


template injectRaylibMusic(self: typed; music: untyped) =
if self.music.isNone:
return
let music: raylib.Music = self.music.unsafeGet()

type
Music* = ref object of RootObj
music: Option[raylib.Music]

func unload(self: Music) =
if self.music.isSome:
raylib.UnloadMusicStream(self.music.unsafeGet())
self.music = none[raylib.Music]()

func destroy*(self: Music) =
self.unload()

func newMusic*(musicPath: string): Music =
result = Music(
music: some(raylib.LoadMusicStream(musicPath))
)

func isPlaying*(self: Music): bool =
self.injectRaylibMusic(music)
result = raylib.IsMusicPlaying(music)

func pause*(self: Music) =
self.injectRaylibMusic(music)
raylib.PauseMusicStream(music)

func play*(self: Music) =
self.injectRaylibMusic(music)
raylib.PlayMusicStream(music)

func resume*(self: Music) =
self.injectRaylibMusic(music)
raylib.ResumeMusicStream(music)

func stop*(self: Music) =
self.injectRaylibMusic(music)
raylib.StopMusicStream(music)

func `volume=`(self: Music; volume: float32) =
self.injectRaylibMusic(music)
raylib.SetMusicVolume(music, volume)

func `pitch=`(self: Music; pitch: float32) =
self.injectRaylibMusic(music)
raylib.SetMusicPitch(music, pitch)
54 changes: 54 additions & 0 deletions src/komodo/lib/audio/sound.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import options

from ../private/raylib import nil


template injectRaylibSound(self: typed; sound: untyped) =
if self.sound.isNone:
return
let sound: raylib.Sound = self.sound.unsafeGet()

type
Sound* = ref object of RootObj
sound: Option[raylib.Sound]

func unload(self: Sound) =
if self.sound.isSome:
raylib.UnloadSound(self.sound.unsafeGet())
self.sound = none[raylib.Sound]()

func destroy*(self: Sound) =
self.unload()

func newSound*(soundPath: string): Sound =
result = Sound(
sound: some(raylib.LoadSound(soundPath))
)

func isPlaying*(self: Sound): bool =
self.injectRaylibSound(sound)
result = raylib.IsSoundPlaying(sound)

func pause*(self: Sound) =
self.injectRaylibSound(sound)
raylib.PauseSound(sound)

func play*(self: Sound) =
self.injectRaylibSound(sound)
raylib.PlaySound(sound)

func resume*(self: Sound) =
self.injectRaylibSound(sound)
raylib.ResumeSound(sound)

func stop*(self: Sound) =
self.injectRaylibSound(sound)
raylib.StopSound(sound)

func `volume=`(self: Sound; volume: float32) =
self.injectRaylibSound(sound)
raylib.SetSoundVolume(sound, volume)

func `pitch=`(self: Sound; pitch: float32) =
self.injectRaylibSound(sound)
raylib.SetSoundPitch(sound, pitch)
9 changes: 9 additions & 0 deletions src/komodo/lib/audio/sound_device.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from ../private/raylib import nil

func initialize*() = raylib.InitAudioDevice()

func isReady*(): bool = raylib.IsAudioDeviceReady()

func close*() = raylib.CloseAudioDevice()

func setMasterVolume*(volume: float32) = raylib.SetMasterVolume(volume)
2 changes: 1 addition & 1 deletion src/komodo/lib/graphics/window.nim
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func close*() = raylib.CloseWindow()

func endDraw*() = raylib.EndDrawing()

func initWindow*(screenSize: Vector2; title: string) = raylib.InitWindow(
func initialize*(screenSize: Vector2; title: string) = raylib.InitWindow(
int32(screenSize.x),
int32(screenSize.y),
title,
Expand Down

0 comments on commit ea694c7

Please sign in to comment.