diff --git a/assets/base/shared/sound/master.json b/assets/base/shared/sound/master.json new file mode 100644 index 0000000..2c52df2 --- /dev/null +++ b/assets/base/shared/sound/master.json @@ -0,0 +1,22 @@ +{ + "playlists": { + "menus": [ + "menu_background" + ], + "nighttime": [], + "daytime": [] + }, + "music": [ + { + "name": "menu_background", + "path": "music/untitled-2-revised-extended_mixed.ogg" + } + ], + "sounds": [ + { + "name": "shield_regen", + "type": "sfx", + "path": "sfx/shield_regen.wav" + } + ] +} \ No newline at end of file diff --git a/assets/base/shared/sound/master.yaml b/assets/base/shared/sound/master.yaml deleted file mode 100644 index 75768ad..0000000 --- a/assets/base/shared/sound/master.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -playlists: - - menus: - - nighttime: - - daytime: -music: -sounds: - - - name: shield_regen - type: sfx - path: sfx/shield_regen.wav \ No newline at end of file diff --git a/assets/base/shared/sound/music/untitled-2-revised-extended_mixed.ogg b/assets/base/shared/sound/music/untitled-2-revised-extended_mixed.ogg new file mode 100644 index 0000000..b66fd12 Binary files /dev/null and b/assets/base/shared/sound/music/untitled-2-revised-extended_mixed.ogg differ diff --git a/lib/managers/sound_manager.rb b/lib/managers/sound_manager.rb index 94caa3c..d7f3752 100644 --- a/lib/managers/sound_manager.rb +++ b/lib/managers/sound_manager.rb @@ -7,37 +7,40 @@ class IMICFPS @masters = {} @effects = [] @playlists = {} + @current_playlist = nil + @current_playlist_package = nil + @current_playlist_name = nil + @current_playlist_index = 0 def self.master_volume - 1.0 + window.config.get(:options, :audio, :volume_master) end def self.music_volume - 0.25 * master_volume + window.config.get(:options, :audio, :volume_music) * master_volume end def self.sfx_volume - 0.5 * master_volume + window.config.get(:options, :audio, :volume_sound_effects) * master_volume end def self.load_master(package) return if @masters[package] - yaml = YAML.load_file("#{IMICFPS.assets_path}/#{package}/shared/sound/master.yaml") - @masters[package] = yaml + hash = JSON.parse(File.read("#{IMICFPS.assets_path}/#{package}/shared/sound/master.json")) + @masters[package] = hash end def self.sound(package, name) - if data = sound_data(package, name.to_s) - get_sample("#{IMICFPS.assets_path}/#{package}/shared/sound/#{data['path']}") - else - raise "Missing sound: '#{name}' in package '#{package}'" - end + raise "Missing sound: '#{name}' in package '#{package}'" unless (data = sound_data(package, name.to_s)) + + get_sample("#{IMICFPS.assets_path}/#{package}/shared/sound/#{data['path']}") end def self.sound_data(package, name) load_master(package) - if master = @masters[package] + + if (master = @masters[package]) return master["sounds"].find { |s| s["name"] == name } end @@ -48,8 +51,61 @@ class IMICFPS @effects << klass.new(options) end + def self.music(package, name) + raise "Missing song: '#{name}' in package '#{package}'" unless (data = music_data(package, name.to_s)) + + get_song("#{IMICFPS.assets_path}/#{package}/shared/sound/#{data['path']}") + end + + def self.music_data(package, name) + load_master(package) + + if (master = @masters[package]) + return master["music"].find { |s| s["name"] == name } + end + + nil + end + + def self.playlist_data(package, name) + load_master(package) + + if (master = @masters[package]) + return master.dig("playlists", name.to_s) + end + + nil + end + + def self.play_playlist(package, name) + return if @current_playlist_name == name.to_s + return unless (list = playlist_data(package, name.to_s)) + + @current_playlist = list + @current_playlist_package = package + @current_playlist_name = name.to_s + @current_playlist_index = 0 + + @current_song = music(@current_playlist_package, @current_playlist[@current_playlist_index]) + @current_song.volume = music_volume + @current_song.play + end + def self.update @effects.each { |e| e.update; @effects.delete(e) if e.done? } + + return unless @current_playlist + + if !@current_song&.playing? && music_volume > 0.0 + @current_playlist_index += 1 + @current_playlist_index = 0 if @current_playlist_index >= @current_playlist.size + + @current_song = music(@current_playlist_package, @current_playlist[@current_playlist_index]) + @current_song.play + end + + @current_song&.volume = music_volume + @current_song&.stop if music_volume < 0.1 end end end diff --git a/lib/ui/menu.rb b/lib/ui/menu.rb index 20e5e60..15e03a2 100644 --- a/lib/ui/menu.rb +++ b/lib/ui/menu.rb @@ -93,6 +93,8 @@ class IMICFPS } } ) + + SoundManager.play_playlist("base", "menus") end def draw diff --git a/lib/ui/menus/settings_menu.rb b/lib/ui/menus/settings_menu.rb index 8502cc8..700b077 100644 --- a/lib/ui/menus/settings_menu.rb +++ b/lib/ui/menus/settings_menu.rb @@ -5,12 +5,18 @@ class IMICFPS include CommonMethods def self.set_defaults - if $window.config.get(:options, :audio, :volume_sound).nil? - $window.config[:options, :audio, :volume_sound] = 1.0 + if $window.config.get(:options, :audio, :volume_master).nil? + $window.config[:options, :audio, :volume_master] = 1.0 end + + if $window.config.get(:options, :audio, :volume_sound_effects).nil? + $window.config[:options, :audio, :volume_sound_effects] = 1.0 + end + if $window.config.get(:options, :audio, :volume_music).nil? $window.config[:options, :audio, :volume_music] = 0.7 end + if $window.config.get(:options, :audio, :volume_dialogue).nil? $window.config[:options, :audio, :volume_dialogue] = 0.7 end @@ -77,6 +83,8 @@ class IMICFPS @page_container.clear do send(:"page_#{page}") end + + @page_container.scroll_top = 0 end def page_display @@ -128,20 +136,28 @@ class IMICFPS def page_audio label "Audio", text_size: 50 longest_string = "Dialogue".length - volumes = %i[sound music dialogue] + volumes = %i[master sound_effects music dialogue] - stack do + stack(width: 1.0) do volumes.each do |volume| config_value = window.config.get(:options, :audio, :"volume_#{volume}") - flow do - label volume.to_s.split("_").join(" ").capitalize.ljust(longest_string, " ") - instance_variable_set(:"@volume_#{volume}", slider(range: 0.0..1.0, value: config_value)) - instance_variable_get(:"@volume_#{volume}").subscribe(:changed) do |_sender, value| - instance_variable_get(:"@volume_#{volume}_label").value = format("%03.2f%%", value * 100.0) - window.config[:options, :audio, :"volume_#{volume}"] = value + flow(width: 1.0, margin_bottom: 10) do + flow(width: 0.25) do + label volume.to_s.split("_").map(&:capitalize).join(" ").ljust(longest_string, " ") + end + + flow(width: 0.5) do + instance_variable_set(:"@volume_#{volume}", slider(range: 0.0..1.0, value: config_value, width: 1.0)) + instance_variable_get(:"@volume_#{volume}").subscribe(:changed) do |_sender, value| + instance_variable_get(:"@volume_#{volume}_label").value = format("%03.2f%%", value * 100.0) + window.config[:options, :audio, :"volume_#{volume}"] = value + end + end + + flow(width: 0.25) do + instance_variable_set(:"@volume_#{volume}_label", label(format("%03.2f%%", config_value * 100.0))) end - instance_variable_set(:"@volume_#{volume}_label", label(format("%03.2f%%", config_value * 100.0))) end end end