#!ruby # -*- mode: ruby; coding: utf-8 -*- # Last updated: <2021/08/18 09:20:26 +0900> =begin vaudiorb is vAudio.dll wrapper. @version 0.0.1 @author mieki256 License : Public Domain / CC0 it works: * Windows10 x64 21H1 * Ruby 2.3.3 p222 [i386-mingw32] * Ruby 2.6.8 p205 [i386-mingw32] * Ruby 2.7.4 p191 [i386-mingw32] * Ruby 3.0.2 p107 [i386-mingw32] @example Play stream require "dxruby" require_relative "VAudio" VAudio.init(Window.hWnd) s = VAudio.loadStream("loop_bgm.ogg") s.setRepeat(true) s.play Window.loop do break if Input.keyPush?(K_ESCAPE) end s.free VAudio.free @example Play sample require "dxruby" require_relative "VAudio" VAudio.init(Window.hWnd) s = VAudio.loadSample("jingle.ogg") s.setRepeat(false) s.play Window.loop do break if Input.keyPush?(K_ESCAPE) end s.free VAudio.free =end require "fiddle" require "fiddle/import" require "fiddle/types" module VAudio extend Fiddle::Importer dlload "#{__dir__}/vAudio.dll" include Fiddle::Win32Types extern "int vAudioInit(int)" extern "void vAudioEnd(void)" extern "int vAudioEnableFileType(int, int)" extern "int vAudioSetPlayerType(int)" extern "int vAudioGetPlayerType(void)" extern "int vAudioLoad(char*)" extern "int vAudioLoadFromMemory(void*, int)" extern "int vAudioRelease(int)" extern "int vAudioReleaseAll(void)" extern "int vAudioPlay(int)" extern "int vAudioResume(int)" extern "int vAudioStop(int)" extern "int vAudioStopAll(void)" extern "int vAudioSeek(int, int)" extern "int vAudioGetCurrentTime(int, int*)" extern "int vAudioGetTotalTime(int, int*)" extern "int vAudioIsPlaying(int)" extern "int vAudioSetLoopPoints(int, int, int)" extern "int vAudioGetLoopPoints(int, int*, int*)" extern "int vAudioSetRepeat(int, int)" extern "int vAudioGetRepeat(int, int*)" extern "int vAudioSetVolume(int, double)" extern "int vAudioGetVolume(int, double*)" extern "int vAudioSetPan(int, double)" extern "int vAudioGetPan(int, double*)" extern "int vAudioSetEffect(int, int)" extern "int vAudioSetEffectParam(int, int, void*)" extern "int vAudioGetEffectParam(int, int, void*)" extern "int vAudioSetParamEqNum(int, int)" extern "int vAudioGetParamEqNum(int, int*)" extern "int vAudioSetParamEqParam(int, int, void*)" extern "int vAudioGetParamEqParam(int, int, void*)" extern "int vAudioFadeIn(int, int)" extern "int vAudioResumeFadeIn(int, int)" extern "int vAudioFadeOut(int, int)" extern "int vAudioGetLastError(void)" # VAUDIO_ERR_xxxx Errmsg = { 0 => "NONE", 1 => "DONOT_INIT", 2 => "UNSUPPORTED_DATA", 3 => "INVALID_PARAM", 4 => "INVALID_AUDIOHANDLE", 5 => "UNKNOWN_FILE", 6 => "INVALID_CALL", 7 => "INTERNAL_DX", 8 => "INTERNAL_SYSTEM", 9 => "INVALID_EFFECT_PARAM", } # Support filetype FILETYPES = { "WAVE" => 0, "MP3" => 1, "OGG" => 2, "FLAC" => 3, "MIDI" => 4, } # support player type PLAYERTYPES = { "AUTO" => 0, "NORMAL" => 1, "STREAMING" => 2, } # support effects EFFECTS = { "NONE" => 0, "CHORUS" => 1, "COMPRESSOR" => 2, "DISTORTION" => 4, "ECHO" => 8, "FLANGER" => 16, "GARGLE" => 32, "REVERB" => 64, # "PARAMEQ" => 128, # "I3DL2REVERB" => 256, } EFFECT_NONE = 0 EFFECT_CHORUS = 1 EFFECT_COMPRESSOR = 2 EFFECT_DISTORTION = 4 EFFECT_ECHO = 8 EFFECT_FLANGER = 16 EFFECT_GARGLE = 32 EFFECT_REVERB = 64 # EFFECT_PARAMEQ = 128 # EFFECT_I3DL2REVERB = 256 # Output error message def self.err raise("VAUDIO_ERR_#{Errmsg[vAudioGetLastError()]}") end # initialize vAudio.dll # # @param hwnd [Integer] Window handle def self.init(hwnd) err if vAudioInit(hwnd) == 0 end # End vAudio.dll def self.free vAudioReleaseAll() err if vAudioEnd() end # Set enable filetype # # @param filetype [String] Use filetype. "WAVE", "MP3", "OGG", "FLAC", "MIDI" # @param flag [true,false] true is enable. false is disable. def self.enableFileType(filetype, flag) err if vAudioEnableFileType(FILETYPES[filetype.upcase], ((flag) ? 1 : 0)) == 0 end # Set player type # # @param kind [String] Use player type. "AUTO", "NORMAL", "STREAMING" def self.setPlayerType(kind) err if vAudioSetPlayerType(PLAYERTYPES[kind.upcase]) == 0 end # Load stream # # @param filename [String] Sound file path # @return [Object] Audio class def self.loadStream(filename) return Audio.new(filename, "STREAMING") end # Load sample # # @param filename [String] Sound file path # @return [Object] Audio class def self.loadSample(filename) return Audio.new(filename, "NORMAL") end # Stop all sound def self.stopAll err if vAudioStopAll() == 0 end # Audio Hnadle class Audio # @param filename [String] Sound file path # @param kind [String] Use player type. "AUTO" or "NORMAL" or "STREAMING" def initialize(filename, kind) if filename.class != String then raise "File name is invalid. filename: #{filename} - initialize" end @playertype = kind ::VAudio.err if ::VAudio.vAudioSetPlayerType(PLAYERTYPES[@playertype]) == 0 @ch = ::VAudio.vAudioLoad(filename) ::VAudio.err if @ch == 0 end # Release sound def free ::VAudio.err if ::VAudio.vAudioRelease(@ch) == 0 end # Play # # @param opts [Hash] Options # @option opts :loop [true,false] true is repeat # @option opts :pan [float] pan (Left: -1.0, Center: 0.0, Right: 1.0) # @option opts :volume [float] volume (0.0 - 100.0) def play(opts = {}) self.setRepeat(opts[:loop]) if opts[:loop] self.setPan(opts[:pan]) if opts[:pan] self.setVolume(opts[:volume]) if opts[:volume] ::VAudio.err if ::VAudio.vAudioPlay(@ch) == 0 end # Stop def stop ::VAudio.err if ::VAudio.vAudioStop(@ch) == 0 end # Resume def resume ::VAudio.err if ::VAudio.vAudioResume(@ch) == 0 end # Set volume # # @param vol [float] Volume (0.0 - 100.0) def setVolume(vol) ::VAudio.err if ::VAudio.vAudioSetVolume(@ch, vol) == 0 end # Set pan # # @param pan [float] Pan (Left:-1.0, Center:0.0, Right:1.0) def setPan(pan) ::VAudio.err if ::VAudio.vAudioSetPan(@ch, pan) == 0 end # Set Repeat(loop) # # @param flag [true,false] true is repeat def setRepeat(flag) ::VAudio.err if ::VAudio.vAudioSetRepeat(@ch, ((flag) ? 1 : 0)) == 0 end # Set loop point # # @param starttime [Integer] loop point start time (msec) # @param endtiem [Integer] loop point end time (msec). (-1 : last pos) def setLoopPoints(starttime, endtime) ::VAudio.err if ::VAudio.vAudioSetLoopPoints(@ch, starttime, endtime) == 0 end # Check playing # # @return [true,false] true is playing, false is stopped def isPlaying return ((::VAudio.vAudioIsPlaying(@ch) == 0) ? false : true) end # Get total time # # @return [Integer] total time (msec) def getTotalTime i = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT) ::VAudio.err if ::VAudio.vAudioGetTotalTime(@ch, i) == 0 return i[0, i.size].unpack("i!")[0] end # Get current time # # @return [Integer] current time (msec) def getCurrentTime i = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT) ::VAudio.err if ::VAudio.vAudioGetCurrentTime(@ch, i) == 0 return i[0, i.size].unpack("i!")[0] end # Get volume # # @return [float] Volume (0.0 - 100.0) def getVolume d = Fiddle::Pointer.malloc(Fiddle::SIZEOF_DOUBLE) ::VAudio.err if ::VAudio.vAudioGetVolume(@ch, d) == 0 return d[0, d.size].unpack("d*")[0] end # Get pan # # @return [float] Pan (Left:-1.0, Center:0.0, Right:1.0) def getPan d = Fiddle::Pointer.malloc(Fiddle::SIZEOF_DOUBLE) ::VAudio.err if ::VAudio.vAudioGetPan(@ch, d) == 0 return d[0, d.size].unpack("d*")[0] end # Fadeout # # @param fadetime [Integer] Fade time (msec) def fadeout(fadetime) return unless self.isPlaying() ::VAudio.err if ::VAudio.vAudioFadeOut(@ch, fadetime) == 0 end # Fadein # # @param fadetime [Integer] Fade time (msec) def fadein(fadetime) ::VAudio.err if ::VAudio.vAudioFadeIn(@ch, fadetime) == 0 end # Resume fadein # # @param fadetime [Integer] Fade time (msec) def resumeFadein(fadetime) ::VAudio.err if ::VAudio.vAudioResumeFadeIn(@ch, fadetime) == 0 end # Set effect type # # @param effectflag [Integer] Effect type (0x000 - 0x1ff) def setEffect(effectflag) ::VAudio.err if ::VAudio.vAudioSetEffect(@ch, effectflag) == 0 end end end