#--------------------------------------------------------------------------
# * Instance Variables
#--------------------------------------------------------------------------
@fmod_dll = FModEx::DLL.new # The FMOD Ex DLL
@fmod = FModEx::System.new(@fmod_dll) # The global System object
@@fmod_bgm = [] # Array of Sound Effects
@@fmod_bgs = [] # Array of Sound Effects
@@fmod_me = [] # Array of Sound Effects
@@fmod_se = [] # Array of Sound Effects
@@rtp_folder = nil # Name of RTP folder
#--------------------------------------------------------------------------
# * Get Path of RTP Folder From Registry
#--------------------------------------------------------------------------
def self.getRTPFolder
return @@rtp_folder if @@rtp_folder
open_key = Win32API.new('advapi32.dll', 'RegOpenKeyExA', 'LPLLP', 'L')
query_value = Win32API.new('advapi32.dll', 'RegQueryValueExA', 'LPLPPP', 'L')
close_key = Win32API.new('advapi32', 'RegCloseKey', 'L', 'L')
key = 0.chr * 4
# Open a HKEY_LOCAL_MACHINE with KEY_READ attribute and save handle in key
open_key.call(0x80000002, 'Software\Enterbrain\RGSS2\RTP', 0, 0x20019, key)
key = @fmod_dll.unpackInt(key)
type = 0.chr * 4
size = 0.chr * 4
# Read RTP folder to use from setting in Game.ini
rtp = self.read_ini("RTP")
# Query to get string size
query_value.call(key, rtp, 0, type, 0, size)
data = ' ' * @fmod_dll.unpackInt(size)
# Query the string value itself using size
query_value.call(key, rtp, 0, type, data, size)
@@rtp_folder = data.chop
close_key.call(key)
# Convert the addres to the RGSS standard
@@rtp_folder.gsub!(/\\/, "/")
@@rtp_folder += "/" if @@rtp_folder[-1] != "/"
return @@rtp_folder
end
#--------------------------------------------------------------------------
# * Read data from ini file
# variable : Data to read
# filename : Name without extension
#--------------------------------------------------------------------------
def self.read_ini(variable,filename="Game")
reg = /^#{variable}=(.*)$/
File.foreach(filename+'.ini') { |line| break($1) if line =~ reg }
end
#--------------------------------------------------------------------------
# * Return Proper File Name (With Extensions)
# name : Name of the file
# extensions : Extensions to add to file name
#--------------------------------------------------------------------------
def self.checkExtensions(name, extensions)
if FileTest.exist?(name)
return name
end
# Add extension if needed
extensions.each do |ext|
if FileTest.exist?(name + '.' + ext)
return name + '.' + ext
end
end
# File doesn't exist
return name
end
#--------------------------------------------------------------------------
# * Get Valid File Name
# name : Name of the file
#--------------------------------------------------------------------------
def self.selectBGMFilename(name, likeRTP = true)
return Dir.glob(name+'.*')[0] || Dir.glob(name)[0] ||
Dir.glob(self.getRTPFolder+name+'.*')[0] ||
Dir.glob(self.getRTPFolder+name)[0] if likeRTP
# See if file exists in game folder
localname = self.checkExtensions(name, FModEx::FMOD_FILE_TYPES)
if FileTest.exist?(localname)
return localname
end
# See if file exists in RTP
commonname = self.checkExtensions(self.getRTPFolder + name, FModEx::FMOD_FILE_TYPES)
if FileTest.exist?(commonname)
return commonname
end
# An invalid name was provided
raise name
end
#--------------------------------------------------------------------------
# * Play a Sound File Then Return it
# name : Name of the file
# volume : Channel volume
# pitch : Channel frequency
# position : Starting position in milliseconds
# looping : Does the sound loop?
# streaming : Stream sound or load whole thing to memory?
#--------------------------------------------------------------------------
def self.play(name, volume, pitch, position, looping, streaming)
# Get a valid file name
filename = self.selectBGMFilename(name)
# Create Sound or Stream and set initial values
sound = streaming ? @fmod.createStream(filename) : @fmod.createSound(filename)
sound.loopMode = looping ? FModEx::FMOD_LOOP_NORMAL : FModEx::FMOD_LOOP_OFF
channel = sound.play
volume = volume * 1.0
pitch = pitch * 1.0
file_length = sound.length(FModEx::FMOD_DEFAULT_UNIT)
sound_file = SoundFile.new(filename, sound, channel, volume,
pitch, looping, streaming, file_length)
sound_file.channel.volume = volume / 100.0
sound_file.channel.frequency = sound_file.channel.frequency * pitch / 100
sound_file.channel.position = position
self.play_operations(sound_file)
return sound_file
end
#--------------------------------------------------------------------------
# * Do something on new Sound File
#--------------------------------------------------------------------------
def self.play_operations(sound_file)
# alias this if you want to do something on the newly played files :)
end
#--------------------------------------------------------------------------
# * Replay of Sound File
#--------------------------------------------------------------------------
def self.replay(sound_file, volume = 100, pitch = 100, position = 0, reset = false)
self.set_volume(sound_file, volume)
self.set_pitch(sound_file, pitch)
self.set_position(sound_file, position) if position != 0 || (position == 0 && reset)
end
#--------------------------------------------------------------------------
# * Stop and Dispose of Sound File
#--------------------------------------------------------------------------
def self.stop(sound_file)
unless sound_file and sound_file.channel
return
end
# Stop channel, then clear variables and dispose of bgm
sound_file.channel.stop
sound_file.channel = nil
sound_file.sound.dispose
end
#--------------------------------------------------------------------------
# * Return Length in Milliseconds
#--------------------------------------------------------------------------
def self.get_length(sound_file, unit = FModEx::FMOD_DEFAULT_UNIT)
return sound_file.length(unit)
end
#--------------------------------------------------------------------------
# * Check if Another Sound File is Playing
#--------------------------------------------------------------------------
def self.already_playing?(sound_file, name, position = 0)
# Get a valid file name
filename = self.selectBGMFilename(name)
if (sound_file)
# If the same sound file is already playing don't play it again
if (sound_file.name == filename and position == 0)
return true
end
# If another sound file is playing, stop it
if sound_file.channel
self.stop(sound_file)
end
end
# No sound file is playing or it was already stopped
return false
end
#--------------------------------------------------------------------------
# * Check if this Sound File is Playing
#--------------------------------------------------------------------------
def self.playing_this?(sound_file, name)
if (sound_file)
if (sound_file.name == name)
return true
end
end
return false
end
#--------------------------------------------------------------------------
# * Check if Sound File is Playing
#--------------------------------------------------------------------------
def self.playing?(sound_file)
unless sound_file and sound_file.channel
return false
end
return sound_file.channel.playing?
end
#--------------------------------------------------------------------------
# * Get Current Sound File Playing Position
#--------------------------------------------------------------------------
def self.get_position(sound_file)
unless sound_file and sound_file.channel
return 0
end
return sound_file.channel.position
end
#--------------------------------------------------------------------------
# * Seek to a New Sound File Playing Position
#--------------------------------------------------------------------------
def self.set_position(sound_file, new_pos)
unless sound_file and sound_file.channel
return
end
sound_file.channel.position = new_pos
end
#--------------------------------------------------------------------------
# * Get Current Sound File Volume
#--------------------------------------------------------------------------
def self.get_volume(sound_file)
unless sound_file
return 0
end
return sound_file.volume
end
#--------------------------------------------------------------------------
# * Set Sound File Volume
#--------------------------------------------------------------------------
def self.set_volume(sound_file, volume)
unless sound_file and sound_file.channel
return
end
sound_file.volume = volume * 1.0
sound_file.channel.volume = volume / 100.0
end
#--------------------------------------------------------------------------
# * Set Sound File Mute
#--------------------------------------------------------------------------
def self.set_mute(sound_file)
unless sound_file and sound_file.channel
return
end
sound_file.channel.mute
end
#--------------------------------------------------------------------------
# * Set Sound File Unmute
#--------------------------------------------------------------------------
def self.set_unmute(sound_file)
unless sound_file and sound_file.channel
return
end
sound_file.channel.unmute
end
#--------------------------------------------------------------------------
# * Get Current Sound File Pitch
#--------------------------------------------------------------------------
def self.get_pitch(sound_file)
unless sound_file
return 0
end
return sound_file.pitch
end
#--------------------------------------------------------------------------
# * Set Sound File Pitch
#--------------------------------------------------------------------------
def self.set_pitch(sound_file, pitch)
unless sound_file and sound_file.channel
return
end
sound_file.pitch = pitch * 1.0
sound_file.channel.frequency = sound_file.channel.frequency * pitch / 100.0
end
#--------------------------------------------------------------------------
# * Get Current Sound File Pan
#--------------------------------------------------------------------------
def self.get_pan(sound_file)
unless sound_file and sound_file.channel
return 0
end
return sound_file.channel.pan
end
#--------------------------------------------------------------------------
# * Set Sound File Pan
#--------------------------------------------------------------------------
def self.set_pan(sound_file, pan)
unless sound_file and sound_file.channel
return
end
sound_file.channel.pan = pan
end
#--------------------------------------------------------------------------
# * Set Loop Points
# first : Loop start point in milliseconds
# second : Loop end point in milliseconds (-1 for file end)
# unit : FMOD_TIMEUNIT for points
#--------------------------------------------------------------------------
def self.set_loop_points(sound_file, first, second, unit = FModEx::FMOD_DEFAULT_UNIT)
unless sound_file and sound_file.channel
return
end
# If second is -1 then set loop end to the file end
if second == -1
second = sound_file.length - 1
end
# Set loop points and reflush stream buffer
sound_file.channel.sound.setLoopPoints(first, second, unit)
sound_file.channel.position = sound_file.channel.position
return sound_file
end
#--------------------------------------------------------------------------
# * Play BGM (or ME)
# name : Name of the file
# volume : Channel volume
# pitch : Channel frequency
# position : Starting position in milliseconds
# looping : Does the BGM loop?
#--------------------------------------------------------------------------
def self.bgm_play(name, volume, pitch, c, position = 0, looping = true)
al_pl = self.already_playing?(@@fmod_bgm[c], name, position)
self.bgm_set_volume(volume, c) if al_pl
return if al_pl
# Now play the new BGM as a stream
@@fmod_bgm[c] = self.play(name, volume, pitch, position, looping, true)
end
#--------------------------------------------------------------------------
# * Stop and Dispose of BGM
#--------------------------------------------------------------------------
def self.bgm_stop(c)
self.stop(@@fmod_bgm[c])
@@fmod_bgm[c] = nil
end
#--------------------------------------------------------------------------
# * Return BGM Length in Milliseconds
#--------------------------------------------------------------------------
def self.bgm_length(c)
self.get_length(@@fmod_bgm[c])
end
#--------------------------------------------------------------------------
# * Check if a BGM is Playing
#--------------------------------------------------------------------------
def self.bgm_playing?(c)
return self.playing?(@@fmod_bgm[c])
end
#--------------------------------------------------------------------------
# * Get Current BGM Playing Position
#--------------------------------------------------------------------------
def self.bgm_position(c)
return self.get_position(@@fmod_bgm[c])
end
#--------------------------------------------------------------------------
# * Seek to New BGM Playing Position
#--------------------------------------------------------------------------
def self.bgm_set_position(new_pos, c)
self.set_position(@@fmod_bgm[c], new_pos)
end
#--------------------------------------------------------------------------
# * Get Current BGM Volume
#--------------------------------------------------------------------------
def self.bgm_volume(c)
return self.get_volume(@@fmod_bgm[c])
end
#--------------------------------------------------------------------------
# * Set BGM Volume
#--------------------------------------------------------------------------
def self.bgm_set_volume(volume, c)
self.set_volume(@@fmod_bgm[c], volume)
end
#--------------------------------------------------------------------------
# * Set BGM Mute
#--------------------------------------------------------------------------
def self.bgm_set_mute(c)
self.set_mute(@@fmod_bgm[c])
end
#--------------------------------------------------------------------------
# * Set BGM Unmute
#--------------------------------------------------------------------------
def self.bgm_set_unmute(c)
self.set_unmute(@@fmod_bgm[c])
end
#--------------------------------------------------------------------------
# * Get Current BGM Pan
#--------------------------------------------------------------------------
def self.bgm_pan(c)
return self.get_pan(@@fmod_bgm[c])
end
#--------------------------------------------------------------------------
# * Set BGM Pan
#--------------------------------------------------------------------------
def self.bgm_set_pan(pan, c)
self.set_pan(@@fmod_bgm[c], pan)
end
#--------------------------------------------------------------------------
# * Set ME Volume
#--------------------------------------------------------------------------
def self.me_set_volume(volume, c)
self.set_volume(@@fmod_me[c], volume)
end
#--------------------------------------------------------------------------
# * Set ME Mute
#--------------------------------------------------------------------------
def self.me_set_mute(c)
self.set_mute(@@fmod_me[c])
end
#--------------------------------------------------------------------------
# * Set ME Unmute
#--------------------------------------------------------------------------
def self.me_set_unmute(c)
self.set_unmute(@@fmod_me[c])
end
#--------------------------------------------------------------------------
# * Get Current ME Pan
#--------------------------------------------------------------------------
def self.me_pan(c)
return self.get_pan(@@fmod_me[c])
end
#--------------------------------------------------------------------------
# * Set ME Pan
#--------------------------------------------------------------------------
def self.me_set_pan(pan, c)
self.set_pan(@@fmod_me[c], pan)
end
#--------------------------------------------------------------------------
# * Set Loop Points
# first : Loop start point in milliseconds
# second : Loop end point in milliseconds
# unit : FMOD_TIMEUNIT for points
#--------------------------------------------------------------------------
def self.bgm_set_loop_points(first, second, c, unit = FModEx::FMOD_DEFAULT_UNIT)
@@fmod_bgm[c] = self.set_loop_points(@@fmod_bgm[c], first, second, unit)
end
#--------------------------------------------------------------------------
# * Play BGS
# name : Name of the file
# volume : Channel volume
# pitch : Channel frequency
# position : Starting position in milliseconds
# looping : Does the BGS loop?
#--------------------------------------------------------------------------
def self.bgs_play(name, volume, pitch, c, position = 0, looping = true)
al_pl = self.already_playing?(@@fmod_bgs[c], name, position)
self.bgs_set_volume(volume, c) if al_pl
return if al_pl
# Now play the new BGS as a stream
@@fmod_bgs[c] = self.play(name, volume, pitch, position, looping, true)
end
#--------------------------------------------------------------------------
# * Stop and Dispose of BGS
#--------------------------------------------------------------------------
def self.bgs_stop(c)
self.stop(@@fmod_bgs[c])
@@fmod_bgs[c] = nil
end
#--------------------------------------------------------------------------
# * Return BGS Length in Milliseconds
#--------------------------------------------------------------------------
def self.bgm_length(c)
self.get_length(@@fmod_bgs[c])
end
#--------------------------------------------------------------------------
# * Check if a BGS is Playing
#--------------------------------------------------------------------------
def self.bgs_playing?(c)
return self.playing?(@@fmod_bgs[c])
end
#--------------------------------------------------------------------------
# * Get Current BGS Playing Position
#--------------------------------------------------------------------------
def self.bgs_position(c)
return self.get_position(@@fmod_bgs[c])
end
#--------------------------------------------------------------------------
# * Seek to New BGS Playing Position
#--------------------------------------------------------------------------
def self.bgs_set_position(new_pos, c)
self.set_position(@@fmod_bgs[c], new_pos)
end
#--------------------------------------------------------------------------
# * Get Current BGS Volume
#--------------------------------------------------------------------------
def self.bgs_volume(c)
return self.get_volume(@@fmod_bgs[c])
end
#--------------------------------------------------------------------------
# * Set BGS Volume
#--------------------------------------------------------------------------
def self.bgs_set_volume(volume, c)
self.set_volume(@@fmod_bgs[c], volume)
end
#--------------------------------------------------------------------------
# * Set BGS Mute
#--------------------------------------------------------------------------
def self.bgs_set_mute(c)
self.set_mute(@@fmod_bgs[c])
end
#--------------------------------------------------------------------------
# * Set BGS Unmute
#--------------------------------------------------------------------------
def self.bgs_set_unmute(c)
self.set_unmute(@@fmod_bgs[c])
end
#--------------------------------------------------------------------------
# * Get Current BGS Pan
#--------------------------------------------------------------------------
def self.bgs_pan(c)
return self.get_pan(@@fmod_bgs[c])
end
#--------------------------------------------------------------------------
# * Set BGS Pan
#--------------------------------------------------------------------------
def self.bgs_set_pan(pan, c)
self.set_pan(@@fmod_bgs[c], pan)
end
#--------------------------------------------------------------------------
# * Set Loop Points
# first : Loop start point in milliseconds
# second : Loop end point in milliseconds
# unit : FMOD_TIMEUNIT for points
#--------------------------------------------------------------------------
def self.bgs_set_loop_points(first, second, c, unit = FModEx::FMOD_DEFAULT_UNIT)
@@fmod_bgs[c] = self.set_loop_points(@@fmod_bgs[c], first, second, unit)
end
#--------------------------------------------------------------------------
# * Play SE
# name : Name of the file
# volume : Channel volume
# pitch : Channel frequency
#--------------------------------------------------------------------------
def self.se_play(name, volume, pitch, c)
if (@@fmod_se[c] ||= []).size > @fmod.maxChannels
se = @@fmod_se[c].shift
self.stop(se)
end
# Load SE into memory and play it
@@fmod_se[c] << self.play(name, volume, pitch, 0, false, false)
end
#--------------------------------------------------------------------------
# * Stop and Dispose of all SEs
#--------------------------------------------------------------------------
def self.se_stop(c)
for se in (@@fmod_se[c] ||= [])
self.stop(se)
end
@@fmod_se[c].clear
end
#--------------------------------------------------------------------------
# * Set SE Volume
#--------------------------------------------------------------------------
def self.se_set_volume(volume, c)
for se in (@@fmod_se[c] ||= [])
self.set_volume(se, volume)
end
end
#--------------------------------------------------------------------------
# * Set SE Mute
#--------------------------------------------------------------------------
def self.se_set_mute(c)
for se in (@@fmod_se[c] ||= [])
self.set_mute(se)
end
end
#--------------------------------------------------------------------------
# * Set SE Unmute
#--------------------------------------------------------------------------
def self.se_set_unmute(c)
for se in (@@fmod_se[c] ||= [])
self.set_unmute(se)
end
end
#--------------------------------------------------------------------------
# * Get Pan of one of the Current SEs
#--------------------------------------------------------------------------
def self.se_pan(c, n)
return self.get_pan(@@fmod_se[c][n])
end
#--------------------------------------------------------------------------
# * Set Pan for one of the Current SEs
#--------------------------------------------------------------------------
def self.se_set_pan(pan, c, n)
self.set_pan(@@fmod_se[c][n], pan)
end
#--------------------------------------------------------------------------
# * Get Rid of Non-Playing SEs
#--------------------------------------------------------------------------
def self.se_clean(c)
for se in (@@fmod_se[c] ||= [])
unless self.playing?(se)
self.stop(se)
@@fmod_se[c].delete(se)
end
end
end
#--------------------------------------------------------------------------
# * Check if There's Some SE in SE Array
#--------------------------------------------------------------------------
def self.se_list_empty?(c)
return (@@fmod_se[c] ||= []).empty?
end
#--------------------------------------------------------------------------
# * Dispose of Everything
#--------------------------------------------------------------------------
def self.dispose
self.stop_all
@fmod.dispose
end
#--------------------------------------------------------------------------
# * Stop Everything
#--------------------------------------------------------------------------
def self.stop_all
for c in 1...APU::MAX_CHANNELS
self.bgm_stop(c)
self.bgs_stop(c)
self.se_stop(c)
end
end
#==============================================================================
# ** Audio
#------------------------------------------------------------------------------
# The module that carries out music and sound processing.
#==============================================================================
module Audio
#--------------------------------------------------------------------------
# * Constants
#--------------------------------------------------------------------------
BGM_FADE_IN_INCREMENT = 5 # BGM volume incremented 0.2 seconds
#--------------------------------------------------------------------------
# * Instance Variables
#--------------------------------------------------------------------------
@@bgm_fading_out = []#false # BGM started fading out
@@bgm_fade_decrement = []#0.0 # BGM volume decremented each update
@@bgs_fading_out = []#false # BGS started fading out
@@bgs_fade_decrement = []#0.0 # BGS volume decremented each update
@@me_fading_out = []#false # ME started fading out
@@me_fade_decrement = []#0.0 # ME volume decremented each update
@@me_playing = []#false # Is some ME playing?
@@playing_bgm = []#nil # BGM currently being played
@@next_bgm = []#nil # The BGM to be played after fading out
@@next_bgm_position = []#0 # Starting position of next bgm
@@next_bgs = []#nil # The BGS to be played after fading out
@@next_bgs_position = []#0 # Starting position of next bgm
@@next_me = []#nil # The ME to be played after fading
@@memorized_bgm = []
@@memorized_bgm_position = []
@@bgm_fading_in = []
#--------------------------------------------------------------------------
# * Starts BGM Playback
# name : Name of the file
# volume : Channel volume
# pitch : Channel frequency
# position : Starting position in milliseconds
#--------------------------------------------------------------------------
def Audio.bgm_play(filename, volume, pitch, c, position = 0,
fade_in = false)
if @@bgm_fading_out[c] and !fade_in
@@next_bgm[c] = RPG::AudioFile.new(filename, volume, pitch)
@@next_bgm_position[c] = position
return
end
start_volume = volume
if fade_in
@@bgm_target_volume[c] = volume unless @@bgm_fading_in[c]
@@bgm_fading_in[c] = true
start_volume = 0
end
@@bgm_fading_out[c] = false
# If a ME is playing we wait until it's over before playing BGM
unless @@me_playing[c]
FMod::bgm_play(filename, start_volume, pitch, c, position)
end
@@playing_bgm[c] = RPG::AudioFile.new(filename, volume, pitch)
@@memorized_bgm[c] = @@playing_bgm[c]
@@memorized_bgm_position[c] = position
end
#--------------------------------------------------------------------------
# * Stops BGM Playback
#--------------------------------------------------------------------------
def Audio.bgm_stop(c)
@@memorized_bgm[c] = nil
@@playing_bgm[c] = nil
@@bgm_fading_in[c] = false
@@bgm_fading_out[c] = false
# MEs are internally BGMs, but are stopped with me_stop instead
if @@me_playing[c]
return
end
FMod::bgm_stop(c)
end
#--------------------------------------------------------------------------
# * Starts BGM fadeout.
# time : Length of the fadeout in milliseconds.
#--------------------------------------------------------------------------
def Audio.bgm_fade(time, c)
return if @@me_playing[c] or !FMod::bgm_playing?(c)
@@bgm_fading_out[c] = true
time = time / 1000
@@bgm_fade_decrement[c] = FMod::bgm_volume(c) / (time * 10)
end
#--------------------------------------------------------------------------
# * Get BGM Position
#--------------------------------------------------------------------------
def Audio.bgm_pos(c)
FMod::bgm_position(c)
end
#--------------------------------------------------------------------------
# * Starts BGS Playback
# name : Name of the file
# volume : Channel volume
# pitch : Channel frequency
# position : Starting position in milliseconds
#--------------------------------------------------------------------------
def Audio.bgs_play(filename, volume, pitch, c, position = 0)
if @@bgs_fading_out[c]
@@next_bgs[c] = RPG::AudioFile.new(filename, volume, pitch)
@@next_bgs_position[c] = position
return
end
FMod::bgs_play(filename, volume, pitch, c, position)
end
#--------------------------------------------------------------------------
# * Stops BGS Playback
#--------------------------------------------------------------------------
def Audio.bgs_stop(c)
FMod::bgs_stop(c)
@@bgs_fading_out[c] = false
end
#--------------------------------------------------------------------------
# * Starts BGS fadeout.
# time : Length of the fadeout in milliseconds.
#--------------------------------------------------------------------------
def Audio.bgs_fade(time, c)
return unless FMod::bgs_playing?(c)
@@bgs_fading_out[c] = true
time = time / 1000
@@bgs_fade_decrement[c] = FMod::bgs_volume(c) / (time * 10)
end
#--------------------------------------------------------------------------
# * Get BGS Position
#--------------------------------------------------------------------------
def Audio.bgs_pos(c)
FMod::bgs_position(c)
end
#--------------------------------------------------------------------------
# * Starts ME Playback
# name : Name of the file
# volume : Channel volume
# pitch : Channel frequency
#--------------------------------------------------------------------------
def Audio.me_play(filename, volume, pitch, c)
if @@me_fading_out[c]
@@next_me[c] = RPG::AudioFile.new(filename, volume, pitch)
return
end
if @@bgm_fading_out[c]
self.bgm_stop(c)
end
# Memorize playing bgm
if @@playing_bgm[c] and !@@me_playing[c]
bgm = @@playing_bgm[c]
@@playing_bgm[c] = RPG::AudioFile.new(bgm.name, FMod::bgm_volume(c), bgm.pitch)
@@memorized_bgm[c] = @@playing_bgm[c]
@@memorized_bgm_position[c] = FMod::bgm_position(c)
end
@@me_playing[c] = true
FMod::bgm_play(filename, volume, pitch, c, 0, false)
end
#--------------------------------------------------------------------------
# * Stops ME Playback
#--------------------------------------------------------------------------
def Audio.me_stop(c)
return unless @@me_playing[c]
@@me_playing[c] = false
@@me_fading_out[c] = false
# Play memorized bgm, fading in
if @@memorized_bgm[c] and !@@bgm_fading_out[c]
bgm = @@memorized_bgm[c]
self.bgm_play(bgm.name, bgm.volume, bgm.pitch, @@memorized_bgm_position[c], true)
else
self.bgm_stop(c)
end
end
#--------------------------------------------------------------------------
# * Starts ME fadeout.
# time : Length of the fadeout in milliseconds.
#--------------------------------------------------------------------------
def Audio.me_fade(time, c)
return unless FMod::bgm_playing?(c)
@@me_fading_out[c] = true
time = time / 1000
@@bgm_fade_decrement[c] = FMod::bgm_volume(c) / (time * 10)
end
#--------------------------------------------------------------------------
# * Starts SE Playback
# name : Name of the file
# volume : Channel volume
# pitch : Channel frequency
#--------------------------------------------------------------------------
def Audio.se_play(filename, volume, pitch, c)
FMod::se_play(filename, volume, pitch, c)
end
#--------------------------------------------------------------------------
# * Stops SE Playback
#--------------------------------------------------------------------------
def Audio.se_stop(c)
FMod::se_stop(c)
end
#--------------------------------------------------------------------------
# * Check whether in F1 settings music and/or sounds are disabled
#--------------------------------------------------------------------------
def Audio.check_sound
open_key = Win32API.new('advapi32.dll', 'RegOpenKeyExA', 'LPLLP', 'L')
query_value = Win32API.new('advapi32.dll', 'RegQueryValueExA', 'LPLPPP', 'L')
close_key = Win32API.new('advapi32', 'RegCloseKey', 'L', 'L')
key = 0.chr * 4
# Open a HKEY_CURRENT_USER with KEY_READ attribute and save handle in key
open_key.call(0x80000001, 'Software\Enterbrain\RGSS2', 0, 0x20019, key)
key = key.unpack('l')[0]
type = 0.chr * 4
size = 0.chr * 4
# Query to get string size
query_value.call(key, "PlayMusic", 0, type, 0, size)
data = ' ' * size.unpack('l')[0]
# Query the string value itself using size
query_value.call(key, "PlayMusic", 0, type, data, size)
pm = data[0] != 0
# Query to get string size
query_value.call(key, "PlaySound", 0, type, 0, size)
data = ' ' * size.unpack('l')[0]
# Query the string value itself using size
query_value.call(key, "PlaySound", 0, type, data, size)
ps = data[0] != 0
close_key.call(key)
if (@@last_music_play_state ||= !pm) != pm
for c in 1...APU::MAX_CHANNELS
FMod::bgm_set_mute(c) if !pm
FMod::me_set_mute(c) if !pm
FMod::bgm_set_unmute(c) if pm
FMod::me_set_unmute(c) if pm
end
@@last_music_play_state = pm
end
if (@@last_sound_play_state ||= !ps) != ps
for c in 1...APU::MAX_CHANNELS
FMod::bgs_set_mute(c) if !ps
FMod::se_set_mute(c) if !ps
FMod::bgs_set_unmute(c) if ps
FMod::se_set_unmute(c) if ps
end
@@last_sound_play_state = ps
end
end
#--------------------------------------------------------------------------
# * Update ME Playback, SE Disposal and Fading, Called Each Frame
#--------------------------------------------------------------------------
def Audio.update
self.check_sound if APU::READ_F1_SETTINGS
for c in 1...APU::MAX_CHANNELS
# Stop ME when it's over (and continue playing BGM)
if @@me_playing[c]
unless FMod::bgm_playing?(c)
self.me_stop(c)
end
end
# Remove any finished SEs
unless FMod::se_list_empty?(c)
FMod::se_clean(c)
end
if @@bgm_fading_in[c]
# Stop fading when target is reached, otherwise increase volume
if FMod::bgm_volume(c) >= @@bgm_target_volume[c]
@@bgm_fading_in[c] = false
else
current_volume = FMod::bgm_volume(c) + BGM_FADE_IN_INCREMENT
FMod::bgm_set_volume(current_volume, c)
end
end
if FMod::bgm_playing?(c) and @@bgm_fading_out[c] and
!@@me_playing[c]
if FMod::bgm_volume(c) <= 0
@@bgm_fading_out[c] = false
self.bgm_stop(c)
# If another BGM played while fading out, play it (most recent)
if @@next_bgm[c]
self.bgm_play(@@next_bgm[c].name, @@next_bgm[c].volume,
@@next_bgm[c].pitch, c, @@next_bgm_position[c])
@@next_bgm[c] = nil
end
else
current_volume = FMod::bgm_volume(c) - @@bgm_fade_decrement[c]
FMod::bgm_set_volume(current_volume, c)
end
end
if FMod::bgs_playing?(c) and @@bgs_fading_out[c]
if FMod::bgs_volume(c) <= 0
@@bgs_fading_out[c] = false
self.bgs_stop(c)
# If another BGS played while fading out, play it (most recent)
if @@next_bgs[c]
self.bgs_play(@@next_bgs[c].name, @@next_bgs[c].volume,
@@next_bgs[c].pitch, c, @@next_bgs_position[c])
@@next_bgs[c] = nil
end
else
current_volume = FMod::bgs_volume(c) - @@bgs_fade_decrement[c]
FMod::bgs_set_volume(current_volume, c)
end
end
if FMod::bgm_playing?(c) and @@me_fading_out[c]
if FMod::bgm_volume(c) <= 0
# If another ME played while fading out, play it (most recent)
if @@next_me[c]
self.me_play(@@next_me[c].name, @@next_me[c].volume, @@next_me[c].pitch, c)
@@next_me[c] = nil
else
@@me_fading_out[c] = false
self.me_stop(c)
end
else
current_volume = FMod::bgm_volume(c) - @@bgm_fade_decrement[c]
FMod::bgm_set_volume(current_volume, c)
end
end
end
end
end
end
# Addition to let the DSP effects work.
module FMod
def self.addDSP(sound_file, type)
return -1 if type <= 0
unless sound_file and sound_file.channel
return -1
end
return sound_file.channel.addDSP(type)
end
def self.bgm_addDSP(c, type)
return nil if c <= 0
return nil unless @@fmod_bgm[c]
return @@fmod_bgm[c].channel.DSP(self.addDSP(@@fmod_bgm[c], type))
end
def self.bgs_addDSP(c, type)
return nil if c <= 0
return nil unless @@fmod_bgs[c]
return @@fmod_bgs[c].channel.DSP(self.addDSP(@@fmod_bgs[c], type))
end
def self.me_addDSP(c, type)
return nil if c <= 0
return nil unless @@fmod_me[c]
return @@fmod_me[c].channel.DSP(self.addDSP(@@fmod_me[c], type))
end
def self.se_total(c)
return 0 if c <= 0
(@@fmod_se[c] ||= []).size
end
def self.se_addDSP(n, c, type)
return nil if c <= 0
return nil unless @@fmod_se[c][n]
return @@fmod_se[c][n].channel.DSP(self.addDSP(@@fmod_se[c][n], type))
end
def self.removeDSP(sound_file, id)
unless sound_file and sound_file.channel
return
end
sound_file.channel.removeDSP(id)
end
def self.bgm_removeDSP(c, id)
self.removeDSP(@@fmod_bgm[c], id)
end
def self.bgs_removeDSP(c, id)
self.removeDSP(@@fmod_bgs[c], id)
end
def self.me_removeDSP(c, id)
self.removeDSP(@@fmod_me[c], id)
end
def self.se_removeDSP(c, id)
for se in (@@fmod_se[c] ||= [])
self.removeDSP(se, id)
end
end
def self.bgm_DSP(c)
return 0 if c <= 0
return 0 unless @@fmod_bgm[c]
return @@fmod_bgm[c].channel.dsps.size
end
def self.bgs_DSP(c)
return 0 if c <= 0
return 0 unless @@fmod_bgs[c]
return @@fmod_bgs[c].channel.dsps.size
end
def self.me_DSP(c)
return 0 if c <= 0
return 0 unless @@fmod_me[c]
return @@fmod_me[c].channel.dsps.size
end
def self.se_DSP(c)
return 0 if c <= 0
return 0 unless @@fmod_se[c]
return 0 unless @@fmod_se[c][0]
return @@fmod_se[c][0].channel.dsps.size
end
def self.setParameter(sound_file, dsp_id, param_id, value)
unless sound_file and sound_file.channel
return
end
dsp = sound_file.channel.DSP(dsp_id)
return if dsp.nil?
dsp.setParameter(param_id, value)
end
def self.bgm_setParameter(c, dsp_id, param_id, value)
self.setParameter(@@fmod_bgm[c], dsp_id, param_id, value)
end
def self.bgs_setParameter(c, dsp_id, param_id, value)
self.setParameter(@@fmod_bgs[c], dsp_id, param_id, value)
end
def self.me_setParameter(c, dsp_id, param_id, value)
self.setParameter(@@fmod_me[c], dsp_id, param_id, value)
end
def self.se_setParameter(c, dsp_id, param_id, value)
for se in (@@fmod_se[c] ||= [])
self.setParameter(se, dsp_id, param_id, value)
end
end
def self.getParameter(sound_file, dsp_id, param_id = 0)
unless sound_file and sound_file.channel
return - 1
end
dsp = sound_file.channel.DSP(dsp_id)
return -1 if dsp.nil?
dsp.getParameter(param_id)
end
def self.bgm_getParameter(c, dsp_id, param_id = 0)
self.getParameter(@@fmod_bgm[c], dsp_id, param_id)
end
def self.bgs_getParameter(c, dsp_id, param_id = 0)
self.getParameter(@@fmod_bgs[c], dsp_id, param_id)
end
def self.me_getParameter(c, dsp_id, param_id = 0)
self.getParameter(@@fmod_me[c], dsp_id, param_id)
end
def self.se_getParameter(c, dsp_id, param_id = 0)
self.getParameter(@@fmod_se[c][0], dsp_id, param_id)
end
def self.getNumParameters(sound_file, dsp_id)
unless sound_file and sound_file.channel
return 0
end
dsp = sound_file.channel.DSP(dsp_id)
return 0 if dsp.nil?
dsp.getNumParameters
end
def self.bgm_getNumParameters(c, dsp_id)
self.getNumParameters(@@fmod_bgm[c], dsp_id)
end
def self.bgs_getNumParameters(c, dsp_id)
self.getNumParameters(@@fmod_bgs[c], dsp_id)
end
def self.me_getNumParameters(c, dsp_id)
self.getNumParameters(@@fmod_me[c], dsp_id)
end
def self.se_getNumParameters(c, dsp_id)
self.getNumParameters(@@fmod_se[c][0], dsp_id)
end
def self.getType(sound_file, dsp_id)
unless sound_file and sound_file.channel
return 0
end
dsp = sound_file.channel.DSP(dsp_id)
return 0 if dsp.nil?
dsp.getType
end
def self.bgm_getType(c, dsp_id)
self.getType(@@fmod_bgm[c], dsp_id)
end
def self.bgs_getType(c, dsp_id)
self.getType(@@fmod_bgs[c], dsp_id)
end
def self.me_getType(c, dsp_id)
self.getType(@@fmod_me[c], dsp_id)
end
def self.se_getType(c, dsp_id)
self.getType(@@fmod_se[c][0], dsp_id)
end
def self.getDSPTypeByName(effect)
return FModEx::FMOD_DSP_TYPES.index(effect.upcase)
end
def self.addEffect(dsp, type, *params)
return if dsp.nil? || type.nil? || type == 0
max_p = dsp.getNumParameters
if params.size > max_p
p "This effect requires max #{max_p.to_s} arguments, you passed #{params.size.to_s}."
p "Default will be used."
return
end
id = 0
for par in params
dsp.setParameter(id, par) if par != nil
id += 1
end
end
module Audio
def self.bgm_add_effect(effect, c, *params)
t = FMod::getDSPTypeByName(effect)
FMod::addEffect(dsp = FMod::bgm_addDSP(c, t), t, *params)
return dsp
end
def self.bgs_add_effect(effect, c, *params)
t = FMod::getDSPTypeByName(effect)
FMod::addEffect(dsp = FMod::bgs_addDSP(c, t), t, *params)
return dsp
end
def self.me_add_effect(effect, c, *params)
t = FMod::getDSPTypeByName(effect)
FMod::addEffect(dsp = FMod::me_addDSP(c, t), t, *params)
return dsp
end
def self.se_add_effect(effect, c, *params)
t = FMod::getDSPTypeByName(effect)
for n in 0...FMod::se_total(c)
FMod::addEffect(FMod::se_addDSP(n, c, t), t, *params)
end
end
end
end
# Methods: (following comments are for searching purposes)
class << Audio
#module Audio#def self.bgm_play() <- aliased
#module Audio#def self.bgm_stop() <- aliased
#module Audio#def self.bgm_fade() <- aliased
#module Audio#def self.bgs_play() <- aliased
#module Audio#def self.bgs_stop() <- aliased
#module Audio#def self.bgs_fade() <- aliased
#module Audio#def self.me_play() <- aliased
#module Audio#def self.me_stop() <- aliased
#module Audio#def self.me_fade() <- aliased
#module Audio#def self.se_play() <- aliased
#module Audio#def self.se_stop() <- aliased
["bgm_play","bgm_stop","bgm_fade",#"bgm_pos",
"bgs_play","bgs_stop","bgs_fade",#"bgs_pos",
"me_play","me_stop","me_fade",
"se_play","se_stop"].each { |m|
new = (m+"_b4_apu").to_sym
old = m.to_sym
alias_method(new, old) unless method_defined?(new)
define_method(old){ |*args|
if $game_variables[APU::CURRENT_CHANNEL_VARIABLE] == 0 || APU::CURRENT_CHANNEL_VARIABLE > APU::MAX_CHANNELS
self.method(new).call(*args)
else
args << $game_variables[APU::CURRENT_CHANNEL_VARIABLE]
FMod::Audio.method(old).call(*args)
end
}
}
end
# Let's update in Scene_Base!
class Scene_Base
alias_method(:update_b4_apu, :update) unless method_defined?(:update_b4_apu)
#class Scene_Base#def update() <- aliased
def update
if !@audio_sleep || @audio_sleep == 4
FMod::Audio.update
@audio_sleep = 0
else
@audio_sleep += 1
end
update_b4_apu
end
end
FMod::stop_all # Stop all the playing audio at start (think about F12)