• Our software update is now concluded. You will need to reset your password to log in. In order to do this, you will have to click "Log in" in the top right corner and then "Forgot your password?".
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

Your suggestions for Essentials

KillerMapper

Helix Follower
200
Posts
9
Years
I tried to use FMod but it was breaking battle musics randomly. I don't know if this script will work with Essentials, since it has a lot of differences with PSP (which I was using before).

I hope it can work, I miss the looping part of the music :/

Il faudra traduire en anglais aussi :p
 
11
Posts
9
Years
Posting a French script in an English forum, i'm a bit stupid ...

This is the English Version of the script

Spoiler:


Regards KaiserYoshi
 

KillerMapper

Helix Follower
200
Posts
9
Years
I also forgot to say that we can't copy the code if it includes emotes (: + S will do :S for example).

Better use CODE tag (or disable smilies in the post), like this:

Code:
#==============================================================================
# ** FModEx
#------------------------------------------------------------------------------
#  FMOD Ex binding by Kevin Gadd ([email protected])
#==============================================================================
unless $FMODEX
  $FMODEX=true
module FModEx
  #--------------------------------------------------------------------------
  # * Constants
  #--------------------------------------------------------------------------
  # FMOD_INITFLAGS flags
  FMOD_INIT_NORMAL = 0
  # FMOD_RESULT flags
  FMOD_OK = 0
  FMOD_ERR_CHANNEL_STOLEN = 11
  FMOD_ERR_FILE_NOT_FOUND = 23
  FMOD_ERR_INVALID_HANDLE = 36
  # FMOD_MODE flags
  FMOD_DEFAULT = 0
  FMOD_LOOP_OFF = 1
  FMOD_LOOP_NORMAL = 2
  FMOD_LOOP_BIDI = 4
  FMOD_LOOP_BITMASK = 7
  FMOD_2D = 8
  FMOD_3D = 16
  FMOD_HARDWARE = 32
  FMOD_SOFTWARE = 64
  FMOD_CREATESTREAM = 128
  FMOD_CREATESAMPLE = 256
  FMOD_OPENUSER = 512
  FMOD_OPENMEMORY = 1024
  FMOD_OPENRAW = 2048
   FMOD_OPENONLY = 4096
   FMOD_OPENMEMORY_POINT = 0x10000000
  FMOD_ACCURATETIME = 8192
  FMOD_MPEGSEARCH = 16384
  FMOD_NONBLOCKING = 32768
  FMOD_UNIQUE = 65536
  # The default mode that the script uses
  FMOD_DEFAULT_SOFTWARWE = FMOD_LOOP_OFF | FMOD_2D | FMOD_SOFTWARE
  FMOD_TEST = FMOD_OPENMEMORY | FMOD_SOFTWARE
  # FMOD_CHANNELINDEX flags
  FMOD_CHANNEL_FREE = -1
  FMOD_CHANNEL_REUSE = -2
  # FMOD_TIMEUNIT_flags
  FMOD_TIMEUNIT_MS = 1
  FMOD_TIMEUNIT_PCM = 2
  # The default time unit the script uses
  FMOD_DEFAULT_UNIT = FMOD_TIMEUNIT_MS
  # Types supported by FMOD Ex
  FMOD_FILE_TYPES = ['ogg', 'aac', 'wma', 'mp3', 'wav', 'it', 'xm', 'mod', 's3m', 'mid', 'midi']
  
  #============================================================================
  # ** DLL
  #----------------------------------------------------------------------------
  #  A class that manages importing functions from the DLL
  #============================================================================
  
  class DLL
    #--------------------------------------------------------------------------
    # * Public Instance Variables
    #--------------------------------------------------------------------------
    attr_accessor :filename           # DLL file name for instance    
    attr_accessor :functions          # hash of functions imported (by name)
         
    Functions = {}
    Sys_C='System_Create'
    W32_LL = Win32API.new('kernel32.dll', 'LoadLibrary', 'p', 'l')
    FN='fmodex.dll'
    F='f'
    L='l'
    #--------------------------------------------------------------------------
    # * Object Initialization
    #     filename  : Name of the DLL
    #--------------------------------------------------------------------------
    def initialize(filename = FN)
      @filename = filename
      @handle = 0            # Handle to the DLL
      # Load specified library into the address space of game process
      
      @handle = W32_LL.call(filename)
      unless Functions[Sys_C]
      # System functions:
        self.import(Sys_C, 'p')
        self.import('System_Init', 'llll')
        self.import('System_Close', 'l')
        self.import('System_Release', 'l')
        self.import('System_CreateSound', 'lplpp')
        self.import('System_CreateStream', 'lplpp')
        self.import('System_PlaySound', 'llllp')
        # Sound functions:
        self.import('Sound_Release', 'l')
        self.import('Sound_GetMode', 'lp')
        self.import('Sound_SetMode', 'll')
        self.import('Sound_SetLoopPoints', 'lllll')
        self.import('Sound_GetLength', 'lpl')
        # Channel functions:
        self.import('Channel_Stop', 'l')
        self.import('Channel_IsPlaying', 'lp')
        self.import('Channel_GetPaused', 'lp')
        self.import('Channel_SetPaused', 'll')
        self.import('Channel_GetVolume', 'lp')
        self.import('Channel_SetVolume', 'll')
        self.import('Channel_GetPan', 'lp')
        self.import('Channel_SetPan', 'll')
        self.import('Channel_GetFrequency', 'lp')
        self.import('Channel_SetFrequency', 'll')
        self.import('Channel_GetPosition', 'lpl')
        self.import('Channel_SetPosition', 'lll')
      end
    end
    #--------------------------------------------------------------------------
    # * Create a Win32API Object And Add it to Hashtable
    #     name      : Function name
    #     args      : Argument types (p = pointer, l = int, v = void)
    #     returnType: Type of value returned by function
    #--------------------------------------------------------------------------
    def import(name, args = '', returnType = L)
      Functions[name] = Win32API.new(@filename, 'FMOD_' + name, args, returnType)
    end
    #--------------------------------------------------------------------------
    # * Get Function by Name
    #     key       : Function name
    #--------------------------------------------------------------------------
    def [](key)
      return Functions[key]
    end
    #--------------------------------------------------------------------------
    # * Call a Function With Passed Arguments
    #     name      : Function name
    #     args      : Argument to function
    #--------------------------------------------------------------------------
    def invoke(name, *args)
      fn = Functions[name]
      raise "function not imported: #{name}" if fn.nil?
      result = fn.call(*args)
      unless result == FMOD_OK or result == FMOD_ERR_CHANNEL_STOLEN or
        result == FMOD_ERR_FILE_NOT_FOUND
        if result==36
          Audio.se_clean unless $FMOD_CLEANING
        else
          print "FMOD Ex returned error #{result}.\n"
        end
      end
      return result
    end
    #--------------------------------------------------------------------------
    # * Store Float as Binary Int Because Floats Can't be Passed Directly
    #     f         : Float to convert
    #--------------------------------------------------------------------------
    def convertFloat(f)
      # First pack the float in a string as a native binary float
      temp = [f].pack(F)
      # Then unpack the native binary float as an integer
      return unpackInt(temp)
    end
    #--------------------------------------------------------------------------
    # * Unpack Binary Data to Integer
    #     s         : String containing binary data
    #--------------------------------------------------------------------------
    def unpackInt(s)
      return s.unpack(L)[0]
    end
    #--------------------------------------------------------------------------
    # * Unpack Binary Data to Float
    #     s         : String containing binary data
    #--------------------------------------------------------------------------
    def unpackFloat(s)
      return s.unpack(F)[0]
    end
    #--------------------------------------------------------------------------
    # * Unpack Binary Data to Boolean
    #     s         : String containing binary data
    #--------------------------------------------------------------------------
    def unpackBool(s)
      return s.unpack(L)[0] != 0
    end
  end

  #============================================================================
  # ** System
  #----------------------------------------------------------------------------
  #  A class that manages an instance of FMOD::System
  #============================================================================
  
  class System
    #--------------------------------------------------------------------------
    # * Public Instance Variables
    #-------------------------------------------------------------------------- 
    attr_accessor :fmod               # Instance of DLL class (fmodex.dll)
    attr_accessor :handle             # Handle (pointer) to System object
    attr_accessor :maxChannels        # Maximum number of channels
    System_Create='System_Create'
    System_Init='System_Init'
    System_CreateSound='System_CreateSound'
    UX="U*"
    CX="C*"
    System_CreateStream='System_CreateStream'
    System_Close='System_Close'
    System_Release='System_Release'
    #--------------------------------------------------------------------------
    # * Object Initialization
    #     fmod            : An instance of DLL class
    #     maxChannels     : Maximum number of used channels
    #     flags           : FMOD_INITFLAGS
    #     extraDriverData : Driver specific data
    #--------------------------------------------------------------------------
    def initialize(theDLL, maxChannels = 32, flags = FMOD_INIT_NORMAL, extraDriverData = 0)
      @fmod = theDLL
      @maxChannels = maxChannels
      # Create and initialize FMOD::System
      temp = 0.chr * 4
      @fmod.invoke(System_Create, temp)
      @handle = @fmod.unpackInt(temp)
      @fmod.invoke(System_Init, @handle, maxChannels, flags, extraDriverData)
    end
    #--------------------------------------------------------------------------
    # * Create FMOD::Sound (fully loaded into memory by default)
    #     filename        : Name of file to open
    #     mode            : FMOD_MODE flags
    #--------------------------------------------------------------------------
    def createSound(filename, mode = FMOD_DEFAULT_SOFTWARWE,struc=0)
      # Create sound and return it
      temp = 0.chr * 4
      result = @fmod.invoke(System_CreateSound, @handle, filename, mode, struc, temp)
      if result == FMOD_ERR_FILE_NOT_FOUND
        result2 = @fmod.invoke(System_CreateSound, @handle, filename.unpack(UX).pack(CX), mode, 0, temp)
        raise "File not found: \"#{filename}\"" if result2 == FMOD_ERR_FILE_NOT_FOUND
      end
      newSound = Sound.new(self, @fmod.unpackInt(temp))
      return newSound
    end
    #--------------------------------------------------------------------------
    # * Create Streamed FMOD::Sound (chunks loaded on demand)
    #     filename        : Name of file to open
    #     mode            : FMOD_MODE flags
    #--------------------------------------------------------------------------
    def createStream(filename, mode = FMOD_DEFAULT_SOFTWARWE,struc=0)
      # Create sound and return it
      temp = 0.chr * 4
      result = @fmod.invoke(System_CreateStream, @handle, filename, mode, struc, temp)
      if result == FMOD_ERR_FILE_NOT_FOUND
        result2 = @fmod.invoke(System_CreateStream, @handle, filename.unpack(UX).pack(CX), mode, 0, temp)
        raise "File not found: \"#{filename}\"" if result2 == FMOD_ERR_FILE_NOT_FOUND
      end
      newSound = Sound.new(self, @fmod.unpackInt(temp))
      return newSound
    end
    #--------------------------------------------------------------------------
    # * Close And Release System
    #--------------------------------------------------------------------------
    def dispose
      if (@handle > 0)
        @fmod.invoke(System_Close, @handle)
        @fmod.invoke(System_Release, @handle)
        @handle = 0
      end
      @fmod = nil
    end
  end

  #============================================================================
  # ** Sound
  #----------------------------------------------------------------------------
  #  A class that manages an instance of FMOD::Sound
  #============================================================================
  
  class Sound
    #--------------------------------------------------------------------------
    # * Public Instance Variables
    #-------------------------------------------------------------------------- 
    attr_accessor :system             # System that created this Sound
    attr_accessor :fmod               # Instance of DLL class (fmodex.dll)
    attr_accessor :handle             # Handle (pointer) to Sound object
    
    System_PlaySound='System_PlaySound'
    Sound_GetMode='Sound_GetMode'
    Sound_SetMode='Sound_SetMode'
    Sound_GetLength='Sound_GetLength'
    Sound_SetLoopPoints='Sound_SetLoopPoints'
    Sound_Release='Sound_Release'
    #--------------------------------------------------------------------------
    # * Object Initialization
    #     theSystem       : The System that created this Sound object
    #     handle          : Handle to the FMOD::Sound object
    #--------------------------------------------------------------------------
    def initialize(theSystem, theHandle)
      @system = theSystem
      @fmod = theSystem.fmod
      @handle = theHandle
    end
    #--------------------------------------------------------------------------
    # * Play Sound
    #     paused          : Start paused?
    #     channel         : Channel allocated to sound (nil for automatic)
    #--------------------------------------------------------------------------
    def play(paused = false, channel = nil)
      # If channel wasn't specified, let FMOD pick a free one,
      # otherwise use the passed channel (id from 0 to maxChannels)
      unless channel
        temp = 0.chr * 4
      else
        temp = [channel].pack('l')
      end
      @fmod.invoke(System_PlaySound, @system.handle, 
                (channel == nil) ? FMOD_CHANNEL_FREE : FMOD_CHANNEL_REUSE, 
                @handle,
                (paused == true) ? 1 : 0, 
                temp)
      theChannel = @fmod.unpackInt(temp)
      # Create a Channel object based on returned channel
      newChannel = Channel.new(self, theChannel)
      return newChannel
    end
    #--------------------------------------------------------------------------
    # * Get FMOD_MODE Bits
    #--------------------------------------------------------------------------
    def mode
      temp = 0.chr * 4
      @fmod.invoke(Sound_GetMode, @handle, temp)
      return @fmod.unpackInt(temp)
    end
    #--------------------------------------------------------------------------
    # * Set FMOD_MODE Bits
    #--------------------------------------------------------------------------
    def mode=(newMode)
      @fmod.invoke(Sound_SetMode, @handle, newMode)
    end
    #--------------------------------------------------------------------------
    # * Get FMOD_LOOP_MODE
    #--------------------------------------------------------------------------  
    def loopMode
      temp = 0.chr * 4
      @fmod.invoke(Sound_GetMode, @handle, temp)
      return @fmod.unpackInt(temp) & FMOD_LOOP_BITMASK
    end
    #--------------------------------------------------------------------------
    # * Set FMOD_LOOP_MODE
    #--------------------------------------------------------------------------  
    def loopMode=(newMode)
      @fmod.invoke(Sound_SetMode, @handle, (self.mode & ~FMOD_LOOP_BITMASK) | newMode)
    end
    #--------------------------------------------------------------------------
    # * Return Sound Length
    #-------------------------------------------------------------------------- 
    def length(unit = FMOD_DEFAULT_UNIT)
      temp = 0.chr * 4
      @fmod.invoke(Sound_GetLength, @handle, temp, unit)
      return @fmod.unpackInt(temp)
    end
    #--------------------------------------------------------------------------
    # * Set Loop Points
    #     first           : Loop start point in milliseconds
    #     second          : Loop end point in milliseconds
    #     unit            : FMOD_TIMEUNIT for points
    #--------------------------------------------------------------------------    
    def setLoopPoints(first, second, unit = FMOD_DEFAULT_UNIT)
      @fmod.invoke(Sound_SetLoopPoints, @handle, first, unit, second, unit)
    end
    #--------------------------------------------------------------------------
    # * Release Sound
    #-------------------------------------------------------------------------- 
    def dispose
      if (@handle > 0)
        @fmod.invoke(Sound_Release, @handle)
        @handle = 0
      end
      @fmod = nil
      @system = nil
    end
  end

  #============================================================================
  # ** Channel
  #----------------------------------------------------------------------------
  #  A class that represents an FMOD::Channel
  #============================================================================
  
  class Channel
    #--------------------------------------------------------------------------
    # * Public Instance Variables
    #-------------------------------------------------------------------------- 
    attr_accessor :system             # System that created the Sound
    attr_accessor :sound              # Sound using the Channel
    attr_accessor :fmod               # Instance of DLL class (fmodex.dll)
    attr_accessor :handle             # Handle (pointer) to Sound object
    
    
    Channel_Stop='Channel_Stop'
    Channel_IsPlaying='Channel_IsPlaying'
    Channel_GetVolume='Channel_GetVolume'
    Channel_SetVolume='Channel_SetVolume'
    Channel_GetPan='Channel_GetPan'
    Channel_SetPan='Channel_SetPan'
    Channel_GetFrequency='Channel_GetFrequency'
    Channel_SetFrequency='Channel_SetFrequency'
    Channel_GetPaused='Channel_GetPaused'
    Channel_SetPaused='Channel_SetPaused'
    Channel_GetPosition='Channel_GetPosition'
    Channel_SetPosition='Channel_SetPosition'
    #--------------------------------------------------------------------------
    # * Object Initialization
    #     theSound        : The Sound using this Channel object
    #     handle          : Handle to the FMOD::Channel object
    #--------------------------------------------------------------------------
    def initialize(theSound, theHandle)
      @sound = theSound
      @system = theSound.system
      @fmod = theSound.system.fmod
      @handle = theHandle
    end
    #--------------------------------------------------------------------------
    # * Stop Channel and Make it Available for Other Sounds
    #--------------------------------------------------------------------------
    def stop
      @fmod.invoke(Channel_Stop, @handle)
    end
    #--------------------------------------------------------------------------
    # * Is the Channel Handle Valid?
    #--------------------------------------------------------------------------
    def valid?
      temp = 0.chr * 4
      begin
        result = @fmod.invoke(Channel_IsPlaying, @handle, temp)
      rescue
        if (result == FMOD_ERR_INVALID_HANDLE)
          return false
        else
          raise
        end
      end
      # If we get here then it's valid
      return true
    end
    #--------------------------------------------------------------------------
    # * Is the Channel Playing?
    #--------------------------------------------------------------------------
    def playing?
      temp = 0.chr * 4
      @fmod.invoke(Channel_IsPlaying, @handle, temp)
      return @fmod.unpackBool(temp)
    end
    #--------------------------------------------------------------------------
    # * Get Channel Volume Level (0.0 -> 1.0)
    #--------------------------------------------------------------------------
    def volume
      temp = 0.chr * 4
      @fmod.invoke(Channel_GetVolume, @handle, temp)
      return @fmod.unpackFloat(temp)
    end
    #--------------------------------------------------------------------------
    # * Set Channel Volume Level (0.0 -> 1.0)
    #--------------------------------------------------------------------------
    def volume=(newVolume)
      @fmod.invoke(Channel_SetVolume, @handle, @fmod.convertFloat(newVolume))
    end
    #--------------------------------------------------------------------------
    # * Get Channel Pan Position (-1.0 -> 1.0)
    #--------------------------------------------------------------------------
    def pan
      temp = 0.chr * 4
      @fmod.invoke(Channel_GetPan, @handle, temp)
      return @fmod.unpackFloat(temp)
    end
    #--------------------------------------------------------------------------
    # * Set Channel Pan Position (-1.0 -> 1.0)
    #--------------------------------------------------------------------------
    def pan=(newPan)
      @fmod.invoke(Channel_SetPan, @handle, @fmod.convertFloat(newPan))
    end
    #--------------------------------------------------------------------------
    # * Get Channel Frequency in HZ (Speed/Pitch)
    #--------------------------------------------------------------------------
    def frequency
      temp = 0.chr * 4
      @fmod.invoke(Channel_GetFrequency, @handle, temp)
      return @fmod.unpackFloat(temp)
    end
    #--------------------------------------------------------------------------
    # * Set Channel Frequency in HZ (Speed/Pitch)
    #--------------------------------------------------------------------------
    def frequency=(newFrequency)
      @fmod.invoke(Channel_SetFrequency, @handle, @fmod.convertFloat(newFrequency))
    end
    #--------------------------------------------------------------------------
    # * Is Channel Paused?
    #--------------------------------------------------------------------------
    def paused
      temp = 0.chr * 4
      @fmod.invoke(Channel_GetPaused, @handle, temp)
      return @fmod.unpackBool(temp)
    end
    #--------------------------------------------------------------------------
    # * Pause Channel
    #--------------------------------------------------------------------------
    def paused=(newPaused)
      @fmod.invoke(Channel_SetPaused, @handle, (newPaused == true) ? 1 : 0)
    end
    #--------------------------------------------------------------------------
    # * Get Current Playback Position
    #     unit            : FMOD_TIMEUNIT to return position in
    #--------------------------------------------------------------------------   
    def position(unit = FMOD_DEFAULT_UNIT)
      temp = 0.chr * 4
      @fmod.invoke(Channel_GetPosition, @handle, temp, unit)
      return @fmod.unpackInt(temp)
    end
    #--------------------------------------------------------------------------
    # * Set Current Playback Position
    #     newPosition     : New playback position
    #     unit            : FMOD_TIMEUNIT to use when setting position
    #--------------------------------------------------------------------------    
    def position=(newPosition, unit = FMOD_DEFAULT_UNIT)
      @fmod.invoke(Channel_SetPosition, @handle, newPosition, unit)
    end
    #--------------------------------------------------------------------------
    # * Dispose of Channel
    #--------------------------------------------------------------------------  
    def dispose
      @handle = 0
      @sound = nil
      @system = nil
      @fmod = nil
    end
  end
  
end

#==============================================================================
# ** FMod
#------------------------------------------------------------------------------
#  A higher level module to access FMOD Ex
#==============================================================================

module Audio
  SLP_TIME=0.01
  #============================================================================
  # ** SoundFile
  #----------------------------------------------------------------------------
  #  Represents a Sound file (BGM, BGS, SE, etc.) and associated Channel
  #============================================================================
  
  class SoundFile
    #--------------------------------------------------------------------------
    # * Public Instance Variables
    #--------------------------------------------------------------------------
    attr_accessor :name                     # File name
    attr_accessor :sound                    # FModEx::Sound object
    attr_accessor :channel                  # Channel playing sound
    attr_accessor :volume                   # Volume in RPG::AudioFile format
    attr_accessor :pitch                    # Pitch in RPG::AudioFile format
    attr_accessor :looping                  # Sound loops
    attr_accessor :streaming                # Sound is streamed
    attr_accessor :length                   # Sound length in milliseconds
    #--------------------------------------------------------------------------
    # * Object Initialization
    #--------------------------------------------------------------------------
    def initialize(name, sound, channel, volume, pitch, looping, streaming, length)
      @name = name
      @sound = sound
      @channel = channel
      @volume = volume
      @pitch = pitch
      @looping = looping
      @streaming = streaming
      @length = length
    end
  end
  #--------------------------------------------------------------------------
  # * Instance Variables
  #--------------------------------------------------------------------------
  @fmod_dll = FModEx::DLL.new               # The FMOD Ex DLL
  @fmod = FModEx::System.new(@fmod_dll)     # The global System object
  @fmod_se = []                             # Array of Sound Effects
  @rtp_folder = nil                         # Name of RTP folder
  #--------------------------------------------------------------------------
  # * Get Path of RTP Folder From Registry
  #-------------------------------------------------------------------------- 
  def self.getRTPFolder
    if @rtp_folder
      return @rtp_folder
    end
    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\RGSS\RTP', 0, 0x20019, key)
    key = @fmod_dll.unpackInt(key)
    type = 0.chr * 4
    size = 0.chr * 4
    # Query to get string size
    query_value.call(key, 'Standard', 0, type, 0, size)
    data = ' ' * @fmod_dll.unpackInt(size)
    # Query the string value itself using size
    query_value.call(key, 'Standard', 0, type, data, size)
    @rtp_folder = data.chop
    close_key.call(key)
    # Make sure the directory ends with a backslash
    @rtp_folder += "\\" if @rtp_folder[-1].chr != "\\"
    return @rtp_folder
  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)
    name = name.gsub("/", "\\")
    # See if file exists in game folder
    localname = self.checkExtensions(name, FModEx::FMOD_FILE_TYPES)
    # See if file exists in RTP
    commonname = self.checkExtensions(getRTPFolder + name, FModEx::FMOD_FILE_TYPES)
    if FileTest.exist?(localname)
      return localname
    end
    if FileTest.exist?(commonname)
      return commonname
    end
    # An invalid name was provided
    return 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
    return sound_file
  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 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 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 ME
  #     name            : Name of the file
  #     volume          : Channel volume
  #     pitch           : Channel frequency
  #     position        : Starting position in milliseconds
  #     looping         : Does the BGM loop?
  #-------------------------------------------------------------------------- 
  def self.me_play(name, volume=100, pitch=100, position = 0, looping = false)
    return if self.already_playing?(@fmod_me, name, position) and Audio.me_playing?
    # Now play the new BGM as a stream
    @fmod_me = self.play(name, volume, pitch, position, false, true)
    Thread.new do
      if @fmod_bgm
        paused=@fmod_bgm.channel.paused
        @fmod_bgm.channel.paused=true
      else
        paused=false
      end
      loop do
        unless @fmod_me
          break
        end
        unless Audio.me_playing?
          break
        end
        sleep(SLP_TIME)
      end
      if @fmod_bgm
        @fmod_bgm.channel.paused=paused
      end
    end
    return @fmod_me
  end
  #--------------------------------------------------------------------------
  # * Stop and Dispose of ME
  #-------------------------------------------------------------------------- 
  def self.me_stop
    self.stop(@fmod_me)
    @fmod_me = nil
  end
  #--------------------------------------------------------------------------
  # * Return ME Length in Milliseconds
  #-------------------------------------------------------------------------- 
  def self.me_length(sound_file)
    self.get_length(@fmod_me)
  end
  #--------------------------------------------------------------------------
  # * Check if a ME is Playing
  #--------------------------------------------------------------------------  
  def self.me_playing?
    return self.playing?(@fmod_me)
  end
  #--------------------------------------------------------------------------
  # * Get Current ME Playing Position
  #-------------------------------------------------------------------------- 
  def self.me_position
    return self.get_position(@fmod_me)
  end
  #--------------------------------------------------------------------------
  # * Seek to New ME Playing Position
  #-------------------------------------------------------------------------- 
  def self.me_position=(new_pos)
    self.set_position(@fmod_bgm, new_pos)
  end
  #--------------------------------------------------------------------------
  # * Get Current ME Volume
  #-------------------------------------------------------------------------- 
  def self.me_volume
    return self.get_volume(@fmod_me)
  end
  #--------------------------------------------------------------------------
  # * Set ME Volume
  #-------------------------------------------------------------------------- 
  def self.me_volume=(volume)
    self.set_volume(@fmod_me, volume)
  end
  #--------------------------------------------------------------------------
  # * Set ME fade
  #-------------------------------------------------------------------------- 
  def self.me_fade(time)
    return unless @fmod_me and Audio.me_playing? and !@fading_me
    @fading_me=true
    Thread.new do
      vol=Audio.me_volume
      cnt=(time/1000.0/SLP_TIME).to_i
      cnt.times do |i|
        Audio.me_volume=(vol-(vol*i/cnt))
        sleep SLP_TIME
      end
      Audio.me_stop
      @fading_me=false
    end
  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=100, pitch=100, position = 0, looping = true)
    return if self.already_playing?(@fmod_bgm, name, position)
    # Now play the new BGM as a stream
    @fmod_bgm = self.play(name, volume, pitch, position, looping, true)
    if @fmod_me and Audio.me_playing?
      @fmod_bgm.channel.paused=true
    end
  end
  #--------------------------------------------------------------------------
  # * Stop and Dispose of BGM
  #-------------------------------------------------------------------------- 
  def self.bgm_stop
    self.stop(@fmod_bgm)
    @fmod_bgm = nil
  end
  #--------------------------------------------------------------------------
  # * Return BGM Length in Milliseconds
  #-------------------------------------------------------------------------- 
  def self.bgm_length(sound_file)
    self.get_length(@fmod_bgm)
  end
  #--------------------------------------------------------------------------
  # * Check if a BGM is Playing
  #--------------------------------------------------------------------------  
  def self.bgm_playing?
    return self.playing?(@fmod_bgm)
  end
  #--------------------------------------------------------------------------
  # * Get Current BGM Playing Position
  #-------------------------------------------------------------------------- 
  def self.bgm_position
    return self.get_position(@fmod_bgm)
  end
  #--------------------------------------------------------------------------
  # * Seek to New BGM Playing Position
  #-------------------------------------------------------------------------- 
  def self.bgm_position=(new_pos)
    self.set_position(@fmod_bgm, new_pos)
  end
  #--------------------------------------------------------------------------
  # * Get Current BGM Volume
  #-------------------------------------------------------------------------- 
  def self.bgm_volume
    return self.get_volume(@fmod_bgm)
  end
  #--------------------------------------------------------------------------
  # * Set BGM Volume
  #-------------------------------------------------------------------------- 
  def self.bgm_volume=(volume)
    self.set_volume(@fmod_bgm, volume)
  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, unit = FModEx::FMOD_DEFAULT_UNIT)
    @fmod_bgm = self.set_loop_points(@fmod_bgm, first, second, unit)
  end
  #--------------------------------------------------------------------------
  # * Set BGM fade
  #-------------------------------------------------------------------------- 
  def self.bgm_fade(time)
    return unless @fmod_bgm and Audio.bgm_playing? and !@fading_bgm
    @fading_bgm=true
    Thread.new do
      vol=Audio.bgm_volume
      cnt=(time/1000.0/SLP_TIME).to_i
      cnt.times do |i|
        Audio.bgm_volume=(vol-(vol*i/cnt))
        sleep SLP_TIME
      end
      Audio.bgm_stop
      @fading_bgm=false
    end
  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=100, pitch=100, position = 0, looping = true)
    return if self.already_playing?(@fmod_bgs, name, position)
    # Now play the new BGS as a stream
    @fmod_bgs = self.play(name, volume, pitch, position, looping, true)
  end
  #--------------------------------------------------------------------------
  # * Stop and Dispose of BGS
  #-------------------------------------------------------------------------- 
  def self.bgs_stop
    self.stop(@fmod_bgs)
    @fmod_bgs = nil
  end
  #--------------------------------------------------------------------------
  # * Return BGS Length in Milliseconds
  #-------------------------------------------------------------------------- 
  def self.bgm_length(sound_file)
    self.get_length(@fmod_bgs)
  end
  #--------------------------------------------------------------------------
  # * Check if a BGS is Playing
  #--------------------------------------------------------------------------  
  def self.bgs_playing?
    return self.playing?(@fmod_bgs)
  end
  #--------------------------------------------------------------------------
  # * Get Current BGS Playing Position
  #-------------------------------------------------------------------------- 
  def self.bgs_position
    return self.get_position(@fmod_bgs)
  end
  #--------------------------------------------------------------------------
  # * Seek to New BGS Playing Position
  #-------------------------------------------------------------------------- 
  def self.bgs_position=(new_pos)
    self.set_position(@fmod_bgs, new_pos)
  end
  #--------------------------------------------------------------------------
  # * Get Current BGS Volume
  #-------------------------------------------------------------------------- 
  def self.bgs_volume
    return self.get_volume(@fmod_bgs)
  end
  #--------------------------------------------------------------------------
  # * Set BGS Volume
  #-------------------------------------------------------------------------- 
  def self.bgs_volume=(volume)
    self.set_volume(@fmod_bgs, volume)
  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, unit = FModEx::FMOD_DEFAULT_UNIT)
    @fmod_bgs = self.set_loop_points(@fmod_bgs, first, second, unit)
  end
  #--------------------------------------------------------------------------
  # * Set BGS fade
  #-------------------------------------------------------------------------- 
  def self.bgs_fade(time)
    return unless @fmod_bgs and Audio.bgs_playing? and !@fading_bgs
    @fading_bgs=true
    Thread.new do
      vol=Audio.bgs_volume
      cnt=(time/1000.0/SLP_TIME).to_i
      cnt.times do |i|
        Audio.bgs_volume=(vol-(vol*i/cnt))
        sleep SLP_TIME
      end
      Audio.me_stop
      @fading_bgs=false
    end
  end
  
  #--------------------------------------------------------------------------
  # * Play SE
  #     name            : Name of the file
  #     volume          : Channel volume
  #     pitch           : Channel frequency
  #-------------------------------------------------------------------------- 
  def self.se_play(name, volume=100, pitch=100)
    if @fmod_se.size > @fmod.maxChannels
      #msgbox_p 0
      se = @fmod_se.shift
      #msgbox_p se
      self.stop(se)  if self.playing?(se)
    end
    # Load SE into memory and play it
    @fmod_se << self.play(name, volume, pitch, 0, false, false)
  end
  #--------------------------------------------------------------------------
  # * Stop and Dispose of all SEs
  #-------------------------------------------------------------------------- 
  def self.se_stop
    for se in @fmod_se
      self.stop(se) if self.playing?(se)
    end
    @fmod_se.clear
  end
  #--------------------------------------------------------------------------
  # * Get Rid of Non-Playing SEs
  #--------------------------------------------------------------------------  
      def self.se_clean
      $FMOD_CLEANING=true
    for se in @fmod_se
      unless self.playing?(se)
        self.stop(se)
        @fmod_se.delete(se)
      end
      end
      $FMOD_CLEANING=false   
  end
  #--------------------------------------------------------------------------
  # * Check if There's Some SE in SE Array
  #--------------------------------------------------------------------------  
  def self.se_list_empty?
    return @fmod_se.empty?
  end
  #--------------------------------------------------------------------------
  # * Dispose of Everything
  #--------------------------------------------------------------------------  
  def self.dispose
    self.bgm_stop
    self.bgs_stop
    self.se_stop
    @fmod.dispose
  end
end
end
module FMod
  include Audio
end

I tried the script, but as excepted it doesn't work. The game launches, but all the BGM except the looped one fade out immediately after a map transition. Sometimes it's only the looped music which fades out and the other not. And the loop doesn't work. There is probably something to do with Essential to get it working. But it's probably FMod incompatibility.

Edit: I did something wrong... If I put the loop script under the FMod script in the script editor, it makes the loop working. But non-looped BGM still fades out immediately after playing.

Edit 2: after some researches I noticed this: if I load my game in a place with looped music, only this music will work, other will quickly fade out (looped or not). Battle themes will be fine though. The problem is probably related to the loading game script...

Edit 3: ok the problem isn't with the game loading, but with map transitions. Because when we change the map, Essentials fades out the previous BGM and plays the next BGM. When installing the FMod script, the next BGM immediately starts and fade outs. Probably some incompatibility here... But I don't know how to fix this. For now I disabled the fade by replacing the pbClueBGM by pbBGMPlay in autoplayAsCue, in Game_Map_ section.
 
Last edited:
11
Posts
9
Years
Scripts updated :

Code:
#=======================================================================
# ■ Loop data of music
#
# Contains the data indicating the start and the end of a
# loop for the indicated music.
# Compatible with all versions of RMXP and PSP
# Requires FModEx and fmodex.dll file to the project root
#=======================================================================
# ■ HOW TO USE ?
# Modify LOOP_TABLE by adding an entry of the following form :
# [ "Audio/xxx/File_name", debut, fin ]
# - The chain is simply the path of the file
# (Without the extension!)
# - debut : Point de début de la boucle, en millisecondes
# - fin : Point de fin de la boucle, en millisecondes
#
# When you read an in-game music, this script will automatically
# search corresponding data loop.
#-----------------------------------------------------------------------
# ■ NOTES
# - It is not necessary to add a file to the table if 
# the file haven't loop, or if the loop covers the entire file.
# - Add in preferably BGMs or BGSs
# - Use Audacity (or others) and your ears for get the 
# start and end values.
# - Important : Avoid accents in files name.
#=======================================================================

module Audio

LOOP_TABLE = [

# [ "Audio/xxx/File_name", debut, fin ]
# Add here


# Note: Think add a comma after each "]"
# (Except for the last line and the "]" below).
]

# Do not change the next lines only if you know what you are doing

def self.find_in_loop_table(file)
for i in 0...LOOP_TABLE.size
if LOOP_TABLE[i][0] == file
return i
end
end
return nil
end

def self.bgm_play(name, volume=100, pitch=100, position = 0, looping = true)
return if self.already_playing?(@fmod_bgm, name, position)
@fmod_bgm = self.play(name, volume, pitch, position, looping, true)
if @fmod_me and Audio.me_playing?
@fmod_bgm.channel.paused=true
end
i = self.find_in_loop_table(name)
unless i == nil
#print("Found | #{LOOP_TABLE[i][1].to_s} -> #{LOOP_TABLE[i][2].to_s}")
self.bgm_set_loop_points(LOOP_TABLE[i][1], LOOP_TABLE[i][2])
end
end

def self.bgs_play(name, volume=100, pitch=100, position = 0, looping = true)
return if self.already_playing?(@fmod_bgs, name, position)
@fmod_bgs = self.play(name, volume, pitch, position, looping, true)
i = self.find_in_loop_table(name)
unless i == nil
self.bgs_set_loop_points(LOOP_TABLE[i][1], LOOP_TABLE[i][2])
end
end

end
and

Code:
# Copyright (c) 2005, Kevin Gadd
#==============================================================================
# ** FModEx
#------------------------------------------------------------------------------
#  FMOD Ex binding by Kevin Gadd ([email protected])
#==============================================================================
unless $FMODEX
  $FMODEX=true
module FModEx
  #--------------------------------------------------------------------------
  # * Constants
  #--------------------------------------------------------------------------
  # FMOD_INITFLAGS flags
  FMOD_INIT_NORMAL = 0
  # FMOD_RESULT flags
  FMOD_OK = 0
  FMOD_ERR_CHANNEL_STOLEN = 11
  FMOD_ERR_FILE_NOT_FOUND = 23
  FMOD_ERR_INVALID_HANDLE = 36
  # FMOD_MODE flags
  FMOD_DEFAULT = 0
  FMOD_LOOP_OFF = 1
  FMOD_LOOP_NORMAL = 2
  FMOD_LOOP_BIDI = 4
  FMOD_LOOP_BITMASK = 7
  FMOD_2D = 8
  FMOD_3D = 16
  FMOD_HARDWARE = 32
  FMOD_SOFTWARE = 64
  FMOD_CREATESTREAM = 128
  FMOD_CREATESAMPLE = 256
  FMOD_OPENUSER = 512
  FMOD_OPENMEMORY = 1024
  FMOD_OPENRAW = 2048
   FMOD_OPENONLY = 4096
   FMOD_OPENMEMORY_POINT = 0x10000000
  FMOD_ACCURATETIME = 8192
  FMOD_MPEGSEARCH = 16384
  FMOD_NONBLOCKING = 32768
  FMOD_UNIQUE = 65536
  # The default mode that the script uses
  FMOD_DEFAULT_SOFTWARWE = FMOD_LOOP_OFF | FMOD_2D | FMOD_SOFTWARE
  FMOD_TEST = FMOD_OPENMEMORY | FMOD_SOFTWARE
  # FMOD_CHANNELINDEX flags
  FMOD_CHANNEL_FREE = -1
  FMOD_CHANNEL_REUSE = -2
  # FMOD_TIMEUNIT_flags
  FMOD_TIMEUNIT_MS = 1
  FMOD_TIMEUNIT_PCM = 2
  # The default time unit the script uses
  FMOD_DEFAULT_UNIT = FMOD_TIMEUNIT_MS
  # Types supported by FMOD Ex
  FMOD_FILE_TYPES = ['ogg', 'aac', 'wma', 'mp3', 'wav', 'it', 'xm', 'mod', 's3m', 'mid', 'midi']
  
  #============================================================================
  # ** DLL
  #----------------------------------------------------------------------------
  #  A class that manages importing functions from the DLL
  #============================================================================
  
  class DLL
    #--------------------------------------------------------------------------
    # * Public Instance Variables
    #--------------------------------------------------------------------------
    attr_accessor :filename           # DLL file name for instance    
    attr_accessor :functions          # hash of functions imported (by name)
         
    Functions = {}
    Sys_C='System_Create'
    W32_LL = Win32API.new('kernel32.dll', 'LoadLibrary', 'p', 'l')
    FN='fmodex.dll'
    F='f'
    L='l'
    #--------------------------------------------------------------------------
    # * Object Initialization
    #     filename  : Name of the DLL
    #--------------------------------------------------------------------------
    def initialize(filename = FN)
      @filename = filename
      @handle = 0            # Handle to the DLL
      # Load specified library into the address space of game process
      
      @handle = W32_LL.call(filename)
      unless Functions[Sys_C]
      # System functions:
        self.import(Sys_C, 'p')
        self.import('System_Init', 'llll')
        self.import('System_Close', 'l')
        self.import('System_Release', 'l')
        self.import('System_CreateSound', 'lplpp')
        self.import('System_CreateStream', 'lplpp')
        self.import('System_PlaySound', 'llllp')
        # Sound functions:
        self.import('Sound_Release', 'l')
        self.import('Sound_GetMode', 'lp')
        self.import('Sound_SetMode', 'll')
        self.import('Sound_SetLoopPoints', 'lllll')
        self.import('Sound_GetLength', 'lpl')
        # Channel functions:
        self.import('Channel_Stop', 'l')
        self.import('Channel_IsPlaying', 'lp')
        self.import('Channel_GetPaused', 'lp')
        self.import('Channel_SetPaused', 'll')
        self.import('Channel_GetVolume', 'lp')
        self.import('Channel_SetVolume', 'll')
        self.import('Channel_GetPan', 'lp')
        self.import('Channel_SetPan', 'll')
        self.import('Channel_GetFrequency', 'lp')
        self.import('Channel_SetFrequency', 'll')
        self.import('Channel_GetPosition', 'lpl')
        self.import('Channel_SetPosition', 'lll')
      end
    end
    #--------------------------------------------------------------------------
    # * Create a Win32API Object And Add it to Hashtable
    #     name      : Function name
    #     args      : Argument types (p = pointer, l = int, v = void)
    #     returnType: Type of value returned by function
    #--------------------------------------------------------------------------
    def import(name, args = '', returnType = L)
      Functions[name] = Win32API.new(@filename, 'FMOD_' + name, args, returnType)
    end
    #--------------------------------------------------------------------------
    # * Get Function by Name
    #     key       : Function name
    #--------------------------------------------------------------------------
    def [](key)
      return Functions[key]
    end
    #--------------------------------------------------------------------------
    # * Call a Function With Passed Arguments
    #     name      : Function name
    #     args      : Argument to function
    #--------------------------------------------------------------------------
    def invoke(name, *args)
      fn = Functions[name]
      raise "function not imported: #{name}" if fn.nil?
      result = fn.call(*args)
      unless result == FMOD_OK or result == FMOD_ERR_CHANNEL_STOLEN or
        result == FMOD_ERR_FILE_NOT_FOUND
        if result==36
          Audio.se_clean unless $FMOD_CLEANING
        else
          print "FMOD Ex returned error #{result}.\n"
        end
      end
      return result
    end
    #--------------------------------------------------------------------------
    # * Store Float as Binary Int Because Floats Can't be Passed Directly
    #     f         : Float to convert
    #--------------------------------------------------------------------------
    def convertFloat(f)
      # First pack the float in a string as a native binary float
      temp = [f].pack(F)
      # Then unpack the native binary float as an integer
      return unpackInt(temp)
    end
    #--------------------------------------------------------------------------
    # * Unpack Binary Data to Integer
    #     s         : String containing binary data
    #--------------------------------------------------------------------------
    def unpackInt(s)
      return s.unpack(L)[0]
    end
    #--------------------------------------------------------------------------
    # * Unpack Binary Data to Float
    #     s         : String containing binary data
    #--------------------------------------------------------------------------
    def unpackFloat(s)
      return s.unpack(F)[0]
    end
    #--------------------------------------------------------------------------
    # * Unpack Binary Data to Boolean
    #     s         : String containing binary data
    #--------------------------------------------------------------------------
    def unpackBool(s)
      return s.unpack(L)[0] != 0
    end
  end

  #============================================================================
  # ** System
  #----------------------------------------------------------------------------
  #  A class that manages an instance of FMOD::System
  #============================================================================
  
  class System
    #--------------------------------------------------------------------------
    # * Public Instance Variables
    #-------------------------------------------------------------------------- 
    attr_accessor :fmod               # Instance of DLL class (fmodex.dll)
    attr_accessor :handle             # Handle (pointer) to System object
    attr_accessor :maxChannels        # Maximum number of channels
    System_Create='System_Create'
    System_Init='System_Init'
    System_CreateSound='System_CreateSound'
    UX="U*"
    CX="C*"
    System_CreateStream='System_CreateStream'
    System_Close='System_Close'
    System_Release='System_Release'
    #--------------------------------------------------------------------------
    # * Object Initialization
    #     fmod            : An instance of DLL class
    #     maxChannels     : Maximum number of used channels
    #     flags           : FMOD_INITFLAGS
    #     extraDriverData : Driver specific data
    #--------------------------------------------------------------------------
    def initialize(theDLL, maxChannels = 32, flags = FMOD_INIT_NORMAL, extraDriverData = 0)
      @fmod = theDLL
      @maxChannels = maxChannels
      # Create and initialize FMOD::System
      temp = 0.chr * 4
      @fmod.invoke(System_Create, temp)
      @handle = @fmod.unpackInt(temp)
      @fmod.invoke(System_Init, @handle, maxChannels, flags, extraDriverData)
    end
    #--------------------------------------------------------------------------
    # * Create FMOD::Sound (fully loaded into memory by default)
    #     filename        : Name of file to open
    #     mode            : FMOD_MODE flags
    #--------------------------------------------------------------------------
    def createSound(filename, mode = FMOD_DEFAULT_SOFTWARWE,struc=0)
      # Create sound and return it
      temp = 0.chr * 4
      result = @fmod.invoke(System_CreateSound, @handle, filename, mode, struc, temp)
      if result == FMOD_ERR_FILE_NOT_FOUND
        result2 = @fmod.invoke(System_CreateSound, @handle, filename.unpack(UX).pack(CX), mode, 0, temp)
        raise "File not found: \"#{filename}\"" if result2 == FMOD_ERR_FILE_NOT_FOUND
      end
      newSound = Sound.new(self, @fmod.unpackInt(temp))
      return newSound
    end
    #--------------------------------------------------------------------------
    # * Create Streamed FMOD::Sound (chunks loaded on demand)
    #     filename        : Name of file to open
    #     mode            : FMOD_MODE flags
    #--------------------------------------------------------------------------
    def createStream(filename, mode = FMOD_DEFAULT_SOFTWARWE,struc=0)
      # Create sound and return it
      temp = 0.chr * 4
      result = @fmod.invoke(System_CreateStream, @handle, filename, mode, struc, temp)
      if result == FMOD_ERR_FILE_NOT_FOUND
        result2 = @fmod.invoke(System_CreateStream, @handle, filename.unpack(UX).pack(CX), mode, 0, temp)
        raise "File not found: \"#{filename}\"" if result2 == FMOD_ERR_FILE_NOT_FOUND
      end
      newSound = Sound.new(self, @fmod.unpackInt(temp))
      return newSound
    end
    #--------------------------------------------------------------------------
    # * Close And Release System
    #--------------------------------------------------------------------------
    def dispose
      if (@handle > 0)
        @fmod.invoke(System_Close, @handle)
        @fmod.invoke(System_Release, @handle)
        @handle = 0
      end
      @fmod = nil
    end
  end

  #============================================================================
  # ** Sound
  #----------------------------------------------------------------------------
  #  A class that manages an instance of FMOD::Sound
  #============================================================================
  
  class Sound
    #--------------------------------------------------------------------------
    # * Public Instance Variables
    #-------------------------------------------------------------------------- 
    attr_accessor :system             # System that created this Sound
    attr_accessor :fmod               # Instance of DLL class (fmodex.dll)
    attr_accessor :handle             # Handle (pointer) to Sound object
    
    System_PlaySound='System_PlaySound'
    Sound_GetMode='Sound_GetMode'
    Sound_SetMode='Sound_SetMode'
    Sound_GetLength='Sound_GetLength'
    Sound_SetLoopPoints='Sound_SetLoopPoints'
    Sound_Release='Sound_Release'
    #--------------------------------------------------------------------------
    # * Object Initialization
    #     theSystem       : The System that created this Sound object
    #     handle          : Handle to the FMOD::Sound object
    #--------------------------------------------------------------------------
    def initialize(theSystem, theHandle)
      @system = theSystem
      @fmod = theSystem.fmod
      @handle = theHandle
    end
    #--------------------------------------------------------------------------
    # * Play Sound
    #     paused          : Start paused?
    #     channel         : Channel allocated to sound (nil for automatic)
    #--------------------------------------------------------------------------
    def play(paused = false, channel = nil)
      # If channel wasn't specified, let FMOD pick a free one,
      # otherwise use the passed channel (id from 0 to maxChannels)
      unless channel
        temp = 0.chr * 4
      else
        temp = [channel].pack('l')
      end
      @fmod.invoke(System_PlaySound, @system.handle, 
                (channel == nil) ? FMOD_CHANNEL_FREE : FMOD_CHANNEL_REUSE, 
                @handle,
                (paused == true) ? 1 : 0, 
                temp)
      theChannel = @fmod.unpackInt(temp)
      # Create a Channel object based on returned channel
      newChannel = Channel.new(self, theChannel)
      return newChannel
    end
    #--------------------------------------------------------------------------
    # * Get FMOD_MODE Bits
    #--------------------------------------------------------------------------
    def mode
      temp = 0.chr * 4
      @fmod.invoke(Sound_GetMode, @handle, temp)
      return @fmod.unpackInt(temp)
    end
    #--------------------------------------------------------------------------
    # * Set FMOD_MODE Bits
    #--------------------------------------------------------------------------
    def mode=(newMode)
      @fmod.invoke(Sound_SetMode, @handle, newMode)
    end
    #--------------------------------------------------------------------------
    # * Get FMOD_LOOP_MODE
    #--------------------------------------------------------------------------  
    def loopMode
      temp = 0.chr * 4
      @fmod.invoke(Sound_GetMode, @handle, temp)
      return @fmod.unpackInt(temp) & FMOD_LOOP_BITMASK
    end
    #--------------------------------------------------------------------------
    # * Set FMOD_LOOP_MODE
    #--------------------------------------------------------------------------  
    def loopMode=(newMode)
      @fmod.invoke(Sound_SetMode, @handle, (self.mode & ~FMOD_LOOP_BITMASK) | newMode)
    end
    #--------------------------------------------------------------------------
    # * Return Sound Length
    #-------------------------------------------------------------------------- 
    def length(unit = FMOD_DEFAULT_UNIT)
      temp = 0.chr * 4
      @fmod.invoke(Sound_GetLength, @handle, temp, unit)
      return @fmod.unpackInt(temp)
    end
    #--------------------------------------------------------------------------
    # * Set Loop Points
    #     first           : Loop start point in milliseconds
    #     second          : Loop end point in milliseconds
    #     unit            : FMOD_TIMEUNIT for points
    #--------------------------------------------------------------------------    
    def setLoopPoints(first, second, unit = FMOD_DEFAULT_UNIT)
      @fmod.invoke(Sound_SetLoopPoints, @handle, first, unit, second, unit)
    end
    #--------------------------------------------------------------------------
    # * Release Sound
    #-------------------------------------------------------------------------- 
    def dispose
      if (@handle > 0)
        @fmod.invoke(Sound_Release, @handle)
        @handle = 0
      end
      @fmod = nil
      @system = nil
    end
  end

  #============================================================================
  # ** Channel
  #----------------------------------------------------------------------------
  #  A class that represents an FMOD::Channel
  #============================================================================
  
  class Channel
    #--------------------------------------------------------------------------
    # * Public Instance Variables
    #-------------------------------------------------------------------------- 
    attr_accessor :system             # System that created the Sound
    attr_accessor :sound              # Sound using the Channel
    attr_accessor :fmod               # Instance of DLL class (fmodex.dll)
    attr_accessor :handle             # Handle (pointer) to Sound object
    
    
    Channel_Stop='Channel_Stop'
    Channel_IsPlaying='Channel_IsPlaying'
    Channel_GetVolume='Channel_GetVolume'
    Channel_SetVolume='Channel_SetVolume'
    Channel_GetPan='Channel_GetPan'
    Channel_SetPan='Channel_SetPan'
    Channel_GetFrequency='Channel_GetFrequency'
    Channel_SetFrequency='Channel_SetFrequency'
    Channel_GetPaused='Channel_GetPaused'
    Channel_SetPaused='Channel_SetPaused'
    Channel_GetPosition='Channel_GetPosition'
    Channel_SetPosition='Channel_SetPosition'
    #--------------------------------------------------------------------------
    # * Object Initialization
    #     theSound        : The Sound using this Channel object
    #     handle          : Handle to the FMOD::Channel object
    #--------------------------------------------------------------------------
    def initialize(theSound, theHandle)
      @sound = theSound
      @system = theSound.system
      @fmod = theSound.system.fmod
      @handle = theHandle
    end
    #--------------------------------------------------------------------------
    # * Stop Channel and Make it Available for Other Sounds
    #--------------------------------------------------------------------------
    def stop
      @fmod.invoke(Channel_Stop, @handle)
    end
    #--------------------------------------------------------------------------
    # * Is the Channel Handle Valid?
    #--------------------------------------------------------------------------
    def valid?
      temp = 0.chr * 4
      begin
        result = @fmod.invoke(Channel_IsPlaying, @handle, temp)
      rescue
        if (result == FMOD_ERR_INVALID_HANDLE)
          return false
        else
          raise
        end
      end
      # If we get here then it's valid
      return true
    end
    #--------------------------------------------------------------------------
    # * Is the Channel Playing?
    #--------------------------------------------------------------------------
    def playing?
      temp = 0.chr * 4
      @fmod.invoke(Channel_IsPlaying, @handle, temp)
      return @fmod.unpackBool(temp)
    end
    #--------------------------------------------------------------------------
    # * Get Channel Volume Level (0.0 -> 1.0)
    #--------------------------------------------------------------------------
    def volume
      temp = 0.chr * 4
      @fmod.invoke(Channel_GetVolume, @handle, temp)
      return @fmod.unpackFloat(temp)
    end
    #--------------------------------------------------------------------------
    # * Set Channel Volume Level (0.0 -> 1.0)
    #--------------------------------------------------------------------------
    def volume=(newVolume)
      @fmod.invoke(Channel_SetVolume, @handle, @fmod.convertFloat(newVolume))
    end
    #--------------------------------------------------------------------------
    # * Get Channel Pan Position (-1.0 -> 1.0)
    #--------------------------------------------------------------------------
    def pan
      temp = 0.chr * 4
      @fmod.invoke(Channel_GetPan, @handle, temp)
      return @fmod.unpackFloat(temp)
    end
    #--------------------------------------------------------------------------
    # * Set Channel Pan Position (-1.0 -> 1.0)
    #--------------------------------------------------------------------------
    def pan=(newPan)
      @fmod.invoke(Channel_SetPan, @handle, @fmod.convertFloat(newPan))
    end
    #--------------------------------------------------------------------------
    # * Get Channel Frequency in HZ (Speed/Pitch)
    #--------------------------------------------------------------------------
    def frequency
      temp = 0.chr * 4
      @fmod.invoke(Channel_GetFrequency, @handle, temp)
      return @fmod.unpackFloat(temp)
    end
    #--------------------------------------------------------------------------
    # * Set Channel Frequency in HZ (Speed/Pitch)
    #--------------------------------------------------------------------------
    def frequency=(newFrequency)
      @fmod.invoke(Channel_SetFrequency, @handle, @fmod.convertFloat(newFrequency))
    end
    #--------------------------------------------------------------------------
    # * Is Channel Paused?
    #--------------------------------------------------------------------------
    def paused
      temp = 0.chr * 4
      @fmod.invoke(Channel_GetPaused, @handle, temp)
      return @fmod.unpackBool(temp)
    end
    #--------------------------------------------------------------------------
    # * Pause Channel
    #--------------------------------------------------------------------------
    def paused=(newPaused)
      @fmod.invoke(Channel_SetPaused, @handle, (newPaused == true) ? 1 : 0)
    end
    #--------------------------------------------------------------------------
    # * Get Current Playback Position
    #     unit            : FMOD_TIMEUNIT to return position in
    #--------------------------------------------------------------------------   
    def position(unit = FMOD_DEFAULT_UNIT)
      temp = 0.chr * 4
      @fmod.invoke(Channel_GetPosition, @handle, temp, unit)
      return @fmod.unpackInt(temp)
    end
    #--------------------------------------------------------------------------
    # * Set Current Playback Position
    #     newPosition     : New playback position
    #     unit            : FMOD_TIMEUNIT to use when setting position
    #--------------------------------------------------------------------------    
    def position=(newPosition, unit = FMOD_DEFAULT_UNIT)
      @fmod.invoke(Channel_SetPosition, @handle, newPosition, unit)
    end
    #--------------------------------------------------------------------------
    # * Dispose of Channel
    #--------------------------------------------------------------------------  
    def dispose
      @handle = 0
      @sound = nil
      @system = nil
      @fmod = nil
    end
  end
  
end

#==============================================================================
# ** FMod
#------------------------------------------------------------------------------
#  A higher level module to access FMOD Ex
#==============================================================================

module Audio
  SLP_TIME=0.01
  #============================================================================
  # ** SoundFile
  #----------------------------------------------------------------------------
  #  Represents a Sound file (BGM, BGS, SE, etc.) and associated Channel
  #============================================================================
  
  class SoundFile
    #--------------------------------------------------------------------------
    # * Public Instance Variables
    #--------------------------------------------------------------------------
    attr_accessor :name                     # File name
    attr_accessor :sound                    # FModEx::Sound object
    attr_accessor :channel                  # Channel playing sound
    attr_accessor :volume                   # Volume in RPG::AudioFile format
    attr_accessor :pitch                    # Pitch in RPG::AudioFile format
    attr_accessor :looping                  # Sound loops
    attr_accessor :streaming                # Sound is streamed
    attr_accessor :length                   # Sound length in milliseconds
    #--------------------------------------------------------------------------
    # * Object Initialization
    #--------------------------------------------------------------------------
    def initialize(name, sound, channel, volume, pitch, looping, streaming, length)
      @name = name
      @sound = sound
      @channel = channel
      @volume = volume
      @pitch = pitch
      @looping = looping
      @streaming = streaming
      @length = length
    end
  end
  #--------------------------------------------------------------------------
  # * Instance Variables
  #--------------------------------------------------------------------------
  @fmod_dll = FModEx::DLL.new               # The FMOD Ex DLL
  @fmod = FModEx::System.new(@fmod_dll)     # The global System object
  @fmod_se = []                             # Array of Sound Effects
  @rtp_folder = nil                         # Name of RTP folder
  #--------------------------------------------------------------------------
  # * Get Path of RTP Folder From Registry
  #-------------------------------------------------------------------------- 
  def self.getRTPFolder
    if @rtp_folder
      return @rtp_folder
    end
    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\RGSS\RTP', 0, 0x20019, key)
    key = @fmod_dll.unpackInt(key)
    type = 0.chr * 4
    size = 0.chr * 4
    # Query to get string size
    query_value.call(key, 'Standard', 0, type, 0, size)
    data = ' ' * @fmod_dll.unpackInt(size)
    # Query the string value itself using size
    query_value.call(key, 'Standard', 0, type, data, size)
    @rtp_folder = data.chop
    close_key.call(key)
    # Make sure the directory ends with a backslash
    @rtp_folder += "\\" if @rtp_folder[-1].chr != "\\"
    return @rtp_folder
  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)
    name = name.gsub("/", "\\")
    # See if file exists in game folder
    localname = self.checkExtensions(name, FModEx::FMOD_FILE_TYPES)
    # See if file exists in RTP
    commonname = self.checkExtensions(getRTPFolder + name, FModEx::FMOD_FILE_TYPES)
    if FileTest.exist?(localname)
      return localname
    end
    if FileTest.exist?(commonname)
      return commonname
    end
    # An invalid name was provided
    return 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
    return sound_file
  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 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 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 ME
  #     name            : Name of the file
  #     volume          : Channel volume
  #     pitch           : Channel frequency
  #     position        : Starting position in milliseconds
  #     looping         : Does the BGM loop?
  #-------------------------------------------------------------------------- 
  def self.me_play(name, volume=100, pitch=100, position = 0, looping = false)
    return if self.already_playing?(@fmod_me, name, position) and Audio.me_playing?
    # Now play the new BGM as a stream
    @fmod_me = self.play(name, volume, pitch, position, false, true)
    Thread.new do
      if @fmod_bgm
        paused=@fmod_bgm.channel.paused
        @fmod_bgm.channel.paused=true
      else
        paused=false
      end
      loop do
        unless @fmod_me
          break
        end
        unless Audio.me_playing?
          break
        end
        sleep(SLP_TIME)
      end
      if @fmod_bgm
        @fmod_bgm.channel.paused=paused
      end
    end
    return @fmod_me
  end
  #--------------------------------------------------------------------------
  # * Stop and Dispose of ME
  #-------------------------------------------------------------------------- 
  def self.me_stop
    self.stop(@fmod_me)
    @fmod_me = nil
  end
  #--------------------------------------------------------------------------
  # * Return ME Length in Milliseconds
  #-------------------------------------------------------------------------- 
  def self.me_length(sound_file)
    self.get_length(@fmod_me)
  end
  #--------------------------------------------------------------------------
  # * Check if a ME is Playing
  #--------------------------------------------------------------------------  
  def self.me_playing?
    return self.playing?(@fmod_me)
  end
  #--------------------------------------------------------------------------
  # * Get Current ME Playing Position
  #-------------------------------------------------------------------------- 
  def self.me_position
    return self.get_position(@fmod_me)
  end
  #--------------------------------------------------------------------------
  # * Seek to New ME Playing Position
  #-------------------------------------------------------------------------- 
  def self.me_position=(new_pos)
    self.set_position(@fmod_bgm, new_pos)
  end
  #--------------------------------------------------------------------------
  # * Get Current ME Volume
  #-------------------------------------------------------------------------- 
  def self.me_volume
    return self.get_volume(@fmod_me)
  end
  #--------------------------------------------------------------------------
  # * Set ME Volume
  #-------------------------------------------------------------------------- 
  def self.me_volume=(volume)
    self.set_volume(@fmod_me, volume)
  end
  #--------------------------------------------------------------------------
  # * Set ME fade
  #-------------------------------------------------------------------------- 
  def self.me_fade(time)
    return unless @fmod_me and Audio.me_playing? and !@fading_me
    @fading_me=true
    Thread.new do
      vol=Audio.me_volume
      cnt=(time/1000.0/SLP_TIME).to_i
      cnt.times do |i|
        Audio.me_volume=(vol-(vol*i/cnt))
        sleep SLP_TIME
      end
      Audio.me_stop
      @fading_me=false
    end
  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=100, pitch=100, position = 0, looping = true)
    return if self.already_playing?(@fmod_bgm, name, position)
    # Now play the new BGM as a stream
    @fmod_bgm = self.play(name, volume, pitch, position, looping, true)
    if @fmod_me and Audio.me_playing?
      @fmod_bgm.channel.paused=true
    end
  end
  #--------------------------------------------------------------------------
  # * Stop and Dispose of BGM
  #-------------------------------------------------------------------------- 
  def self.bgm_stop
    self.stop(@fmod_bgm)
    @fmod_bgm = nil
  end
  #--------------------------------------------------------------------------
  # * Return BGM Length in Milliseconds
  #-------------------------------------------------------------------------- 
  def self.bgm_length(sound_file)
    self.get_length(@fmod_bgm)
  end
  #--------------------------------------------------------------------------
  # * Check if a BGM is Playing
  #--------------------------------------------------------------------------  
  def self.bgm_playing?
    return self.playing?(@fmod_bgm)
  end
  #--------------------------------------------------------------------------
  # * Get Current BGM Playing Position
  #-------------------------------------------------------------------------- 
  def self.bgm_position
    return self.get_position(@fmod_bgm)
  end
  #--------------------------------------------------------------------------
  # * Seek to New BGM Playing Position
  #-------------------------------------------------------------------------- 
  def self.bgm_position=(new_pos)
    self.set_position(@fmod_bgm, new_pos)
  end
  #--------------------------------------------------------------------------
  # * Get Current BGM Volume
  #-------------------------------------------------------------------------- 
  def self.bgm_volume
    return self.get_volume(@fmod_bgm)
  end
  #--------------------------------------------------------------------------
  # * Set BGM Volume
  #-------------------------------------------------------------------------- 
  def self.bgm_volume=(volume)
    self.set_volume(@fmod_bgm, volume)
  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, unit = FModEx::FMOD_DEFAULT_UNIT)
    @fmod_bgm = self.set_loop_points(@fmod_bgm, first, second, unit)
  end
  #--------------------------------------------------------------------------
  # * Set BGM fade
  #-------------------------------------------------------------------------- 
  def self.bgm_fade(time)
    return unless @fmod_bgm and Audio.bgm_playing? and !@fading_bgm
    @fading_bgm=true
    Thread.new do
      vol=Audio.bgm_volume
      cnt=(time/1000.0/SLP_TIME).to_i
      cnt.times do |i|
        Audio.bgm_volume=(vol-(vol*i/cnt))
        sleep SLP_TIME
      end
      Audio.bgm_stop
      @fading_bgm=false
    end
  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=100, pitch=100, position = 0, looping = true)
    return if self.already_playing?(@fmod_bgs, name, position)
    # Now play the new BGS as a stream
    @fmod_bgs = self.play(name, volume, pitch, position, looping, true)
  end
  #--------------------------------------------------------------------------
  # * Stop and Dispose of BGS
  #-------------------------------------------------------------------------- 
  def self.bgs_stop
    self.stop(@fmod_bgs)
    @fmod_bgs = nil
  end
  #--------------------------------------------------------------------------
  # * Return BGS Length in Milliseconds
  #-------------------------------------------------------------------------- 
  def self.bgm_length(sound_file)
    self.get_length(@fmod_bgs)
  end
  #--------------------------------------------------------------------------
  # * Check if a BGS is Playing
  #--------------------------------------------------------------------------  
  def self.bgs_playing?
    return self.playing?(@fmod_bgs)
  end
  #--------------------------------------------------------------------------
  # * Get Current BGS Playing Position
  #-------------------------------------------------------------------------- 
  def self.bgs_position
    return self.get_position(@fmod_bgs)
  end
  #--------------------------------------------------------------------------
  # * Seek to New BGS Playing Position
  #-------------------------------------------------------------------------- 
  def self.bgs_position=(new_pos)
    self.set_position(@fmod_bgs, new_pos)
  end
  #--------------------------------------------------------------------------
  # * Get Current BGS Volume
  #-------------------------------------------------------------------------- 
  def self.bgs_volume
    return self.get_volume(@fmod_bgs)
  end
  #--------------------------------------------------------------------------
  # * Set BGS Volume
  #-------------------------------------------------------------------------- 
  def self.bgs_volume=(volume)
    self.set_volume(@fmod_bgs, volume)
  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, unit = FModEx::FMOD_DEFAULT_UNIT)
    @fmod_bgs = self.set_loop_points(@fmod_bgs, first, second, unit)
  end
  #--------------------------------------------------------------------------
  # * Set BGS fade
  #-------------------------------------------------------------------------- 
  def self.bgs_fade(time)
    return unless @fmod_bgs and Audio.bgs_playing? and !@fading_bgs
    @fading_bgs=true
    Thread.new do
      vol=Audio.bgs_volume
      cnt=(time/1000.0/SLP_TIME).to_i
      cnt.times do |i|
        Audio.bgs_volume=(vol-(vol*i/cnt))
        sleep SLP_TIME
      end
      Audio.me_stop
      @fading_bgs=false
    end
  end
  
  #--------------------------------------------------------------------------
  # * Play SE
  #     name            : Name of the file
  #     volume          : Channel volume
  #     pitch           : Channel frequency
  #-------------------------------------------------------------------------- 
  def self.se_play(name, volume=100, pitch=100)
    if @fmod_se.size > @fmod.maxChannels
      #msgbox_p 0
      se = @fmod_se.shift
      #msgbox_p se
      self.stop(se)  if self.playing?(se)
    end
    # Load SE into memory and play it
    @fmod_se << self.play(name, volume, pitch, 0, false, false)
  end
  #--------------------------------------------------------------------------
  # * Stop and Dispose of all SEs
  #-------------------------------------------------------------------------- 
  def self.se_stop
    for se in @fmod_se
      self.stop(se) if self.playing?(se)
    end
    @fmod_se.clear
  end
  #--------------------------------------------------------------------------
  # * Get Rid of Non-Playing SEs
  #--------------------------------------------------------------------------  
      def self.se_clean
      $FMOD_CLEANING=true
    for se in @fmod_se
      unless self.playing?(se)
        self.stop(se)
        @fmod_se.delete(se)
      end
      end
      $FMOD_CLEANING=false   
  end
  #--------------------------------------------------------------------------
  # * Check if There's Some SE in SE Array
  #--------------------------------------------------------------------------  
  def self.se_list_empty?
    return @fmod_se.empty?
  end
  #--------------------------------------------------------------------------
  # * Dispose of Everything
  #--------------------------------------------------------------------------  
  def self.dispose
    self.bgm_stop
    self.bgs_stop
    self.se_stop
    @fmod.dispose
  end
end
end
module FMod
  include Audio
end

And thanks for the feedback. Regards KaiserYoshi
 
20
Posts
13
Years
  • Seen Apr 23, 2020
Implement a autobattle feature that is started with a key press and disabled when the key is pressed again.
 

FL

Pokémon Island Creator
2,443
Posts
13
Years
  • Seen Apr 16, 2024
  1. http://kleinstudio.deviantart.com/art/UPDATE-Footprints-add-on-for-Essentials-528319698
  2. http://www.pokecommunity.com/showthread.php?t=344506 since your old TODO lists a starter selection scene.
  3. http://www.pokecommunity.com/showthread.php?t=343653 is requested enough and isn't hard to be made.
  4. This kind of bridge: http://pokemonessentials.wikia.com/wiki/Forum:Board_Walks at example maps.
  5. Make this small change on elevator script for making more easier for changing the floors total: http://pokemonessentials.wikia.com/wiki/Forum:Elevators
  6. Setting the EV max (510 and 255) into constants, instead of these values scattered through the scripts.
 
824
Posts
8
Years
Hello, I'm Rot8er_ConeX. I think my phone may have glitched when I made this account and thought I held down X instead of just pressing it. Odd that we can have slashes in our names here.

Anyway, I digress. I'd like to suggest the ability to have a pokemon with three or more types. I personally will be using it to make triple-typed pokemon, but others would be more likely to use it to make the moves Forest's Curse and Trick-or-Treat work properly on dual-typed pokemon.

I admit I edited the suggestions page on the wiki first, but I think I read something that said "feel free to edit to add suggestions, just don't expect them to be implemented quickly"
 
Last edited:

Fotomac

Genwunner and proud of it
909
Posts
8
Years
  • Age 32
  • Seen Jan 9, 2023
May I suggest the ability to customize NPC trainers, as well as the addition of Gen VI-style sprites and stuff for Kanto-ites? If you like, I could send you some designs to use for the Gen VI-style Kanto Gym Leaders at some point in the near future.

ETA: Could you also add stereoscopic capability, if you haven't already? Thanks!
 

Maruno

Lead Dev of Pokémon Essentials
5,285
Posts
16
Years
May I suggest the ability to customize NPC trainers
Customise how? You can already make edits to their team/items, and since you can make as many trainer types as you like, you can make a bunch of Campers each with a different coloured hat if you wanted. What else is there to customise?

as well as the addition of Gen VI-style sprites and stuff for Kanto-ites? If you like, I could send you some designs to use for the Gen VI-style Kanto Gym Leaders at some point in the near future.
The graphics that Essentials uses are just fine, thanks.

ETA: Could you also add stereoscopic capability, if you haven't already? Thanks!
Don't be daft.
 

Fotomac

Genwunner and proud of it
909
Posts
8
Years
  • Age 32
  • Seen Jan 9, 2023
Customise how? You can already make edits to their team/items, and since you can make as many trainer types as you like, you can make a bunch of Campers each with a different coloured hat if you wanted. What else is there to customise?

By customize, I meant being able to give different NPC trainers, even within the same class, individual outfits (e.g. recolorization of Camper and Picnicker costumes).

The graphics that Essentials uses are just fine, thanks.

For those seeking to make Gen II or Gen III or Gen IV or Gen V games, yes, but what about those who want to make Kanto remakes for Gen VI using Essentials? Graphics-wise, Gen VI is a whole new ballpark (for example, in terms of overworld scenes and battles), at least from what I could tell. I simply brought up the possibility of Gen VI sprites for Kanto-based trainers and Gym Leaders because I haven't seen a bunch of them (especially not the Gym Leaders) put in any sort of appearance in a Gen VI game.

Don't be daft.

Sorry if I came across as such. It's just that stereoscopy was introduced to the franchise for Gen VI.
 
824
Posts
8
Years
By customize, I meant being able to give different NPC trainers, even within the same class, individual outfits (e.g. recolorization of Camper and Picnicker costumes).
Like Maurno said, though, you can add trainer classes with the same visual name but different outfits, so not technically what you asked but it gets the job done.

For those seeking to make Gen II or Gen III or Gen IV or Gen V games, yes, but what about those who want to make Kanto remakes for Gen VI using Essentials? Graphics-wise, Gen VI is a whole new ballpark (for example, in terms of overworld scenes and battles), at least from what I could tell. I simply brought up the possibility of Gen VI sprites for Kanto-based trainers and Gym Leaders because I haven't seen a bunch of them (especially not the Gym Leaders) put in any sort of appearance in a Gen VI game.

Sorry if I came across as such. It's just that stereoscopy was introduced to the franchise for Gen VI.

Recreating Gen VI's graphics engine in Essentials would be impossible, especially the stereoscopy. It's not an issue of "can Essentials handle it?", it's an issue of "can RPG Maker XP handle it?" to which the answer is no.

The closest you're going to get to any kind of 3D in Essentials is Luka's Elite Battle System.
 

Fotomac

Genwunner and proud of it
909
Posts
8
Years
  • Age 32
  • Seen Jan 9, 2023
Thanks for clearing that up. Is there any engine that can be used for Gen VI games, apart from Elite Battle System?
 

Luka S.J.

Jealous Croatian
1,270
Posts
15
Years
Thanks for clearing that up. Is there any engine that can be used for Gen VI games, apart from Elite Battle System?

My battle system add-on is not an engine, and it only replicates the gen 5 battle scene. There is no proper gen 6 Pokemon engine, nor pretty much any other engine that utilizes a 3D environment. If you want to go in that direction, and out of the fangame box, then you'll have to pick up your own tools, learn to program and do it yourself.
 

Fotomac

Genwunner and proud of it
909
Posts
8
Years
  • Age 32
  • Seen Jan 9, 2023
My battle system add-on is not an engine, and it only replicates the gen 5 battle scene. There is no proper gen 6 Pokemon engine, nor pretty much any other engine that utilizes a 3D environment. If you want to go in that direction, and out of the fangame box, then you'll have to pick up your own tools, learn to program and do it yourself.

Or else recruit someone to a potential Gen VI-style project who has the expertise to create a proper Gen VI engine, correct?
 

Maruno

Lead Dev of Pokémon Essentials
5,285
Posts
16
Years
This thread is for suggestions of things to add to Essentials, not for discussion about where to find other game engines.
 
824
Posts
8
Years
Well I think we has single battle and double battle, how about triple battle or 5 vs 5 battle like Horde Battle :)

Sadly, Zeak is right - I've looked at the code for battles thinking about a way to make it work for my own game, and making Triple Battles work would mean a complete overhaul of both the battle system AND the PBS file moves.txt.
 

Lunos

Random Uruguayan User
3,113
Posts
15
Years
How about a Port to RPG Maker MV?
Not exactly as fast as possible, but taking that in consideration for the future would be really cool.
 
Back
Top