Save-Point
Audio Module - Printable Version

+- Save-Point (https://www.save-point.org)
+-- Forum: Material Development (https://www.save-point.org/forum-8.html)
+--- Forum: Scripts Database (https://www.save-point.org/forum-39.html)
+---- Forum: C++ and SFML Code (https://www.save-point.org/forum-113.html)
+---- Thread: Audio Module (/thread-8457.html)



Audio Module - Kain Nobel - 01-23-2022

Audio Module (C++ / SFML)
Version 0.2

Description

This is a C++ rewrite of the RPG Maker Audio module implemented with Simple and Fast Multimedia Library by Laurent Gomilla and team.

The end user is responsible for compiling and deploying this in their project. I may provide a plug-n-play DLL later but for now its all on you to figure it out.

The system is written to RGSS3 specifications (and should be backwards compatible with RGSS and RGSS2 since all it does is add features and doesn't change fundamentals.) I have not implemented this in Ruby or any of the RPG Maker systems. It might be awhile but I will get back to that at a later date.

Features
  • Supports multiple filetypes; wavoggflac, probably others.
  • Play 1 Background Music
  • Play 1 Background Sound
  • Play 1 Music Effect
  • Play multiple Sound Effects
  • Adjust fade in/fade out timing of Music Effects
  • Available Functions : Play, Pause, Stop, Fade In/Out, Replay, Volume=, Pitch=
  • Please see SFML/Audio for more information.

(NOTE: Lack of mp3 support is a legal issue, apparently. This is outside the scope of my script and more related to SFML. End user is responsible for implementing their own mp3 support, if desired. (I find ogg to be a better format, personally. Ogg BGM and BGS seem to loop better than mp3 so I actually encourage people to switch formats.))

Requirements
  • SFML (Simple and Fast Multimedia Library)
  • Should only require SFML/Audio (for audio) and SFML/System (for sf::Time functionality). See header file for more details.
  • Working knowledge of C++ and the build tools required to compile and run it.

Instructions

This is NOT a plug-n-play RPG Maker script, you'd need to compile it yourself with C++ and configure it to your needs.
While this is designed to be RGSS compliant, it has not been implemented in Ruby/RPG Maker.
I'm just sharing it for anybody who can do something with it.
If I get the C++ and Ruby to communicate, I will return with a full plug-in-play implementation anyone can use.

Content Hidden

Differences from Original RGSS

There are minor differences between this and the vanilla RGSS, RGSS2 and RGSS3 implementations (personal taste)...
  • When playing Music Effects, all other audio (BGM, BGS, SE) fade out in 2 seconds instead of instant.
  • When playing Music Effects, the volume of all other audio is reduced to 10 instead of 0.
  • When playing Music Effects, the volume fades in approximately 4 seconds. Adjustable.
  • These timing features should be easily adjustable by changing the member variable values in the header file.
  • NOTE: The Fade Out for music effects should be a minimum of 1.0f or it won't fade out at all. Of course, you can edit the script yourself if you're trying to do, say, a half second.

Source Files

RGL/Audio.hpp
Content Hidden

RGL/Audio.cpp
Content Hidden

Author's Notes

Notes : Classes and Memory

Content Hidden

Notes : What Could Be Improved?

Content Hidden

Notes : About (lack of) rbSFML Bindings

I am well aware that there is a SFML bindings for Ruby (rbSFML). It doesn't look like it has been updated in 6 years and I don't know if anybody still uses or supports it, nor do I know how stable it is. The SFML forum doesn't have a sub-forum for it in their bindings so I can only assume rbSFML may not be a stable library? I made the personal choice to do this without rbSFML. I would like to learn for myself how to extend Ruby with C++ so it was a personal choice to do it in C++.

Thank you for checking it out, feel free to lend me a hand if you know anything about this stuff.

Terms and Conditions

End user is responsible for figuring out how to compile and use this themselves. I will only be providing limited support and future updates.
Free to use in commercial and non-commercial projects, you don't even have to credit me (but I do like credits -_^).
SFML has its own terms under the ZLIB/PNG License. SFML is an open source multimedia library written by Laurent Gomilla and a team of programming ninjas.


RE: Audio Module (C++ / SFML) - kyonides - 01-24-2022

I've come up with an idea of how one could manually create some Ruby class from C code.
So in few words this means we are using CRuby code here.

As I had commented in my sample code, it definitely ignores how a C string is converted to a sf::String object. Thus it won't let you compile anything unless that gets resolved first.

According to SMFL C strings should be automatically converted to sf::Strings.

Update 2

Code:
/*=============================================================================*/
// ** rgl::Audio's Ruby Binding as Audio module
/*-----------------------------------------------------------------------------*/
/*
  Simply call the following:
    Init_rgl_audio();
  from any main function for any binary executable or create a Ruby gem.

  C strings should be automatically converted to sf::Strings according to SMFL.
*/

#include "rgl_audio.hpp"
#include <ruby.h>

#define RMF(func) ((VALUE (*)(ANYARGS))(func))

static VALUE rgl_audio_play_bgm(int size, VALUE* args, VALUE self)
{
  if (size == 0)
    return rgl::Audio.playBGM() ? Qtrue : Qfalse;
  const char* fn = StringValueCStr(args[0]);
  if (size == 1)
    return rgl::Audio.playBGM(fn) ? Qtrue : Qfalse;
  bool result;
  float volume = NUM2DBL(args[1]);
  if (size == 2) {
    result = rgl::Audio.playBGM(fn, volume);
  } else if (size == 3) {
    float pitch = NUM2DBL(args[2]);
    result = rgl::Audio.playBGM(fn, volume, pitch);
  }
  return result ? Qtrue : Qfalse;
}

static VALUE rgl_audio_replay_bgm(VALUE self)
{
  return rgl::Audio.replayBGM() ? Qtrue : Qfalse;
}

static VALUE rgl_audio_pause_bgm(VALUE self)
{
  rgl::Audio.pauseBGM();
  return Qnil;
}

static VALUE rgl_audio_stop_bgm(VALUE self)
{
  rgl::Audio.stopBGM();
  return Qnil;
}

static VALUE rgl_audio_fade_bgm(VALUE self, VALUE rvolume, VALUE rduration)
{
  float volume = NUM2DBL(rvolume), duration = NUM2DBL(rduration);
  rgl::Audio.fadeBGM(volume, duration);
  return Qnil;
}

static VALUE rgl_audio_play_bgs(int size, VALUE* args, VALUE self)
{
  if (size == 0)
    return rgl::Audio.playBGS() ? Qtrue : Qfalse;
  const char* fn = StringValueCStr(args[0]);
  if (size == 1)
    return rgl::Audio.playBGS(fn) ? Qtrue : Qfalse;
  bool result;
  float volume = NUM2DBL(args[1]);
  if (size == 2) {
    result = rgl::Audio.playBGS(fn, volume);
  } else if (size == 3) {
    float pitch = NUM2DBL(args[2]);
    result = rgl::Audio.playBGS(fn, volume, pitch);
  }
  return result ? Qtrue : Qfalse;
}

static VALUE rgl_audio_replay_bgs(VALUE self)
{
  return rgl::Audio.replayBGS() ? Qtrue : Qfalse;
}

static VALUE rgl_audio_pause_bgs(VALUE self)
{
  rgl::Audio.pauseBGS();
  return Qnil;
}

static VALUE rgl_audio_stop_bgs(VALUE self)
{
  rgl::Audio.stopBGS();
  return Qnil;
}

static VALUE rgl_audio_fade_bgs(VALUE self, VALUE rvolume, VALUE rduration)
{
  float volume = NUM2DBL(rvolume), duration = NUM2DBL(rduration);
  rgl::Audio.fadeBGS(volume, duration);
  return Qnil;
}

static VALUE rgl_audio_play_me(int size, VALUE* args, VALUE self)
{
  if (size == 0)
    return rgl::Audio.playME() ? Qtrue : Qfalse;
  const char* fn = StringValueCStr(args[0]);
  if (size == 1)
    return rgl::Audio.playME(fn) ? Qtrue : Qfalse;
  bool result;
  float volume = NUM2DBL(args[1]);
  if (size == 2) {
    result = rgl::Audio.playME(fn, volume);
  } else if (size == 3) {
    float pitch = NUM2DBL(args[2]);
    result = rgl::Audio.playME(fn, volume, pitch);
  }
  return result ? Qtrue : Qfalse;
}

static VALUE rgl_audio_replay_me(VALUE self)
{
  return rgl::Audio.replayME() ? Qtrue : Qfalse;
}

static VALUE rgl_audio_pause_me(VALUE self)
{
  rgl::Audio.pauseME();
  return Qnil;
}

static VALUE rgl_audio_stop_me(VALUE self)
{
  rgl::Audio.stopME();
  return Qnil;
}

static VALUE rgl_audio_fade_me(VALUE self, VALUE rvolume, VALUE rduration)
{
  float volume = NUM2DBL(rvolume), duration = NUM2DBL(rduration);
  rgl::Audio.fadeME(volume, duration);
  return Qnil;
}

static VALUE rgl_audio_play_se(int size, VALUE* args, VALUE self)
{
  if (size == 0)
    return rgl::Audio.playSE() ? Qtrue : Qfalse;
  const char* fn = StringValueCStr(args[0]);
  if (size == 1)
    return rgl::Audio.playSE(fn) ? Qtrue : Qfalse;
  bool result;
  float volume = NUM2DBL(args[1]);
  if (size == 2) {
    result = rgl::Audio.playSE(fn, volume);
  } else if (size == 3) {
    float pitch = NUM2DBL(args[2]);
    result = rgl::Audio.playSE(fn, volume, pitch);
  }
  return result ? Qtrue : Qfalse;
}

static VALUE rgl_audio_replay_se(VALUE self)
{
  return rgl::Audio.replaySE() ? Qtrue : Qfalse;
}

static VALUE rgl_audio_pause_se(VALUE self)
{
  rgl::Audio.pauseSE();
  return Qnil;
}

static VALUE rgl_audio_stop_se(VALUE self)
{
  rgl::Audio.stopSE();
  return Qnil;
}

static VALUE rgl_audio_fade_se(VALUE self, VALUE rvolume, VALUE rduration)
{
  float volume = NUM2DBL(rvolume), duration = NUM2DBL(rduration);
  rgl::Audio.fadeSE(volume, duration);
  return Qnil;
}

static VALUE rgl_audio_update(VALUE self)
{
  rgl::Audio.update();
  return Qnil;
}

static VALUE rgl_audio_reset(VALUE self)
{
  rgl::Audio.reset();
  return Qnil;
}

static VALUE rgl_audio_fade_all(VALUE self, VALUE rvolume, VALUE rduration)
{
  float volume = NUM2DBL(rvolume), duration = NUM2DBL(rduration);
  rgl::Audio.fadeAll(volume, duration);
  return Qnil;
}

void Init_rgl_audio()
{
  VALUE module = rb_define_module("Audio");
  rb_define_module_function(module, "play_bgm", RMF(rgl_audio_play_bgm), -1);
  rb_define_module_function(module, "replay_bgm", RMF(rgl_audio_replay_bgm), 0);
  rb_define_module_function(module, "pause_bgm", RMF(rgl_audio_pause_bgm), 0);
  rb_define_module_function(module, "stop_bgm", RMF(rgl_audio_stop_bgm), 0);
  rb_define_module_function(module, "fade_bgm", RMF(rgl_audio_fade_bgm), 2);
  rb_define_module_function(module, "play_bgs", RMF(rgl_audio_play_bgs), -1);
  rb_define_module_function(module, "replay_bgs", RMF(rgl_audio_replay_bgs), 0);
  rb_define_module_function(module, "pause_bgs", RMF(rgl_audio_pause_bgs), 0);
  rb_define_module_function(module, "stop_bgs", RMF(rgl_audio_stop_bgs), 0);
  rb_define_module_function(module, "fade_bgs", RMF(rgl_audio_fade_bgs), 2);
  rb_define_module_function(module, "play_me", RMF(rgl_audio_play_me), -1);
  rb_define_module_function(module, "replay_me", RMF(rgl_audio_replay_me), 0);
  rb_define_module_function(module, "pause_me", RMF(rgl_audio_pause_me), 0);
  rb_define_module_function(module, "stop_me", RMF(rgl_audio_stop_me), 0);
  rb_define_module_function(module, "fade_me", RMF(rgl_audio_fade_me), 2);
  rb_define_module_function(module, "play_se", RMF(rgl_audio_play_se), -1);
  rb_define_module_function(module, "replay_se", RMF(rgl_audio_replay_se), 0);
  rb_define_module_function(module, "pause_se", RMF(rgl_audio_pause_se), 0);
  rb_define_module_function(module, "stop_se", RMF(rgl_audio_stop_se), 0);
  rb_define_module_function(module, "fade_se", RMF(rgl_audio_fade_se), 2);
  rb_define_module_function(module, "update", RMF(rgl_audio_update), 0);
  rb_define_module_function(module, "reset", RMF(rgl_audio_reset), 0);
  rb_define_module_function(module, "fade_all", RMF(rgl_audio_fade_all), 2);
}

Yeah, I've gained some experience after compiling this kind of rubygem or library while working on my HiddenChest project. Laughing
So in theory I might be capable of building it on Linux... if I had the full RGL source code, of course. Winking


RE: Audio Module - Kain Nobel - 01-25-2022

That's so cool you put that together for me :D

Now I just need to figure out how its supposed to be used o.o

Thank you :D