Advertisement
Guest User

FModEX RGSS2

a guest
May 12th, 2012
403
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 66.95 KB | None | 0 0
  1. #==============================================================================
  2. # ** FMOD Ex Audio
  3. #------------------------------------------------------------------------------
  4. # Script by : Hiretsukan (Kevin Gadd)
  5. # janus@luminance.org
  6. # Modified by: : RPG/Cowlol (Firas Assad)
  7. # ArePeeGee (AIM name)
  8. # Last Update : September 23rd, 2008
  9. # Version : 1.5
  10. #------------------------------------------------------------------------------
  11. # A rewrite of the built-in Audio module to extend its functionality
  12. # using the FMOD Ex library (http://www.fmod.org/). In particular,
  13. # it supports several new formats and has the ability to get current
  14. # playing position and seek to a new one, and to set loop points.
  15. # Extensions to Game_System and Scene_Battle makes the memorize BGM/BGS
  16. # event command remember position as well, and map music to resume
  17. # playing from the position it stopped at before a battle, instead
  18. # of starting all over like default RMXP behavior.
  19. #------------------------------------------------------------------------------
  20. # Usage:
  21. #
  22. # You need to copy the file fmodex.dll to your game folder (folder where
  23. # your Game.exe and project file are). I've provided the DLL with the
  24. # demo, and you can also get the latest version from FMOD's official
  25. # website (http://www.fmod.org/index.php/download).
  26. #
  27. # There are three scripts that could be used, the real script is only
  28. # the first one, but the other scripts are provided for convenience:
  29. #
  30. # FModEx
  31. # This includes the core functionality and the Audio module
  32. # rewrite. It's the main script and should be placed on
  33. # top of all scripts using it. Most people would just add a
  34. # new section above the Game_System or Game_Temp section at
  35. # the very top of the script editor and paste script there.
  36. # Game_System
  37. # This script rewrites parts of the Game_System class to
  38. # allow memorize_bgm to support remembering position,
  39. # and to allow the play methods to take an extra parameter
  40. # specifying position to start playing from.
  41. # Add it anywhere under the Game_System script section.
  42. # If you don't need any of these features you don't need this
  43. # script.
  44. # Other Classes
  45. # This is really an optional script that modifies the default
  46. # battle system to memorize map BGM and position instead of
  47. # starting over after the battle. Add it anywhere under
  48. # the Scene_Battle classes.
  49. #
  50. # Aside from integration with RMXP's default scripts, you can use
  51. # this script the same way you used the old Audio class You could also
  52. # access the FMod module for more options at a lower level, such as
  53. # setting loop points (FMod.bgm_set_loop_points(first, second) in
  54. # milliseconds) and getting current BGS position (FMod.bgs_position) to
  55. # name a few.
  56. #------------------------------------------------------------------------------
  57. # Compatibility:
  58. #
  59. # This script has different levels of compatibility depending on what
  60. # scripts you use:
  61. #
  62. # FModEx
  63. # This script overwrites the Audio module, but since
  64. # few if any other scripts would do that, it's pretty
  65. # much compatible with the majority of other scripts
  66. # without modifications.
  67. # Game_System
  68. # The following methods of Game_System are redefined:
  69. # bgm_play, bgm_restore, bgs_play, bgs_restore
  70. # Any other script that redefines these methods may
  71. # not work well with this one. Most scripts wouldn't
  72. # do that, except ones dealing with audio as well.
  73. # I've marked the areas in the script where I made
  74. # changes to help you resolve any conflicts
  75. # The following methods of Game_System are aliased:
  76. # bgm_memorize, bgs_memorize
  77. # Other scripts that redefine these methods should
  78. # be placed above the Game_System script.
  79. # Other Classes
  80. # The following methods of Scene_Battle are redefined:
  81. # judge, start_phase5, update_phase5
  82. # Any other script that redefines these methods may
  83. # not work well with this one. Custom battle system
  84. # scripts may do that, so you might consider not
  85. # including the Other Classes section and just
  86. # manually add position memorizing functionality.
  87. # I've marked the areas in the script where I made
  88. # changes to help you resolve any conflicts
  89. # The following methods of Game_Temp/Scene_Map are aliased:
  90. # Game_Temp#initialize, Scene_Map #call_battle
  91. # Other scripts that redefine these methods should
  92. # be placed above the Other Classes script.
  93. #
  94. # So in other words, FModEx is the most compatible, followed by
  95. # Game_System, and finally the last and optional Other Classes.
  96. # If you use a custom battle system you probably shouldn't include
  97. # Other Classes anyway. This isn't an SDK script and I never tested
  98. # it with the SDK. It'll probably work, but refer to SDK documentation
  99. # for more information.
  100. #------------------------------------------------------------------------------
  101. # Version Info:
  102. # - Version 1.5:
  103. # - Made the Volume and Pitch paramters to Audio ME/SE playing
  104. # methods optional. (Thanks panchokoster!)
  105. # - Script now uses FMOD's software mixer instead of hardware
  106. # acceleration. This solves issues with certain sound cards.
  107. # - A message is now displayed when a file isn't found, instead
  108. # of just throwing the error number.
  109. # - Added an independent thread to handle updating Audio module,
  110. # instead of calling it in $game_system#update. This should
  111. # ensure that it's called in all scenes. (Thanks Zeriab!)
  112. # - Updated fading calculations to depend on seconds instead
  113. # of game frames.
  114. # - Version 1.4:
  115. # - Fixed a bug where file isn't found if RTP path doesn't end
  116. # with a backslash (thanks Atoa!).
  117. # - Added BGM fading in after a ME is done playing to mimic
  118. # original Audio class behavior, the volume increment when
  119. # fading is specified by constant Audio::BGM_FADE_IN_INCREMENT.
  120. # - Several minor bug fixes and minor behavior changes relating
  121. # to fading out and stopping sounds.
  122. # - Version 1.3:
  123. # - Fixed a bug with ME fading out.
  124. # - Added methods to get BGM and BGS length.
  125. # - Providing -1 as loop end point to set_loop_points methods
  126. # makes the sound file's end the loop end point.
  127. # - Changed implementation of set_loop_points a bit.
  128. # - Position of BGM/BGS to be played after fading is now
  129. # remembered instead of starting all over.
  130. # - Version 1.2:
  131. # - Fully documented the script, and fixed some bugs.
  132. # - Completely rewrote Audio module, allowing FMOD to handle
  133. # BGMs, BGSs, MEs, and SEs except of just BGMs.
  134. # - Fixed RTP reading to use registry instead of special files..
  135. # - Version 1.1:
  136. # - Added position tracking and adjusting.
  137. # - Added loop point support.
  138. # - Implemented BGM fading.
  139. # - Version 1.0:
  140. # - Hiretsukan (Kevin Gadd)'s initial release.
  141. #------------------------------------------------------------------------------
  142. # Known bugs:
  143. #
  144. # - MIDI abrupt start when seeking or restoring from position
  145. # - Found a bug or have some ideas for the next version? Please tell me!
  146. #------------------------------------------------------------------------------
  147. # Terms of Use:
  148. #
  149. # Use of this script is subject to the permissive BSD-like license below.
  150. # That basically means you could use it in any way you like as long
  151. # as you keep the following copyright and license unchanged and available,
  152. # and don't use name of copyright holder to promote products based on
  153. # this software. Note, however, that this license only applies to the
  154. # script, and not to the FMOD library. For more information about FMOD
  155. # licenses consult FMOD website: http://www.fmod.org/index.php/sales
  156. # It's free for non-commercial use, and they provide several types
  157. # of licenses for different types of developers.
  158. #
  159. # Copyright (c) 2005, Kevin Gadd
  160. # All rights reserved.
  161. #
  162. # Redistribution and use in source and binary forms, with or without
  163. # modification, are permitted provided that the following conditions are met:
  164. # * Redistributions of source code must retain the above copyright
  165. # notice, this list of conditions and the following disclaimer.
  166. # * Redistributions in binary form must reproduce the above copyright
  167. # notice, this list of conditions and the following disclaimer in the
  168. # documentation and/or other materials provided with the distribution.
  169. # * The name of the contributors may not be used to endorse or promote
  170. # products derived from this software without specific prior written
  171. # permission.
  172. #
  173. # THIS SOFTWARE IS PROVIDED BY Kevin Gadd ''AS IS'' AND ANY
  174. # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  175. # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  176. # DISCLAIMED. IN NO EVENT SHALL Kevin Gadd BE LIABLE FOR ANY
  177. # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  178. # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  179. # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  180. # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  181. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  182. # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  183. #==============================================================================
  184.  
  185. #==============================================================================
  186. # ** FModEx
  187. #------------------------------------------------------------------------------
  188. # FMOD Ex binding by Kevin Gadd (janus@luminance.org)
  189. #==============================================================================
  190.  
  191. module FModEx
  192. #--------------------------------------------------------------------------
  193. # * Constants
  194. #--------------------------------------------------------------------------
  195. # FMOD_INITFLAGS flags
  196. FMOD_INIT_NORMAL = 0
  197. # FMOD_RESULT flags
  198. FMOD_OK = 0
  199. FMOD_ERR_CHANNEL_STOLEN = 11
  200. FMOD_ERR_FILE_NOT_FOUND = 23
  201. FMOD_ERR_INVALID_HANDLE = 36
  202. # FMOD_MODE flags
  203. FMOD_DEFAULT = 0
  204. FMOD_LOOP_OFF = 1
  205. FMOD_LOOP_NORMAL = 2
  206. FMOD_LOOP_BIDI = 4
  207. FMOD_LOOP_BITMASK = 7
  208. FMOD_2D = 8
  209. FMOD_3D = 16
  210. FMOD_HARDWARE = 32
  211. FMOD_SOFTWARE = 64
  212. FMOD_CREATESTREAM = 128
  213. FMOD_CREATESAMPLE = 256
  214. FMOD_OPENUSER = 512
  215. FMOD_OPENMEMORY = 1024
  216. FMOD_OPENRAW = 2048
  217. FMOD_OPENONLY = 4096
  218. FMOD_ACCURATETIME = 8192
  219. FMOD_MPEGSEARCH = 16384
  220. FMOD_NONBLOCKING = 32768
  221. FMOD_UNIQUE = 65536
  222. # The default mode that the script uses
  223. FMOD_DEFAULT_SOFTWARWE = FMOD_LOOP_OFF | FMOD_2D | FMOD_SOFTWARE
  224. # FMOD_CHANNELINDEX flags
  225. FMOD_CHANNEL_FREE = -1
  226. FMOD_CHANNEL_REUSE = -2
  227. # FMOD_TIMEUNIT_flags
  228. FMOD_TIMEUNIT_MS = 1
  229. FMOD_TIMEUNIT_PCM = 2
  230. # The default time unit the script uses
  231. FMOD_DEFAULT_UNIT = FMOD_TIMEUNIT_MS
  232. # Types supported by FMOD Ex
  233. FMOD_FILE_TYPES = ['ogg', 'aac', 'wma', 'mp3', 'wav', 'it', 'xm', 'mod', 's3m', 'mid', 'midi']
  234.  
  235. #============================================================================
  236. # ** DLL
  237. #----------------------------------------------------------------------------
  238. # A class that manages importing functions from the DLL
  239. #============================================================================
  240.  
  241. class DLL
  242. #--------------------------------------------------------------------------
  243. # * Public Instance Variables
  244. #--------------------------------------------------------------------------
  245. attr_accessor :filename # DLL file name for instance
  246. attr_accessor :functions # hash of functions imported (by name)
  247. #--------------------------------------------------------------------------
  248. # * Object Initialization
  249. # filename : Name of the DLL
  250. #--------------------------------------------------------------------------
  251. def initialize(filename = 'fmodex.dll')
  252. @filename = filename
  253. @functions = {}
  254. @handle = 0 # Handle to the DLL
  255. # Load specified library into the address space of game process
  256. w32_LL = Win32API.new('kernel32.dll', 'LoadLibrary', 'p', 'l')
  257. @handle = w32_LL.call(filename)
  258. # System functions:
  259. self.import('System_Create', 'p')
  260. self.import('System_Init', 'llll')
  261. self.import('System_Close', 'l')
  262. self.import('System_Release', 'l')
  263. self.import('System_CreateSound', 'lpllp')
  264. self.import('System_CreateStream', 'lpllp')
  265. self.import('System_PlaySound', 'llllp')
  266. # Sound functions:
  267. self.import('Sound_Release', 'l')
  268. self.import('Sound_GetMode', 'lp')
  269. self.import('Sound_SetMode', 'll')
  270. self.import('Sound_SetLoopPoints', 'lllll')
  271. self.import('Sound_GetLength', 'lpl')
  272. # Channel functions:
  273. self.import('Channel_Stop', 'l')
  274. self.import('Channel_IsPlaying', 'lp')
  275. self.import('Channel_GetPaused', 'lp')
  276. self.import('Channel_SetPaused', 'll')
  277. self.import('Channel_GetVolume', 'lp')
  278. self.import('Channel_SetVolume', 'll')
  279. self.import('Channel_GetPan', 'lp')
  280. self.import('Channel_SetPan', 'll')
  281. self.import('Channel_GetFrequency', 'lp')
  282. self.import('Channel_SetFrequency', 'll')
  283. self.import('Channel_GetPosition', 'lpl')
  284. self.import('Channel_SetPosition', 'lll')
  285. end
  286. #--------------------------------------------------------------------------
  287. # * Create a Win32API Object And Add it to Hashtable
  288. # name : Function name
  289. # args : Argument types (p = pointer, l = int, v = void)
  290. # returnType: Type of value returned by function
  291. #--------------------------------------------------------------------------
  292. def import(name, args = '', returnType = 'l')
  293. @functions[name] = Win32API.new(@filename, 'FMOD_' + name, args, returnType)
  294. end
  295. #--------------------------------------------------------------------------
  296. # * Get Function by Name
  297. # key : Function name
  298. #--------------------------------------------------------------------------
  299. def [](key)
  300. return @functions[key]
  301. end
  302. #--------------------------------------------------------------------------
  303. # * Call a Function With Passed Arguments
  304. # name : Function name
  305. # args : Argument to function
  306. #--------------------------------------------------------------------------
  307. def invoke(name, *args)
  308. fn = @functions[name]
  309. raise "function not imported: #{name}" if fn.nil?
  310. result = fn.call(*args)
  311. unless result == FMOD_OK or result == FMOD_ERR_CHANNEL_STOLEN or
  312. result == FMOD_ERR_FILE_NOT_FOUND
  313. raise "FMOD Ex returned error #{result}"
  314. end
  315. return result
  316. end
  317. #--------------------------------------------------------------------------
  318. # * Store Float as Binary Int Because Floats Can't be Passed Directly
  319. # f : Float to convert
  320. #--------------------------------------------------------------------------
  321. def convertFloat(f)
  322. # First pack the float in a string as a native binary float
  323. temp = [f].pack('f')
  324. # Then unpack the native binary float as an integer
  325. return unpackInt(temp)
  326. end
  327. #--------------------------------------------------------------------------
  328. # * Unpack Binary Data to Integer
  329. # s : String containing binary data
  330. #--------------------------------------------------------------------------
  331. def unpackInt(s)
  332. return s.unpack('l')[0]
  333. end
  334. #--------------------------------------------------------------------------
  335. # * Unpack Binary Data to Float
  336. # s : String containing binary data
  337. #--------------------------------------------------------------------------
  338. def unpackFloat(s)
  339. return s.unpack('f')[0]
  340. end
  341. #--------------------------------------------------------------------------
  342. # * Unpack Binary Data to Boolean
  343. # s : String containing binary data
  344. #--------------------------------------------------------------------------
  345. def unpackBool(s)
  346. return s.unpack('l')[0] != 0
  347. end
  348. end
  349.  
  350. #============================================================================
  351. # ** System
  352. #----------------------------------------------------------------------------
  353. # A class that manages an instance of FMOD::System
  354. #============================================================================
  355.  
  356. class System
  357. #--------------------------------------------------------------------------
  358. # * Public Instance Variables
  359. #--------------------------------------------------------------------------
  360. attr_accessor :fmod # Instance of DLL class (fmodex.dll)
  361. attr_accessor :handle # Handle (pointer) to System object
  362. attr_accessor :maxChannels # Maximum number of channels
  363. #--------------------------------------------------------------------------
  364. # * Object Initialization
  365. # fmod : An instance of DLL class
  366. # maxChannels : Maximum number of used channels
  367. # flags : FMOD_INITFLAGS
  368. # extraDriverData : Driver specific data
  369. #--------------------------------------------------------------------------
  370. def initialize(theDLL, maxChannels = 32, flags = FMOD_INIT_NORMAL, extraDriverData = 0)
  371. @fmod = theDLL
  372. @maxChannels = maxChannels
  373. # Create and initialize FMOD::System
  374. temp = 0.chr * 4
  375. @fmod.invoke('System_Create', temp)
  376. @handle = @fmod.unpackInt(temp)
  377. @fmod.invoke('System_Init', @handle, maxChannels, flags, extraDriverData)
  378. end
  379. #--------------------------------------------------------------------------
  380. # * Create FMOD::Sound (fully loaded into memory by default)
  381. # filename : Name of file to open
  382. # mode : FMOD_MODE flags
  383. #--------------------------------------------------------------------------
  384. def createSound(filename, mode = FMOD_DEFAULT_SOFTWARWE)
  385. # Create sound and return it
  386. temp = 0.chr * 4
  387. result = @fmod.invoke('System_CreateSound', @handle, filename, mode, 0, temp)
  388. raise "File not found: \"#{filename}\"" if result == FMOD_ERR_FILE_NOT_FOUND
  389. newSound = Sound.new(self, @fmod.unpackInt(temp))
  390. return newSound
  391. end
  392. #--------------------------------------------------------------------------
  393. # * Create Streamed FMOD::Sound (chunks loaded on demand)
  394. # filename : Name of file to open
  395. # mode : FMOD_MODE flags
  396. #--------------------------------------------------------------------------
  397. def createStream(filename, mode = FMOD_DEFAULT_SOFTWARWE)
  398. # Create sound and return it
  399. temp = 0.chr * 4
  400. result = @fmod.invoke('System_CreateStream', @handle, filename, mode, 0, temp)
  401. raise "File not found: \"#{filename}\"" if result == FMOD_ERR_FILE_NOT_FOUND
  402. newSound = Sound.new(self, @fmod.unpackInt(temp))
  403. return newSound
  404. end
  405. #--------------------------------------------------------------------------
  406. # * Close And Release System
  407. #--------------------------------------------------------------------------
  408. def dispose
  409. if (@handle > 0)
  410. @fmod.invoke('System_Close', @handle)
  411. @fmod.invoke('System_Release', @handle)
  412. @handle = 0
  413. end
  414. @fmod = nil
  415. end
  416. end
  417.  
  418. #============================================================================
  419. # ** Sound
  420. #----------------------------------------------------------------------------
  421. # A class that manages an instance of FMOD::Sound
  422. #============================================================================
  423.  
  424. class Sound
  425. #--------------------------------------------------------------------------
  426. # * Public Instance Variables
  427. #--------------------------------------------------------------------------
  428. attr_accessor :system # System that created this Sound
  429. attr_accessor :fmod # Instance of DLL class (fmodex.dll)
  430. attr_accessor :handle # Handle (pointer) to Sound object
  431. #--------------------------------------------------------------------------
  432. # * Object Initialization
  433. # theSystem : The System that created this Sound object
  434. # handle : Handle to the FMOD::Sound object
  435. #--------------------------------------------------------------------------
  436. def initialize(theSystem, theHandle)
  437. @system = theSystem
  438. @fmod = theSystem.fmod
  439. @handle = theHandle
  440. end
  441. #--------------------------------------------------------------------------
  442. # * Play Sound
  443. # paused : Start paused?
  444. # channel : Channel allocated to sound (nil for automatic)
  445. #--------------------------------------------------------------------------
  446. def play(paused = false, channel = nil)
  447. # If channel wasn't specified, let FMOD pick a free one,
  448. # otherwise use the passed channel (id from 0 to maxChannels)
  449. unless channel
  450. temp = 0.chr * 4
  451. else
  452. temp = [channel].pack('l')
  453. end
  454. @fmod.invoke('System_PlaySound', @system.handle,
  455. (channel == nil) ? FMOD_CHANNEL_FREE : FMOD_CHANNEL_REUSE,
  456. @handle,
  457. (paused == true) ? 1 : 0,
  458. temp)
  459. theChannel = @fmod.unpackInt(temp)
  460. # Create a Channel object based on returned channel
  461. newChannel = Channel.new(self, theChannel)
  462. return newChannel
  463. end
  464. #--------------------------------------------------------------------------
  465. # * Get FMOD_MODE Bits
  466. #--------------------------------------------------------------------------
  467. def mode
  468. temp = 0.chr * 4
  469. @fmod.invoke('Sound_GetMode', @handle, temp)
  470. return @fmod.unpackInt(temp)
  471. end
  472. #--------------------------------------------------------------------------
  473. # * Set FMOD_MODE Bits
  474. #--------------------------------------------------------------------------
  475. def mode=(newMode)
  476. @fmod.invoke('Sound_SetMode', @handle, newMode)
  477. end
  478. #--------------------------------------------------------------------------
  479. # * Get FMOD_LOOP_MODE
  480. #--------------------------------------------------------------------------
  481. def loopMode
  482. temp = 0.chr * 4
  483. @fmod.invoke('Sound_GetMode', @handle, temp)
  484. return @fmod.unpackInt(temp) & FMOD_LOOP_BITMASK
  485. end
  486. #--------------------------------------------------------------------------
  487. # * Set FMOD_LOOP_MODE
  488. #--------------------------------------------------------------------------
  489. def loopMode=(newMode)
  490. @fmod.invoke('Sound_SetMode', @handle, (self.mode & ~FMOD_LOOP_BITMASK) | newMode)
  491. end
  492. #--------------------------------------------------------------------------
  493. # * Return Sound Length
  494. #--------------------------------------------------------------------------
  495. def length(unit = FMOD_DEFAULT_UNIT)
  496. temp = 0.chr * 4
  497. @fmod.invoke('Sound_GetLength', @handle, temp, unit)
  498. return @fmod.unpackInt(temp)
  499. end
  500. #--------------------------------------------------------------------------
  501. # * Set Loop Points
  502. # first : Loop start point in milliseconds
  503. # second : Loop end point in milliseconds
  504. # unit : FMOD_TIMEUNIT for points
  505. #--------------------------------------------------------------------------
  506. def setLoopPoints(first, second, unit = FMOD_DEFAULT_UNIT)
  507. @fmod.invoke('Sound_SetLoopPoints', @handle, first, unit, second, unit)
  508. end
  509. #--------------------------------------------------------------------------
  510. # * Release Sound
  511. #--------------------------------------------------------------------------
  512. def dispose
  513. if (@handle > 0)
  514. @fmod.invoke('Sound_Release', @handle)
  515. @handle = 0
  516. end
  517. @fmod = nil
  518. @system = nil
  519. end
  520. end
  521.  
  522. #============================================================================
  523. # ** Channel
  524. #----------------------------------------------------------------------------
  525. # A class that represents an FMOD::Channel
  526. #============================================================================
  527.  
  528. class Channel
  529. #--------------------------------------------------------------------------
  530. # * Public Instance Variables
  531. #--------------------------------------------------------------------------
  532. attr_accessor :system # System that created the Sound
  533. attr_accessor :sound # Sound using the Channel
  534. attr_accessor :fmod # Instance of DLL class (fmodex.dll)
  535. attr_accessor :handle # Handle (pointer) to Sound object
  536. #--------------------------------------------------------------------------
  537. # * Object Initialization
  538. # theSound : The Sound using this Channel object
  539. # handle : Handle to the FMOD::Channel object
  540. #--------------------------------------------------------------------------
  541. def initialize(theSound, theHandle)
  542. @sound = theSound
  543. @system = theSound.system
  544. @fmod = theSound.system.fmod
  545. @handle = theHandle
  546. end
  547. #--------------------------------------------------------------------------
  548. # * Stop Channel and Make it Available for Other Sounds
  549. #--------------------------------------------------------------------------
  550. def stop
  551. @fmod.invoke('Channel_Stop', @handle)
  552. end
  553. #--------------------------------------------------------------------------
  554. # * Is the Channel Handle Valid?
  555. #--------------------------------------------------------------------------
  556. def valid?
  557. temp = 0.chr * 4
  558. begin
  559. result = @fmod.invoke('Channel_IsPlaying', @handle, temp)
  560. rescue
  561. if (result == FMOD_ERR_INVALID_HANDLE)
  562. return false
  563. else
  564. raise
  565. end
  566. end
  567. # If we get here then it's valid
  568. return true
  569. end
  570. #--------------------------------------------------------------------------
  571. # * Is the Channel Playing?
  572. #--------------------------------------------------------------------------
  573. def playing?
  574. temp = 0.chr * 4
  575. @fmod.invoke('Channel_IsPlaying', @handle, temp)
  576. return @fmod.unpackBool(temp)
  577. end
  578. #--------------------------------------------------------------------------
  579. # * Get Channel Volume Level (0.0 -> 1.0)
  580. #--------------------------------------------------------------------------
  581. def volume
  582. temp = 0.chr * 4
  583. @fmod.invoke('Channel_GetVolume', @handle, temp)
  584. return @fmod.unpackFloat(temp)
  585. end
  586. #--------------------------------------------------------------------------
  587. # * Set Channel Volume Level (0.0 -> 1.0)
  588. #--------------------------------------------------------------------------
  589. def volume=(newVolume)
  590. @fmod.invoke('Channel_SetVolume', @handle, @fmod.convertFloat(newVolume))
  591. end
  592. #--------------------------------------------------------------------------
  593. # * Get Channel Pan Position (-1.0 -> 1.0)
  594. #--------------------------------------------------------------------------
  595. def pan
  596. temp = 0.chr * 4
  597. @fmod.invoke('Channel_GetPan', @handle, temp)
  598. return @fmod.unpackFloat(temp)
  599. end
  600. #--------------------------------------------------------------------------
  601. # * Set Channel Pan Position (-1.0 -> 1.0)
  602. #--------------------------------------------------------------------------
  603. def pan=(newPan)
  604. @fmod.invoke('Channel_SetPan', @handle, @fmod.convertFloat(newPan))
  605. end
  606. #--------------------------------------------------------------------------
  607. # * Get Channel Frequency in HZ (Speed/Pitch)
  608. #--------------------------------------------------------------------------
  609. def frequency
  610. temp = 0.chr * 4
  611. @fmod.invoke('Channel_GetFrequency', @handle, temp)
  612. return @fmod.unpackFloat(temp)
  613. end
  614. #--------------------------------------------------------------------------
  615. # * Set Channel Frequency in HZ (Speed/Pitch)
  616. #--------------------------------------------------------------------------
  617. def frequency=(newFrequency)
  618. @fmod.invoke('Channel_SetFrequency', @handle, @fmod.convertFloat(newFrequency))
  619. end
  620. #--------------------------------------------------------------------------
  621. # * Is Channel Paused?
  622. #--------------------------------------------------------------------------
  623. def paused
  624. temp = 0.chr * 4
  625. @fmod.invoke('Channel_GetPaused', @handle, temp)
  626. return @fmod.unpackBool(temp)
  627. end
  628. #--------------------------------------------------------------------------
  629. # * Pause Channel
  630. #--------------------------------------------------------------------------
  631. def paused=(newPaused)
  632. @fmod.invoke('Channel_SetPaused', @handle, (newPaused == true) ? 1 : 0)
  633. end
  634. #--------------------------------------------------------------------------
  635. # * Get Current Playback Position
  636. # unit : FMOD_TIMEUNIT to return position in
  637. #--------------------------------------------------------------------------
  638. def position(unit = FMOD_DEFAULT_UNIT)
  639. temp = 0.chr * 4
  640. @fmod.invoke('Channel_GetPosition', @handle, temp, unit)
  641. return @fmod.unpackInt(temp)
  642. end
  643. #--------------------------------------------------------------------------
  644. # * Set Current Playback Position
  645. # newPosition : New playback position
  646. # unit : FMOD_TIMEUNIT to use when setting position
  647. #--------------------------------------------------------------------------
  648. def position=(newPosition, unit = FMOD_DEFAULT_UNIT)
  649. @fmod.invoke('Channel_SetPosition', @handle, newPosition, unit)
  650. end
  651. #--------------------------------------------------------------------------
  652. # * Dispose of Channel
  653. #--------------------------------------------------------------------------
  654. def dispose
  655. @handle = 0
  656. @sound = nil
  657. @system = nil
  658. @fmod = nil
  659. end
  660. end
  661.  
  662. end
  663.  
  664. #==============================================================================
  665. # ** FMod
  666. #------------------------------------------------------------------------------
  667. # A higher level module to access FMOD Ex
  668. #==============================================================================
  669.  
  670. module FMod
  671.  
  672. #============================================================================
  673. # ** SoundFile
  674. #----------------------------------------------------------------------------
  675. # Represents a Sound file (BGM, BGS, SE, etc.) and associated Channel
  676. #============================================================================
  677.  
  678. class SoundFile
  679. #--------------------------------------------------------------------------
  680. # * Public Instance Variables
  681. #--------------------------------------------------------------------------
  682. attr_accessor :name # File name
  683. attr_accessor :sound # FModEx::Sound object
  684. attr_accessor :channel # Channel playing sound
  685. attr_accessor :volume # Volume in RPG::AudioFile format
  686. attr_accessor :pitch # Pitch in RPG::AudioFile format
  687. attr_accessor :looping # Sound loops
  688. attr_accessor :streaming # Sound is streamed
  689. attr_accessor :length # Sound length in milliseconds
  690. #--------------------------------------------------------------------------
  691. # * Object Initialization
  692. #--------------------------------------------------------------------------
  693. def initialize(name, sound, channel, volume, pitch, looping, streaming, length)
  694. @name = name
  695. @sound = sound
  696. @channel = channel
  697. @volume = volume
  698. @pitch = pitch
  699. @looping = looping
  700. @streaming = streaming
  701. @length = length
  702. end
  703. end
  704. #--------------------------------------------------------------------------
  705. # * Instance Variables
  706. #--------------------------------------------------------------------------
  707. @fmod_dll = FModEx::DLL.new # The FMOD Ex DLL
  708. @fmod = FModEx::System.new(@fmod_dll) # The global System object
  709. @fmod_se = [] # Array of Sound Effects
  710. @rtp_folder = nil # Name of RTP folder
  711. #--------------------------------------------------------------------------
  712. # * Get Path of RTP Folder From Registry
  713. #--------------------------------------------------------------------------
  714. def self.getRTPFolder
  715. if @rtp_folder
  716. return @rtp_folder
  717. end
  718. open_key = Win32API.new('advapi32.dll', 'RegOpenKeyExA', 'LPLLP', 'L')
  719. query_value = Win32API.new('advapi32.dll', 'RegQueryValueExA', 'LPLPPP', 'L')
  720. close_key = Win32API.new('advapi32', 'RegCloseKey', 'L', 'L')
  721. key = 0.chr * 4
  722. # Open a HKEY_LOCAL_MACHINE with KEY_READ attribute and save handle in key
  723. open_key.call(0x80000002, 'Software\Enterbrain\RGSS\RTP', 0, 0x20019, key)
  724. key = @fmod_dll.unpackInt(key)
  725. type = 0.chr * 4
  726. size = 0.chr * 4
  727. # Query to get string size
  728. query_value.call(key, 'Standard', 0, type, 0, size)
  729. data = ' ' * @fmod_dll.unpackInt(size)
  730. # Query the string value itself using size
  731. query_value.call(key, 'Standard', 0, type, data, size)
  732. @rtp_folder = data.chop
  733. close_key.call(key)
  734. # Make sure the directory ends with a backslash
  735. @rtp_folder += "\\" if @rtp_folder[-1].chr != "\\"
  736. return @rtp_folder
  737. end
  738. #--------------------------------------------------------------------------
  739. # * Return Proper File Name (With Extensions)
  740. # name : Name of the file
  741. # extensions : Extensions to add to file name
  742. #--------------------------------------------------------------------------
  743. def self.checkExtensions(name, extensions)
  744. if FileTest.exist?(name)
  745. return name
  746. end
  747. # Add extension if needed
  748. extensions.each do |ext|
  749. if FileTest.exist?(name + '.' + ext)
  750. return name + '.' + ext
  751. end
  752. end
  753. # File doesn't exist
  754. return name
  755. end
  756. #--------------------------------------------------------------------------
  757. # * Get Valid File Name
  758. # name : Name of the file
  759. #--------------------------------------------------------------------------
  760. def self.selectBGMFilename(name)
  761. name = name.gsub("/", "\\")
  762. # See if file exists in game folder
  763. localname = self.checkExtensions(name, FModEx::FMOD_FILE_TYPES)
  764. # See if file exists in RTP
  765. commonname = self.checkExtensions(getRTPFolder + name, FModEx::FMOD_FILE_TYPES)
  766. if FileTest.exist?(localname)
  767. return localname
  768. end
  769. if FileTest.exist?(commonname)
  770. return commonname
  771. end
  772. # An invalid name was provided
  773. return name
  774. end
  775. #--------------------------------------------------------------------------
  776. # * Play a Sound File Then Return it
  777. # name : Name of the file
  778. # volume : Channel volume
  779. # pitch : Channel frequency
  780. # position : Starting position in milliseconds
  781. # looping : Does the sound loop?
  782. # streaming : Stream sound or load whole thing to memory?
  783. #--------------------------------------------------------------------------
  784. def self.play(name, volume, pitch, position, looping, streaming)
  785. # Get a valid file name
  786. filename = self.selectBGMFilename(name)
  787. # Create Sound or Stream and set initial values
  788. sound = streaming ? @fmod.createStream(filename) : @fmod.createSound(filename)
  789. sound.loopMode = looping ? FModEx::FMOD_LOOP_NORMAL : FModEx::FMOD_LOOP_OFF
  790. channel = sound.play
  791. volume = volume * 1.0
  792. pitch = pitch * 1.0
  793. file_length = sound.length(FModEx::FMOD_DEFAULT_UNIT)
  794. sound_file = SoundFile.new(filename, sound, channel, volume,
  795. pitch, looping, streaming, file_length)
  796. sound_file.channel.volume = volume / 100.0
  797. sound_file.channel.frequency = sound_file.channel.frequency * pitch / 100
  798. sound_file.channel.position = position
  799. return sound_file
  800. end
  801. #--------------------------------------------------------------------------
  802. # * Stop and Dispose of Sound File
  803. #--------------------------------------------------------------------------
  804. def self.stop(sound_file)
  805. unless sound_file and sound_file.channel
  806. return
  807. end
  808. # Stop channel, then clear variables and dispose of bgm
  809. sound_file.channel.stop
  810. sound_file.channel = nil
  811. sound_file.sound.dispose
  812. end
  813. #--------------------------------------------------------------------------
  814. # * Return Length in Milliseconds
  815. #--------------------------------------------------------------------------
  816. def self.get_length(sound_file, unit = FModEx::FMOD_DEFAULT_UNIT)
  817. return sound_file.length(unit)
  818. end
  819. #--------------------------------------------------------------------------
  820. # * Check if Another Sound File is Playing
  821. #--------------------------------------------------------------------------
  822. def self.already_playing?(sound_file, name, position = 0)
  823. # Get a valid file name
  824. filename = self.selectBGMFilename(name)
  825. if (sound_file)
  826. # If the same sound file is already playing don't play it again
  827. if (sound_file.name == filename and position == 0)
  828. return true
  829. end
  830. # If another sound file is playing, stop it
  831. if sound_file.channel
  832. self.stop(sound_file)
  833. end
  834. end
  835. # No sound file is playing or it was already stopped
  836. return false
  837. end
  838. #--------------------------------------------------------------------------
  839. # * Check if Sound File is Playing
  840. #--------------------------------------------------------------------------
  841. def self.playing?(sound_file)
  842. unless sound_file and sound_file.channel
  843. return false
  844. end
  845. return sound_file.channel.playing?
  846. end
  847. #--------------------------------------------------------------------------
  848. # * Get Current Sound File Playing Position
  849. #--------------------------------------------------------------------------
  850. def self.get_position(sound_file)
  851. unless sound_file and sound_file.channel
  852. return 0
  853. end
  854. return sound_file.channel.position
  855. end
  856. #--------------------------------------------------------------------------
  857. # * Seek to a New Sound File Playing Position
  858. #--------------------------------------------------------------------------
  859. def self.set_position(sound_file, new_pos)
  860. unless sound_file and sound_file.channel
  861. return
  862. end
  863. sound_file.channel.position = new_pos
  864. end
  865. #--------------------------------------------------------------------------
  866. # * Get Current Sound File Volume
  867. #--------------------------------------------------------------------------
  868. def self.get_volume(sound_file)
  869. unless sound_file
  870. return 0
  871. end
  872. return sound_file.volume
  873. end
  874. #--------------------------------------------------------------------------
  875. # * Set Sound File Volume
  876. #--------------------------------------------------------------------------
  877. def self.set_volume(sound_file, volume)
  878. unless sound_file and sound_file.channel
  879. return
  880. end
  881. sound_file.volume = volume * 1.0
  882. sound_file.channel.volume = volume / 100.0
  883. end
  884. #--------------------------------------------------------------------------
  885. # * Set Loop Points
  886. # first : Loop start point in milliseconds
  887. # second : Loop end point in milliseconds (-1 for file end)
  888. # unit : FMOD_TIMEUNIT for points
  889. #--------------------------------------------------------------------------
  890. def self.set_loop_points(sound_file, first, second, unit = FModEx::FMOD_DEFAULT_UNIT)
  891. unless sound_file and sound_file.channel
  892. return
  893. end
  894. # If second is -1 then set loop end to the file end
  895. if second == -1
  896. second = sound_file.length - 1
  897. end
  898. # Set loop points and reflush stream buffer
  899. sound_file.channel.sound.setLoopPoints(first, second, unit)
  900. sound_file.channel.position = sound_file.channel.position
  901. return sound_file
  902. end
  903. #--------------------------------------------------------------------------
  904. # * Play BGM (or ME)
  905. # name : Name of the file
  906. # volume : Channel volume
  907. # pitch : Channel frequency
  908. # position : Starting position in milliseconds
  909. # looping : Does the BGM loop?
  910. #--------------------------------------------------------------------------
  911. def self.bgm_play(name, volume, pitch, position = 0, looping = true)
  912. return if self.already_playing?(@fmod_bgm, name, position)
  913. # Now play the new BGM as a stream
  914. @fmod_bgm = self.play(name, volume, pitch, position, looping, true)
  915. end
  916. #--------------------------------------------------------------------------
  917. # * Stop and Dispose of BGM
  918. #--------------------------------------------------------------------------
  919. def self.bgm_stop
  920. self.stop(@fmod_bgm)
  921. @fmod_bgm = nil
  922. end
  923. #--------------------------------------------------------------------------
  924. # * Return BGM Length in Milliseconds
  925. #--------------------------------------------------------------------------
  926. def self.bgm_length(sound_file)
  927. self.get_length(@fmod_bgm)
  928. end
  929. #--------------------------------------------------------------------------
  930. # * Check if a BGM is Playing
  931. #--------------------------------------------------------------------------
  932. def self.bgm_playing?
  933. return self.playing?(@fmod_bgm)
  934. end
  935. #--------------------------------------------------------------------------
  936. # * Get Current BGM Playing Position
  937. #--------------------------------------------------------------------------
  938. def self.bgm_position
  939. return self.get_position(@fmod_bgm)
  940. end
  941. #--------------------------------------------------------------------------
  942. # * Seek to New BGM Playing Position
  943. #--------------------------------------------------------------------------
  944. def self.bgm_position=(new_pos)
  945. self.set_position(@fmod_bgm, new_pos)
  946. end
  947. #--------------------------------------------------------------------------
  948. # * Get Current BGM Volume
  949. #--------------------------------------------------------------------------
  950. def self.bgm_volume
  951. return self.get_volume(@fmod_bgm)
  952. end
  953. #--------------------------------------------------------------------------
  954. # * Set BGM Volume
  955. #--------------------------------------------------------------------------
  956. def self.bgm_volume=(volume)
  957. self.set_volume(@fmod_bgm, volume)
  958. end
  959. #--------------------------------------------------------------------------
  960. # * Set Loop Points
  961. # first : Loop start point in milliseconds
  962. # second : Loop end point in milliseconds
  963. # unit : FMOD_TIMEUNIT for points
  964. #--------------------------------------------------------------------------
  965. def self.bgm_set_loop_points(first, second, unit = FModEx::FMOD_DEFAULT_UNIT)
  966. @fmod_bgm = self.set_loop_points(@fmod_bgm, first, second, unit)
  967. end
  968. #--------------------------------------------------------------------------
  969. # * Play BGS
  970. # name : Name of the file
  971. # volume : Channel volume
  972. # pitch : Channel frequency
  973. # position : Starting position in milliseconds
  974. # looping : Does the BGS loop?
  975. #--------------------------------------------------------------------------
  976. def self.bgs_play(name, volume, pitch, position = 0, looping = true)
  977. return if self.already_playing?(@fmod_bgs, name, position)
  978. # Now play the new BGS as a stream
  979. @fmod_bgs = self.play(name, volume, pitch, position, looping, true)
  980. end
  981. #--------------------------------------------------------------------------
  982. # * Stop and Dispose of BGS
  983. #--------------------------------------------------------------------------
  984. def self.bgs_stop
  985. self.stop(@fmod_bgs)
  986. @fmod_bgs = nil
  987. end
  988. #--------------------------------------------------------------------------
  989. # * Return BGS Length in Milliseconds
  990. #--------------------------------------------------------------------------
  991. def self.bgm_length(sound_file)
  992. self.get_length(@fmod_bgs)
  993. end
  994. #--------------------------------------------------------------------------
  995. # * Check if a BGS is Playing
  996. #--------------------------------------------------------------------------
  997. def self.bgs_playing?
  998. return self.playing?(@fmod_bgs)
  999. end
  1000. #--------------------------------------------------------------------------
  1001. # * Get Current BGS Playing Position
  1002. #--------------------------------------------------------------------------
  1003. def self.bgs_position
  1004. return self.get_position(@fmod_bgs)
  1005. end
  1006. #--------------------------------------------------------------------------
  1007. # * Seek to New BGS Playing Position
  1008. #--------------------------------------------------------------------------
  1009. def self.bgs_position=(new_pos)
  1010. self.set_position(@fmod_bgs, new_pos)
  1011. end
  1012. #--------------------------------------------------------------------------
  1013. # * Get Current BGS Volume
  1014. #--------------------------------------------------------------------------
  1015. def self.bgs_volume
  1016. return self.get_volume(@fmod_bgs)
  1017. end
  1018. #--------------------------------------------------------------------------
  1019. # * Set BGS Volume
  1020. #--------------------------------------------------------------------------
  1021. def self.bgs_volume=(volume)
  1022. self.set_volume(@fmod_bgs, volume)
  1023. end
  1024. #--------------------------------------------------------------------------
  1025. # * Set Loop Points
  1026. # first : Loop start point in milliseconds
  1027. # second : Loop end point in milliseconds
  1028. # unit : FMOD_TIMEUNIT for points
  1029. #--------------------------------------------------------------------------
  1030. def self.bgs_set_loop_points(first, second, unit = FModEx::FMOD_DEFAULT_UNIT)
  1031. @fmod_bgs = self.set_loop_points(@fmod_bgs, first, second, unit)
  1032. end
  1033. #--------------------------------------------------------------------------
  1034. # * Play SE
  1035. # name : Name of the file
  1036. # volume : Channel volume
  1037. # pitch : Channel frequency
  1038. #--------------------------------------------------------------------------
  1039. def self.se_play(name, volume, pitch)
  1040. if @fmod_se.size > @fmod.maxChannels
  1041. se = @fmod_se.shift
  1042. self.stop(se)
  1043. end
  1044. # Load SE into memory and play it
  1045. @fmod_se << self.play(name, volume, pitch, 0, false, false)
  1046. end
  1047. #--------------------------------------------------------------------------
  1048. # * Stop and Dispose of all SEs
  1049. #--------------------------------------------------------------------------
  1050. def self.se_stop
  1051. for se in @fmod_se
  1052. self.stop(se)
  1053. end
  1054. @fmod_se.clear
  1055. end
  1056. #--------------------------------------------------------------------------
  1057. # * Get Rid of Non-Playing SEs
  1058. #--------------------------------------------------------------------------
  1059. def self.se_clean
  1060. for se in @fmod_se
  1061. unless self.playing?(se)
  1062. self.stop(se)
  1063. @fmod_se.delete(se)
  1064. end
  1065. end
  1066. end
  1067. #--------------------------------------------------------------------------
  1068. # * Check if There's Some SE in SE Array
  1069. #--------------------------------------------------------------------------
  1070. def self.se_list_empty?
  1071. return @fmod_se.empty?
  1072. end
  1073. #--------------------------------------------------------------------------
  1074. # * Dispose of Everything
  1075. #--------------------------------------------------------------------------
  1076. def self.dispose
  1077. self.bgm_stop
  1078. self.bgs_stop
  1079. self.se_stop
  1080. @fmod.dispose
  1081. end
  1082. end
  1083.  
  1084. #==============================================================================
  1085. # ** Audio
  1086. #------------------------------------------------------------------------------
  1087. # The module that carries out music and sound processing.
  1088. #==============================================================================
  1089.  
  1090. module Audio
  1091. #--------------------------------------------------------------------------
  1092. # * Constants
  1093. #--------------------------------------------------------------------------
  1094. BGM_FADE_IN_INCREMENT = 5 # BGM volume incremented 0.2 seconds
  1095. #--------------------------------------------------------------------------
  1096. # * Instance Variables
  1097. #--------------------------------------------------------------------------
  1098. @bgm_fading_out = false # BGM started fading out
  1099. @bgm_fade_decrement = 0.0 # BGM volume decremented each update
  1100. @bgs_fading_out = false # BGS started fading out
  1101. @bgs_fade_decrement = 0.0 # BGS volume decremented each update
  1102. @me_fading_out = false # ME started fading out
  1103. @me_fade_decrement = 0.0 # ME volume decremented each update
  1104. @me_playing = false # Is some ME playing?
  1105. @playing_bgm = nil # BGM currently being played
  1106. @next_bgm = nil # The BGM to be played after fading out
  1107. @next_bgm_position = 0 # Starting position of next bgm
  1108. @next_bgs = nil # The BGS to be played after fading out
  1109. @next_bgs_position = 0 # Starting position of next bgm
  1110. @next_me = nil # The ME to be played after fading
  1111. #--------------------------------------------------------------------------
  1112. # * Starts BGM Playback
  1113. # name : Name of the file
  1114. # volume : Channel volume
  1115. # pitch : Channel frequency
  1116. # position : Starting position in milliseconds
  1117. #--------------------------------------------------------------------------
  1118. def Audio.bgm_play(filename, volume = 100, pitch = 100, position = 0,
  1119. fade_in = false)
  1120. if @bgm_fading_out and !fade_in
  1121. @next_bgm = RPG::AudioFile.new(filename, volume, pitch)
  1122. @next_bgm_position = position
  1123. return
  1124. end
  1125. start_volume = volume
  1126. if fade_in
  1127. @bgm_target_volume = volume unless @bgm_fading_in
  1128. @bgm_fading_in = true
  1129. start_volume = 0
  1130. end
  1131. @bgm_fading_out = false
  1132. # If a ME is playing we wait until it's over before playing BGM
  1133. unless @me_playing
  1134. FMod::bgm_play(filename, start_volume, pitch, position)
  1135. end
  1136. @playing_bgm = RPG::AudioFile.new(filename, volume, pitch)
  1137. @memorized_bgm = @playing_bgm
  1138. @memorized_bgm_position = position
  1139. end
  1140. #--------------------------------------------------------------------------
  1141. # * Stops BGM Playback
  1142. #--------------------------------------------------------------------------
  1143. def Audio.bgm_stop
  1144. @memorized_bgm = nil
  1145. @playing_bgm = nil
  1146. @bgm_fading_in = false
  1147. @bgm_fading_out = false
  1148. # MEs are internally BGMs, but are stopped with me_stop instead
  1149. if @me_playing
  1150. return
  1151. end
  1152. FMod::bgm_stop
  1153. end
  1154. #--------------------------------------------------------------------------
  1155. # * Starts BGM fadeout.
  1156. # time : Length of the fadeout in milliseconds.
  1157. #--------------------------------------------------------------------------
  1158. def Audio.bgm_fade(time)
  1159. return if @me_playing or !FMod::bgm_playing?
  1160. @bgm_fading_out = true
  1161. time = time / 1000
  1162. @bgm_fade_decrement = FMod::bgm_volume / (time * 5)
  1163. end
  1164. #--------------------------------------------------------------------------
  1165. # * Starts BGS Playback
  1166. # name : Name of the file
  1167. # volume : Channel volume
  1168. # pitch : Channel frequency
  1169. # position : Starting position in milliseconds
  1170. #--------------------------------------------------------------------------
  1171. def Audio.bgs_play(filename, volume = 100, pitch = 100, position = 0)
  1172. if @bgs_fading_out
  1173. @next_bgs = RPG::AudioFile.new(filename, volume, pitch)
  1174. @next_bgs_position = position
  1175. return
  1176. end
  1177. FMod::bgs_play(filename, volume, pitch, position)
  1178. end
  1179. #--------------------------------------------------------------------------
  1180. # * Stops BGS Playback
  1181. #--------------------------------------------------------------------------
  1182. def Audio.bgs_stop
  1183. FMod::bgs_stop
  1184. @bgs_fading_out = false
  1185. end
  1186. #--------------------------------------------------------------------------
  1187. # * Starts BGS fadeout.
  1188. # time : Length of the fadeout in milliseconds.
  1189. #--------------------------------------------------------------------------
  1190. def Audio.bgs_fade(time)
  1191. return unless FMod::bgs_playing?
  1192. @bgs_fading_out = true
  1193. time = time / 1000
  1194. @bgs_fade_decrement = FMod::bgs_volume / (time * 5)
  1195. end
  1196. #--------------------------------------------------------------------------
  1197. # * Starts ME Playback
  1198. # name : Name of the file
  1199. # volume : Channel volume
  1200. # pitch : Channel frequency
  1201. #--------------------------------------------------------------------------
  1202. def Audio.me_play(filename, volume = 100, pitch = 100)
  1203. if @me_fading_out
  1204. @next_me = RPG::AudioFile.new(filename, volume, pitch)
  1205. return
  1206. end
  1207. if @bgm_fading_out
  1208. self.bgm_stop
  1209. end
  1210. # Memorize playing bgm
  1211. if @playing_bgm and !@me_playing
  1212. bgm = @playing_bgm
  1213. @playing_bgm = RPG::AudioFile.new(bgm.name, FMod::bgm_volume, bgm.pitch)
  1214. @memorized_bgm = @playing_bgm
  1215. @memorized_bgm_position = FMod::bgm_position
  1216. end
  1217. @me_playing = true
  1218. FMod::bgm_play(filename, volume, pitch, 0, false)
  1219. end
  1220. #--------------------------------------------------------------------------
  1221. # * Stops ME Playback
  1222. #--------------------------------------------------------------------------
  1223. def Audio.me_stop
  1224. return unless @me_playing
  1225. @me_playing = false
  1226. @me_fading_out = false
  1227. # Play memorized bgm, fading in
  1228. if @memorized_bgm and !@bgm_fading_out
  1229. bgm = @memorized_bgm
  1230. self.bgm_play(bgm.name, bgm.volume, bgm.pitch, @memorized_bgm_position, true)
  1231. else
  1232. self.bgm_stop
  1233. end
  1234. end
  1235. #--------------------------------------------------------------------------
  1236. # * Starts ME fadeout.
  1237. # time : Length of the fadeout in milliseconds.
  1238. #--------------------------------------------------------------------------
  1239. def Audio.me_fade(time)
  1240. return unless FMod::bgm_playing?
  1241. @me_fading_out = true
  1242. time = time / 1000
  1243. @bgm_fade_decrement = FMod::bgm_volume / (time * 5)
  1244. end
  1245. #--------------------------------------------------------------------------
  1246. # * Starts SE Playback
  1247. # name : Name of the file
  1248. # volume : Channel volume
  1249. # pitch : Channel frequency
  1250. #--------------------------------------------------------------------------
  1251. def Audio.se_play(filename, volume = 100, pitch = 100)
  1252. FMod::se_play(filename, volume, pitch)
  1253. end
  1254. #--------------------------------------------------------------------------
  1255. # * Stops SE Playback
  1256. #--------------------------------------------------------------------------
  1257. def Audio.se_stop
  1258. FMod::se_stop
  1259. end
  1260. #--------------------------------------------------------------------------
  1261. # * Update ME Playback, SE Disposal and Fading, Called Each Frame
  1262. #--------------------------------------------------------------------------
  1263. def Audio.update
  1264. # Stop ME when it's over (and continue playing BGM)
  1265. if @me_playing
  1266. unless FMod::bgm_playing?
  1267. self.me_stop
  1268. end
  1269. end
  1270. # Remove any finished SEs
  1271. unless FMod::se_list_empty?
  1272. FMod::se_clean
  1273. end
  1274. if @bgm_fading_in
  1275. # Stop fading when target is reached, otherwise increase volume
  1276. if FMod::bgm_volume >= @bgm_target_volume
  1277. @bgm_fading_in = false
  1278. else
  1279. current_volume = FMod::bgm_volume + BGM_FADE_IN_INCREMENT
  1280. FMod::bgm_volume = current_volume
  1281. end
  1282. end
  1283. if FMod::bgm_playing? and @bgm_fading_out and
  1284. !@me_playing
  1285. if FMod::bgm_volume <= 0
  1286. @bgm_fading_out = false
  1287. self.bgm_stop
  1288. # If another BGM played while fading out, play it (most recent)
  1289. if @next_bgm
  1290. self.bgm_play(@next_bgm.name, @next_bgm.volume,
  1291. @next_bgm.pitch, @next_bgm_position)
  1292. @next_bgm = nil
  1293. end
  1294. else
  1295. current_volume = FMod::bgm_volume - @bgm_fade_decrement
  1296. FMod::bgm_volume = current_volume
  1297. end
  1298. end
  1299. if FMod::bgs_playing? and @bgs_fading_out
  1300. if FMod::bgs_volume <= 0
  1301. @bgs_fading_out = false
  1302. self.bgs_stop
  1303. # If another BGS played while fading out, play it (most recent)
  1304. if @next_bgs
  1305. self.bgs_play(@next_bgs.name, @next_bgs.volume,
  1306. @next_bgs.pitch, @next_bgs_position)
  1307. @next_bgs = nil
  1308. end
  1309. else
  1310. current_volume = FMod::bgs_volume - @bgs_fade_decrement
  1311. FMod::bgs_volume = current_volume
  1312. end
  1313. end
  1314. if FMod::bgm_playing? and @me_fading_out
  1315. if FMod::bgm_volume <= 0
  1316. # If another ME played while fading out, play it (most recent)
  1317. if @next_me
  1318. self.me_play(@next_me.name, @next_me.volume, @next_me.pitch)
  1319. @next_me = nil
  1320. else
  1321. @me_fading_out = false
  1322. self.me_stop
  1323. end
  1324. else
  1325. current_volume = FMod::bgm_volume - @bgm_fade_decrement
  1326. FMod::bgm_volume = current_volume
  1327. end
  1328. end
  1329. end
  1330. end
  1331.  
  1332. # Create an endless loop to update Audio module
  1333. Thread.new do
  1334. loop do
  1335. sleep 0.2
  1336. Audio.update
  1337. end
  1338. end
  1339.  
  1340. #==============================================================================
  1341. # ** Game_System
  1342. #------------------------------------------------------------------------------
  1343. # This class handles data surrounding the system. Backround music, etc.
  1344. # is managed here as well. Refer to "$game_system" for the instance of
  1345. # this class.
  1346. #==============================================================================
  1347.  
  1348. class Game_System
  1349. #--------------------------------------------------------------------------
  1350. # * Play Background Music
  1351. # bgm : background music to be played
  1352. #--------------------------------------------------------------------------
  1353. ############################################################################
  1354. # ADDED pos (POSITION) AS PARAMETER TO METHOD
  1355. ############################################################################
  1356. def bgm_play(bgm, pos = 0)
  1357. @playing_bgm = bgm
  1358. if bgm != nil and bgm.name != ""
  1359. Audio.bgm_play("Audio/BGM/" + bgm.name, bgm.volume, bgm.pitch, pos)
  1360. ############################################################################
  1361. else
  1362. Audio.bgm_stop
  1363. end
  1364. Graphics.frame_reset
  1365. end
  1366. #--------------------------------------------------------------------------
  1367. # * Memorize Background Music
  1368. #--------------------------------------------------------------------------
  1369. alias :fmodex_old_system_bgm_memorize :bgm_memorize unless $@
  1370. def bgm_memorize
  1371. fmodex_old_system_bgm_memorize
  1372. @bgm_memorized_position = FMod::bgm_position
  1373. end
  1374. #--------------------------------------------------------------------------
  1375. # * Restore Background Music
  1376. #--------------------------------------------------------------------------
  1377. def bgm_restore
  1378. ############################################################################
  1379. # ADDED @bgm_memorized_position AS PARAMETER TO METHOD
  1380. ############################################################################
  1381. bgm_play(@memorized_bgm, @bgm_memorized_position)
  1382. ############################################################################
  1383. end
  1384. #--------------------------------------------------------------------------
  1385. # * Play Background Sound
  1386. # bgs : background sound to be played
  1387. #--------------------------------------------------------------------------
  1388. ############################################################################
  1389. # ADDED pos (POSITION) AS PARAMETER TO METHOD
  1390. ############################################################################
  1391. def bgs_play(bgs, pos = 0)
  1392. @playing_bgs = bgs
  1393. if bgs != nil and bgs.name != ""
  1394. Audio.bgs_play("Audio/BGS/" + bgs.name, bgs.volume, bgs.pitch, pos)
  1395. ############################################################################
  1396. else
  1397. Audio.bgs_stop
  1398. end
  1399. Graphics.frame_reset
  1400. end
  1401. #--------------------------------------------------------------------------
  1402. # * Stop Background Sound
  1403. #--------------------------------------------------------------------------
  1404. def bgs_stop
  1405. @playing_bgs = nil
  1406. Audio.bgs_stop
  1407. end
  1408. #--------------------------------------------------------------------------
  1409. # * Memorize Background Sound
  1410. #--------------------------------------------------------------------------
  1411. alias :fmodex_old_system_bgs_memorize :bgs_memorize unless $@
  1412. def bgs_memorize
  1413. fmodex_old_system_bgs_memorize
  1414. @bgs_memorized_position = FMod::bgs_position
  1415. end
  1416. #--------------------------------------------------------------------------
  1417. # * Restore Background Sound
  1418. #--------------------------------------------------------------------------
  1419. def bgs_restore
  1420. ############################################################################
  1421. # ADDED @bgs_memorized_position AS PARAMETER TO METHOD
  1422. ############################################################################
  1423. bgs_play(@memorized_bgs, @bgs_memorized_position)
  1424. ############################################################################
  1425. end
  1426. end
  1427.  
  1428. class Game_Temp
  1429. attr_accessor :map_bgm_pos
  1430. alias :fmodex_old_temp_initialize :initialize unless $@
  1431. def initialize
  1432. fmodex_old_temp_initialize
  1433. @map_bgm_pos = 0
  1434. end
  1435. end
  1436.  
  1437. class Scene_Map
  1438. alias :fmodex_old_map_call_battle :call_battle unless $@
  1439. def call_battle
  1440. $game_temp.map_bgm_pos = FMod.bgm_position
  1441. fmodex_old_map_call_battle
  1442. end
  1443. end
  1444.  
  1445. class Scene_Battle
  1446. def judge
  1447. # If all dead determinant is true, or number of members in party is 0
  1448. if $game_party.all_dead? or $game_party.actors.size == 0
  1449. # If possible to lose
  1450. if $game_temp.battle_can_lose
  1451. ############################################################################
  1452. # ADDED $game_temp.map_bgm_pos AS 2ND PARAMETE TO bgm_play
  1453. ############################################################################
  1454. # Return to BGM before battle starts
  1455. $game_system.bgm_play($game_temp.map_bgm, $game_temp.map_bgm_pos)
  1456. ############################################################################
  1457. # Battle ends
  1458. battle_end(2)
  1459. # Return true
  1460. return true
  1461. end
  1462. # Set game over flag
  1463. $game_temp.gameover = true
  1464. # Return true
  1465. return true
  1466. end
  1467. # Return false if even 1 enemy exists
  1468. for enemy in $game_troop.enemies
  1469. if enemy.exist?
  1470. return false
  1471. end
  1472. end
  1473. # Start after battle phase (win)
  1474. start_phase5
  1475. # Return true
  1476. return true
  1477. end
  1478.  
  1479. def start_phase5
  1480. # Shift to phase 5
  1481. @phase = 5
  1482. ############################################################################
  1483. # ADDED $game_temp.map_bgm_pos AS 2ND PARAMETE TO bgm_play
  1484. # AND SWITCHED PLAY ORDER SO BGM IS PLAYED FIRST
  1485. ############################################################################
  1486. # Return to BGM before battle started
  1487. $game_system.bgm_play($game_temp.map_bgm, $game_temp.map_bgm_pos)
  1488. # Play battle end ME
  1489. $game_system.me_play($game_system.battle_end_me)
  1490. ############################################################################
  1491. # Initialize EXP, amount of gold, and treasure
  1492. exp = 0
  1493. gold = 0
  1494. treasures = []
  1495. # Loop
  1496. for enemy in $game_troop.enemies
  1497. # If enemy is not hidden
  1498. unless enemy.hidden
  1499. # Add EXP and amount of gold obtained
  1500. exp += enemy.exp
  1501. gold += enemy.gold
  1502. # Determine if treasure appears
  1503. if rand(100) < enemy.treasure_prob
  1504. if enemy.item_id > 0
  1505. treasures.push($data_items[enemy.item_id])
  1506. end
  1507. if enemy.weapon_id > 0
  1508. treasures.push($data_weapons[enemy.weapon_id])
  1509. end
  1510. if enemy.armor_id > 0
  1511. treasures.push($data_armors[enemy.armor_id])
  1512. end
  1513. end
  1514. end
  1515. end
  1516. # Treasure is limited to a maximum of 6 items
  1517. treasures = treasures[0..5]
  1518. # Obtaining EXP
  1519. for i in 0...$game_party.actors.size
  1520. actor = $game_party.actors[i]
  1521. if actor.cant_get_exp? == false
  1522. last_level = actor.level
  1523. actor.exp += exp
  1524. if actor.level > last_level
  1525. @status_window.level_up(i)
  1526. end
  1527. end
  1528. end
  1529. # Obtaining gold
  1530. $game_party.gain_gold(gold)
  1531. # Obtaining treasure
  1532. for item in treasures
  1533. case item
  1534. when RPG::Item
  1535. $game_party.gain_item(item.id, 1)
  1536. when RPG::Weapon
  1537. $game_party.gain_weapon(item.id, 1)
  1538. when RPG::Armor
  1539. $game_party.gain_armor(item.id, 1)
  1540. end
  1541. end
  1542. # Make battle result window
  1543. @result_window = Window_BattleResult.new(exp, gold, treasures)
  1544. # Set wait count
  1545. @phase5_wait_count = 100
  1546. end
  1547.  
  1548.  
  1549. def update_phase5
  1550. # If wait count is larger than 0
  1551. if @phase5_wait_count > 0
  1552. # Decrease wait count
  1553. @phase5_wait_count -= 1
  1554. # If wait count reaches 0
  1555. if @phase5_wait_count == 0
  1556. # Show result window
  1557. @result_window.visible = true
  1558. # Clear main phase flag
  1559. $game_temp.battle_main_phase = false
  1560. # Refresh status window
  1561. @status_window.refresh
  1562. end
  1563. return
  1564. end
  1565. # If C button was pressed
  1566. if Input.trigger?(Input::C)
  1567. ############################################################################
  1568. # REMOVED $game_system.play_bgm BECAUSE IT'S DONE AUTOMATICALLY
  1569. # WHEN ME IS DONE PLAYING
  1570. ############################################################################
  1571. ############################################################################
  1572. # Battle ends
  1573. battle_end(0)
  1574. end
  1575. end
  1576. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement