Introduction
This system overrides the AUDIO module for the BGM, BGS and ME systems, only letting the SE functions alone. Its primary function is to let the end user have multiple channels for these systems where only one existed before. This means that while the default audio system for RPGMaker XP allowed you to have only one BGS file playing at any one time, you can now have two or more background files playing simultaneously.
You can still use the default Map Event commands and the like for the principle 'first' channel.
Features
Multiple channels of BGM, BGS and ME, allowing you to play multiple background sounds simultaneously
Default commands still function as normal
Script calls for additional channels
Allows the end-user to make music start and loop where he wants (some edits required)
Comes with a custom loop-point editor (makes the edits for you)
Script
Kinda big. Also, the demo comes with an editor for enhanced loop systems.
Instructions
Besides s small help screen, there is a big help file included in the download.
Notes
Aw, I wish I could have done this with DirectX. It's not the best for midi.... but who uses midi nowadays? Like the default system, neither .wma or .ogg files allow for pitch adjustment. I wouldn't recommend trying to loop pitch-adjusted music with the custom loop-point system anyway.
Also, an additional file is present for those wishing to hear .Ogg Vorbis files with the system, a format normally not audible with the winmm.dll.
Patches
A patch to work with my VEHICLES system
Due credit to find the issue goes to Geminil. Give him due credit as well.
Code:
#==============================================================================
# ** Vehicle SendString Patch v 2
#------------------------------------------------------------------------------
# PLACE MCISendString above the Vehicles System Files. Then place this
# patch below both systems. It overwrites certain features from Vehicles.
#
# IMPORTANT: BGS Sound Playback is affected. BGS audio files MUST be in
# your project's Audio\BGS folder and cannot have the same filename as any
# RTP file. You may copy '001-Wave01' into your project, but name it some-
# thing else insteadl.
#==============================================================================
#==============================================================================
# ** Game_Player
#------------------------------------------------------------------------------
# This class handles the player. Its functions include event starting
# determinants and map scrolling. Refer to "$game_player" for the one
# instance of this class.
#==============================================================================
class Game_Player < Game_Character
#--------------------------------------------------------------------------
# * Change Vehicle Music
#--------------------------------------------------------------------------
def vehicle_music(key)
# Save the original music playing
$game_system.v_music = orig_audio_process($game_system.playing_bgm[1])
# Ignore if not set
return unless Vehicles::SOUND.has_key?(key)
# Play vehicle BGM
return if Vehicles::SOUND[key][0].nil?
music_set = Vehicles::SOUND[key][0]
vehicle_music_playback(music_set)
end
#--------------------------------------------------------------------------
# * Change Vehicle Music
#--------------------------------------------------------------------------
def vehicle_sound(key)
# Save the original music playing
$game_system.v_sound = orig_audio_process($game_system.playing_bgs[1])
# Ignore if not set
return unless Vehicles::SOUND.has_key?(key)
# Play vehicle BGM
return if Vehicles::SOUND[key][1].nil?
sound_set = Vehicles::SOUND[key][1]
vehicle_sound_playback(sound_set)
end
#--------------------------------------------------------------------------
# * Frame Update (when making the player exit the vehicle by key input)
#--------------------------------------------------------------------------
def update_disembark
# Only function if Disembark Key pressed
return false unless Input.trigger?(Vehicles::DISEMBARK_INPUT)
# Used for vehicle behavior
id = $game_system.vehicle_current
new_x = @x
new_y = @y
d = @direction
stepping_forward = false
# Adjust depending on type of vehicle
if Vehicles::BEHAVIOR.has_key?(id)
if Vehicles::BEHAVIOR[id][0] == true
new_x = @x + (d == 6 ? 1 : d == 4 ? -1 : 0)
new_y = @y + (d == 2 ? 1 : d == 8 ? -1 : 0)
stepping_forward = true
end
end
tag = $game_map.terrain_tag(new_x, new_y)
# Prevent disembark
unless $game_system.vehicle_disembark.include?(tag)
# Play buzzer SE
$game_system.se_play($data_system.buzzer_se)
return false
end
# Prevent disembark (blocked terrains though same tag)
if $game_map.vehicle_landing?(new_x, new_y, d, self) == false
# Play buzzer SE
$game_system.se_play($data_system.buzzer_se)
return false
end
# Set Wait Count
@v_wait_count = 10
@v_wait_count = 15 if stepping_forward == true
# Reset the Vehicle Data
id = $game_system.vehicle_current
v_through = $game_system.vehicle_event_through
$game_system.vehicle_current = nil
# Reset Actor
$game_party.actors[0].character_name = $game_system.vehicle_character
$game_player.move_speed = $game_system.vehicle_char_speed
# Set the switch if needed
unless Vehicles::VEHICLE[id][5].nil?
$game_switches[Vehicles::VEHICLE[id][5]] = false
end
# Retrieve current event ID for generated vehicle
v_id = Event_Spawner::vehicle(@x, @y, @direction, id, v_through)
# Set Location and event ID in Game_System
vehicle_array = [$game_map.map_id, @x, @y, @direction, v_id]
$game_system.vehicle_object.vehicle[id] = vehicle_array
@through = true
move_forward if stepping_forward == true
# Retrieve Original Music (unless in Auto-Change BGM)
music_set = $game_system.v_music
# Erase music set if it is the vehicle (ala HQ) and it exists
if Vehicles::SOUND.has_key?(id)
unless Vehicles::SOUND[id][0].nil?
unless music_set.nil?
music_set = nil if music_set[0] == Vehicles::SOUND[id][0][0]
end
end
end
if music_set.nil?
$game_system.bgm_stop[1]
$game_system.playing_bgm[1] = nil
end
# Playback Music
vehicle_music_playback(music_set)
# Retrieve Original Sound (unless in Auto-Change BGS)
sound_set = $game_system.v_sound
if sound_set.nil?
$game_system.bgs_stop[1]
$game_system.playing_bgs[1] = nil
end
# Playback Sound
vehicle_sound_playback(sound_set)
# Check if menu was already disabled
unless $game_system.menu_was_disabled == true
# Re-Enable Menu
$game_system.menu_disabled = false
end
# Turn off Stepping
@step_anime = false
# Reset Vehicle Values to Start
$game_system.vehicle_reset
# Don't flag refresh. Force it.
$game_player.refresh
$game_map.need_refresh == true
$game_map.refresh
@through = false
# Reveal squad members if present
update_vehicle_squad_reveal
# Exit true
return true
end
#--------------------------------------------------------------------------
# * Frame Update (when ensuring the player is in the HQ Map)
#--------------------------------------------------------------------------
def update_hq_entry
# Exit if not using HQ Entry input
return unless Input.trigger?(Vehicles::HQ_INPUT)
# Obtain current vehicle key
v_key = $game_system.vehicle_current
# Exit unless the vehicle has a HQ
return unless Vehicles::HEADQUARTERS.has_key?(v_key)
# Create stored vehicle array
vehicle_array = [$game_map.map_id, @x, @y, @direction, nil]
# Save it and other data to Game_System
$game_system.vehicle_object.vehicle[v_key] = vehicle_array
$game_system.vehicle_current = nil
$game_party.actors[0].character_name = $game_system.vehicle_character
$game_player.move_speed = $game_system.vehicle_char_speed
# Retrieve Original Sound (unless in Auto-Change BGS)
sound_set = $game_system.v_sound
if sound_set.nil?
$game_system.bgs_stop[1]
$game_system.playing_bgs[1] = nil
end
# Playback Sound
vehicle_sound_playback(sound_set)
# Check if menu was already disabled
unless $game_system.menu_was_disabled == true
# Re-Enable Menu
$game_system.menu_disabled = false
end
# Vehicle Animation is turned off
@step_anime = false
# Set transferring player flag
$game_temp.player_transferring = true
hq_map = Vehicles::HEADQUARTERS[v_key]
# Set player move destination
$game_temp.player_new_map_id = hq_map[0] # MapID
$game_temp.player_new_x = hq_map[1] # X
$game_temp.player_new_y = hq_map[2] # Y
$game_temp.player_new_direction = hq_map[3] # Direction
if hq_map[4] == true # Fade
# Prepare for transition
Graphics.freeze
# Set transition processing flag
$game_temp.transition_processing = true
$game_temp.transition_name = ""
end
# Don't flag refresh. Force it.
$game_player.refresh
$game_map.need_refresh == true
$game_map.refresh
@through = false
# Reveal squad members if present
update_vehicle_squad_reveal
# Exit Method
return
end
#--------------------------------------------------------------------------
# * Change Vehicle Music
# key : vehicle Key
#--------------------------------------------------------------------------
def map_to_hq(key=nil)
# Exit if no valid key passed
return if key.nil?
# Exit if no valid Vehicle HQ
return unless Vehicles::HEADQUARTERS.has_key?(key)
# Set Vehicle map, postion and direction
vehicle_array = $game_system.vehicle_object.vehicle[key]
# Map ID of vehicle being deleted
map_id = vehicle_array[0]
# Obtain Vehicle Event ID
mapdata = Game_Map.new
mapdata = load_data(sprintf("Data/Map%03d.rxdata", map_id))
event_id = 0
# Set map event data
events = {}
# Cycle through each event
for i in mapdata.events.keys
name = mapdata.events[i].name
if name =~ Vehicles::VEHICLE_FORMULA
# Obtain key
veh_key = $1
# For valid vehicle keys only
if Vehicles::VEHICLE.has_key?(veh_key)
event_id = mapdata.events[i].id if veh_key = key
end
end
end
# Load map data from vehicle's own map
map_data = load_data(sprintf("Data/Map%03d.rxdata", map_id))
# Search and erase vehicle from map
events = {}
for i in map_data.events.keys
events[i] = Game_Event.new(map_id, map_data.events[i])
events[i].erase if events[i].id == event_id
end
# Save map data back to vehicle's own map
save_data(map_data, sprintf("Data/Map%03d.rxdata", map_id))
# Setup a temp version
map_event_temp = []
# Push current map's list into array if it exists
if $game_map.current_map_event_list.has_key?(map_id)
map_event_temp = $game_map.current_map_event_list[map_id]
end
# Erase ID if it exists in array
map_event_temp.delete(event_id) if map_event_temp.include?(event_id)
# Reapply
$game_map.current_map_event_list[map_id] = map_event_temp
# Store the actor and initial key data as if previously boarded
$game_system.vehicle_character = $game_party.actors[0].character_name
$game_system.vehicle_char_speed = $game_player.move_speed
# Set the music and sound
vehicle_music(key)
vehicle_sound(key)
# Retrieve Original Music (unless in Auto-Change BGM)
sound_set = $game_system.v_sound
if sound_set.nil?
$game_system.bgs_stop[1]
$game_system.playing_bgs[1] = nil
end
# Playback Music
vehicle_sound_playback(sound_set)
$game_system.vehicle_current = nil
# Set transferring player flag
$game_temp.player_transferring = true
hq_map = Vehicles::HEADQUARTERS[key]
# Set player move destination
$game_temp.player_new_map_id = hq_map[0] # MapID
$game_temp.player_new_x = hq_map[1] # X
$game_temp.player_new_y = hq_map[2] # Y
$game_temp.player_new_direction = hq_map[3] # Direction
# Don't flag refresh. Force it.
$game_player.refresh
$game_map.need_refresh == true
$game_map.refresh
@through = false
# Reveal squad members if present
update_vehicle_squad_reveal
# Exit Method
return
end
end
#==============================================================================
# ** Scene_Map
#------------------------------------------------------------------------------
# This class performs map screen processing.
#==============================================================================
class Scene_Map
#--------------------------------------------------------------------------
# * Battle Call
#--------------------------------------------------------------------------
def call_battle
# Clear battle calling flag
$game_temp.battle_calling = false
# Clear menu calling flag
$game_temp.menu_calling = false
$game_temp.menu_beep = false
# Make encounter count
$game_player.make_encounter_count
# Memorize map BGM and stop BGM
$game_temp.map_bgm = $game_system.playing_bgm[1]
$game_system.bgm_stop
# Play battle start SE
$game_system.se_play($data_system.battle_start_se)
# Play battle BGM
$game_system.bgm_play($game_system.battle_bgm)
# Straighten player position
$game_player.straighten
# Switch to battle screen
$scene = Scene_Battle.new
end
end
#==============================================================================
# ** Scene_Load
#------------------------------------------------------------------------------
# This class performs load screen processing.
#==============================================================================
class Scene_Load < Scene_File
#--------------------------------------------------------------------------
# * Decision Processing
#--------------------------------------------------------------------------
def on_decision(filename)
# If file doesn't exist
unless FileTest.exist?(filename)
# Play buzzer SE
$game_system.se_play($data_system.buzzer_se)
return
end
# Play load SE
$game_system.se_play($data_system.load_se)
# Read save data
file = File.open(filename, "rb")
read_save_data(file)
file.close
# Restore BGM and BGS
$game_system.bgm_play($game_system.playing_bgm[1])
$game_system.bgs_play($game_system.playing_bgs[1])
# Update map (run parallel process event)
$game_map.update
# Switch to map screen
$scene = Scene_Map.new
end
end
Compatibility
Unless you have something else overwriting the Audio Module or sections of the Game_System class, it should be pretty much compatible with anything for RPGMaker XP.
Credits and Thanks
Cogwheel for the base mechanics dealing with the mcisendstring for RPGMaker XP.
Terms and Conditions
Free for commercial and non-commercial use. Due credit is all that's wanted.
Is it possible to make this do a Zelda like musical background - when you approach an enemy a new track superimposes on the old one to add danger.
For example:
Harp music playing, grassy plains, gentle.
Enemy approaches! Draw your sword! - rhythm and a new melody are added to the original piece to make it more urgent.
Commander Wyatt made a system for MrMo's ABS that recognizes on-screen enemies and changes tunes when you're in a range (in mah MrMo demo). But it's also made for the default Audio and doesn't have the fancy fade-in/fade-out effects that THIS Audio Module could now allow.
Adding more melodies to an existing track... nope. That's something that needs to add to an existing piece or sync at an exact moment/millisecond.
Yep. Only thing that annoys me is that there is a little 'kick' when you enter the range of an event (even a low volume one). You can reduce the amount of kick depending on what file format and filesize you have. .Ogg is probably the worst in filetypes. You may wanna go .wma instead.
Off topic... kinda: I tried coming up with a method to CACHE audio, but meh. Crash n burn....
Hey DerVV. I just tested it out and there's a slight issue with it.
When I tell it to play more than one file at a time, it loads them one at a time then plays them. This means that they're out of sync with each other.
Is there a way to introduce a delay of a few seconds before it plays them so that it loads them all first and then plays them in sync?
Also, is it possible to make a function where you can pan the music? I'd need one BGM to play on the right and another on the left, with a third in the centre.
Thanks man. :P
Sorry. I kinda mentioned in a thread (maybe here... maybe somewhere else) that I tried to find a way to cache the audio files. But it was crash n burn. Because they cannot cache, they aren't pre-loaded. So yeah... each one has to load before beginning play. That's a drawback.
And I searched for a 'balance' effect to control left/right balance. *sigh* Maybe there IS one, but I haven't found one yet.