Please login or register.

Login with username, password and session length
Advanced search  

News:

IRC channel - server: waelisch.de  channel: #wme (read more)

Author Topic: How to crossfade two music files  (Read 19869 times)

0 Members and 1 Guest are viewing this topic.

Jerrot

  • Global Moderator
  • Addicted to WME forum
  • *
  • Karma: 0
  • Offline Offline
  • Gender: Male
  • Posts: 690
    • View Profile
How to crossfade two music files
« on: June 07, 2003, 12:32:45 AM »

Hiya!

Now - here is my first snippet. The goal was a smooth crossfade to a new music file when jumping to the next scene.

First I had to create an entity for the music files. Actually I used two entities, but they are using the same file.

There should be a "SOUNDPANNING=FALSE" in it, but for some weird reason it crashes currently. So I chosed the position to center the entity on a 800x600 game screen. Anyway I hope this bug to be corrected soon, I'm not sure if this is a bug of my script or of WME. I will correct and edit this article as soon as I know it better. ;)

music\music.entity :

Code: [Select]
ENTITY {
  NAME="music"
  CAPTION=""
  ACTIVE=TRUE
  X=400
  Y=300
  SCALABLE=FALSE
  INTERACTIVE=FALSE
  COLORABLE=FALSE
}

Notice that I didn't load any soundfile yet.

In the Game.script I added two lines before changing to the scene to load the entities:

Code: [Select]
global music1 = Game.LoadEntity("music\music.entity");
global music2 = Game.LoadEntity("music\music.entity");


Ok. Now we jump into our scene. I wanted this scene to play "music\my_music_file.ogg" when entering.

I added these lines to the scene_init.script:

Code: [Select]
#include "scripts\func_music.inc"

PlayMusicX("music\my_music_file.ogg");

That's it ? YES! Well ok, of course there is the included function:

scripts\func_music.inc:

Code: [Select]
// Music functions v0.2 (Jerrot, 2003-06-07)

global music1;
global music2;

function PlayMusicX(musicfile)
{
  //---------------------------------------------------------------------
  // Starts to play a musicfile. Uses a fading/crossover if another music
  // is already playing.
  //
  // Syntax:  PlayMusicX(musicfile)
  // Sample:  PlayMusicX("music\wintermutesong.ogg");
  //---------------------------------------------------------------------
     
  var old_channel, new_channel, counter;

  // when entering a scene, we don't know, which channel entity is
  // playing currently. so we have to check this here:

  if (music1.IsSoundPlaying())
  {
    old_channel = music1;
    new_channel = music2;
  }
  else if (music2.IsSoundPlaying())
  {
    old_channel = music2;
    new_channel = music1;
  }
  else
  {
    // in case no music was playing (e.g. when starting the game) we just have
    // to load the sound file into our channel entity and leave the function.

    new_channel = music1;
    new_channel.SetSoundVolume(100);
    new_channel.PlaySound(musicfile,true);
    return;
  }
 
  // this is a very simple crossover. counting to 100, the volume of the old_channel
  // is decreased to zero, while the volume of the new_channel is increased to 100.
  // the Sleep(50) command sets the speed of the crossfading.

  new_channel.SetSoundVolume(0);
  new_channel.PlaySound(musicfile,true);
  for(counter=1; counter<=100; counter=counter+1)
  {
    old_channel.SetSoundVolume(100-counter);
    new_channel.SetSoundVolume(counter);
    Sleep(50);
  }
  old_channel.StopSound();

  // That's it! Enjoy!
 
  return;
}

« Last Edit: June 07, 2003, 12:50:26 AM by Jerrot »
Logged
Mooh!

Mnemonic

  • WME developer
  • Administrator
  • Addicted to WME forum
  • *
  • Karma: 41
  • Offline Offline
  • Gender: Male
  • Posts: 5683
    • View Profile
    • Dead:Code Site
Re:How to crossfade two music files
« Reply #1 on: June 07, 2003, 08:56:44 AM »

Cool, man! Works like a charm.
May I have a small suggestion? If you put the entity loading code into this function, you won't have to modify game.script at all:
Code: [Select]
function PlayMusicX(musicfile)
{
  global music1;
  global music2;
  if(music1==null) music1 = Game.LoadEntity("music\music.entity");
  if(music2==null) music2 = Game.LoadEntity("music\music.entity");
  ...


There should be a "SOUNDPANNING=FALSE" in it, but for some weird reason it crashes currently.

It's "SOUND_PANNING". It shoudn't crash, though...

Logged
Yes, I do have a twitter account
Please don't send me technical questions in private messages, use the forum. ::wave

odnorf

  • w00t?
  • Global Moderator
  • Addicted to WME forum
  • *
  • Karma: 7
  • Offline Offline
  • Gender: Male
  • Posts: 1456
  • Lamp dog!
    • View Profile
Re:How to crossfade two music files
« Reply #2 on: June 07, 2003, 10:33:17 AM »

Thanks Jerrot for the great script!
May I make another suggestion?
I think that it could work with a GlobalMusicVolume too.

Code: [Select]
global music1;
global music2;

// Get the global music volume
global MusicVolume = Game.GetGlobalMusicVolume

function PlayMusicX(musicfile)
{
  //---------------------------------------------------------------------
  // Starts to play a musicfile. Uses a fading/crossover if another music
  // is already playing.
  //
  // Syntax:  PlayMusicX(musicfile)
  // Sample:  PlayMusicX("music\wintermutesong.ogg");
  //---------------------------------------------------------------------
     
  var old_channel, new_channel, counter;

  // when entering a scene, we don't know, which channel entity is
  // playing currently. so we have to check this here:

  if (music1.IsSoundPlaying())
  {
    old_channel = music1;
    new_channel = music2;
  }
  else if (music2.IsSoundPlaying())
  {
    old_channel = music2;
    new_channel = music1;
  }
  else
  {
    // in case no music was playing (e.g. when starting the game) we just have
    // to load the sound file into our channel entity and leave the function.

    new_channel = music1;
    new_channel.SetSoundVolume(MusicVolume);
    new_channel.PlaySound(musicfile,true);
    return;
  }
 
  // this is a very simple crossover. counting to "MusicVolume", the volume of the old_channel
  // is decreased to zero, while the volume of the new_channel is increased to "MusicVolume".
  // the Sleep(50) command sets the speed of the crossfading.

  new_channel.SetSoundVolume(0);
  new_channel.PlaySound(musicfile,true);
  for(counter=1; counter<=MusicVolume; counter=counter+1)
  {
    old_channel.SetSoundVolume(MusicVolume-counter);
    new_channel.SetSoundVolume(counter);
    Sleep(50);
  }
  old_channel.StopSound();

  // That's it! Enjoy!
 
  return;
}

Ofcouse the game that is going to use this script must have a menu, so that the player can adjust the GlobalMusicVolume.
Mnemonic, does the SetGlobalMusicVolume adjusts the music volume in real time, or only after a restore? Is the volume saved in the registry or only in the saved games? The Game.GetGlobalMusicVolume reads the value from the registry or a saved game?
Logged
fl*p

Mnemonic

  • WME developer
  • Administrator
  • Addicted to WME forum
  • *
  • Karma: 41
  • Offline Offline
  • Gender: Male
  • Posts: 5683
    • View Profile
    • Dead:Code Site
Re:How to crossfade two music files
« Reply #3 on: June 07, 2003, 12:09:22 PM »

Mnemonic, does the SetGlobalMusicVolume adjusts the music volume in real time, or only after a restore? Is the volume saved in the registry or only in the saved games? The Game.GetGlobalMusicVolume reads the value from the registry or a saved game?
Yes, SetGlobalMusicVolume works in realtime, the value is stored in registry (i.e. it's a per-user setting), and always GetGlobalMusicVolume reflects the current volume.
Logged
Yes, I do have a twitter account
Please don't send me technical questions in private messages, use the forum. ::wave

odnorf

  • w00t?
  • Global Moderator
  • Addicted to WME forum
  • *
  • Karma: 7
  • Offline Offline
  • Gender: Male
  • Posts: 1456
  • Lamp dog!
    • View Profile
Re:How to crossfade two music files
« Reply #4 on: June 07, 2003, 02:03:12 PM »

Quote
Yes, SetGlobalMusicVolume works in realtime, the value is stored in registry (i.e. it's a per-user setting), and always GetGlobalMusicVolume reflects the current volume.

Does this mean that the modified Jerrot code's with the Game.GetGlobalMusicVolume works? I don't have the time to test it now.
Logged
fl*p

Mnemonic

  • WME developer
  • Administrator
  • Addicted to WME forum
  • *
  • Karma: 41
  • Offline Offline
  • Gender: Male
  • Posts: 5683
    • View Profile
    • Dead:Code Site
Re:How to crossfade two music files
« Reply #5 on: June 07, 2003, 06:32:03 PM »

odnorf: But note that Jerrot's code only manipulates the volume when crossfading. You'd have to catch the user modyfing music volume (e.g. in a settings window) and then change the volume of our music1 and music2 entities.
Logged
Yes, I do have a twitter account
Please don't send me technical questions in private messages, use the forum. ::wave

odnorf

  • w00t?
  • Global Moderator
  • Addicted to WME forum
  • *
  • Karma: 7
  • Offline Offline
  • Gender: Male
  • Posts: 1456
  • Lamp dog!
    • View Profile
Re:How to crossfade two music files
« Reply #6 on: June 07, 2003, 07:05:11 PM »

Hmmm... that's true. The modified Jerrot's code works well if we don't change the GlobalMusicVolume while it crossfades. But if we change the volume then it will work only when we change the scene. I'll think a better way when I got the time (and I'll got a lot of free time in 2-3 days).
Logged
fl*p

Jerrot

  • Global Moderator
  • Addicted to WME forum
  • *
  • Karma: 0
  • Offline Offline
  • Gender: Male
  • Posts: 690
    • View Profile
Re:How to crossfade two music files
« Reply #7 on: June 09, 2003, 10:14:13 PM »

May I have a small suggestion? If you put the entity loading code into this function, you won't have to modify game.script at all:

Oh, right, that'd be better - I will update my post tomorrow. (too tired today)

Quote
It's "SOUND_PANNING". It shoudn't crash, though...

Ah! Works! :) Actually I just guessed - the entity attribute by scripting is "SoundPanning", the ".entity" file format is not documented yet and I just tried it like "active", "scalable", etc. !

BTW it does not crash, but the "Loading..." appears and stays.

« Last Edit: June 09, 2003, 10:14:34 PM by Jerrot »
Logged
Mooh!

Jerrot

  • Global Moderator
  • Addicted to WME forum
  • *
  • Karma: 0
  • Offline Offline
  • Gender: Male
  • Posts: 690
    • View Profile
Re:How to crossfade two music files
« Reply #8 on: June 10, 2003, 09:22:15 AM »

Hmmm... that's true. The modified Jerrot's code works well if we don't change the GlobalMusicVolume while it crossfades.

Yep, that's what I told you by MSN, the for-next could get in trouble. Maybe one should check this in the loop - and if the volume was altered while proceeding the function, it should just exit the crossfading and set the new volume. Guess that's easy. Although I'm not sure yet, if the whole thing wouldn't be better replaced by some built-in function doing this stuff here.

But if we change the volume then it will work only when we change the scene. I'll think a better way when I got the time (and I'll got a lot of free time in 2-3 days).

I did not get the last one - if you change the volume by some settings screen, you can set the SoundVolumes of both music entities and your code should work.

Logged
Mooh!

odnorf

  • w00t?
  • Global Moderator
  • Addicted to WME forum
  • *
  • Karma: 7
  • Offline Offline
  • Gender: Male
  • Posts: 1456
  • Lamp dog!
    • View Profile
Re:How to crossfade two music files
« Reply #9 on: June 10, 2003, 12:53:52 PM »

Hmmm... that's true. The modified Jerrot's code works well if we don't change the GlobalMusicVolume while it crossfades.

Yep, that's what I told you by MSN, the for-next could get in trouble. Maybe one should check this in the loop - and if the volume was altered while proceeding the function, it should just exit the crossfading and set the new volume. Guess that's easy. Although I'm not sure yet, if the whole thing wouldn't be better replaced by some built-in function doing this stuff here.

But if we change the volumes in the for-next loop some nasty things might happen. For example, the volumes can go to a negative number (I just tested it). Ofcourse it can be solved by using a few if() but the code gets agly and the volume-changes while crossfading sounds bad. It seems that I am too lazy right now to do more tests... And I have to agry again with you that a built-in function is a much better idea.
Like Crossfade(MusicX, SpeedValue)
« Last Edit: June 10, 2003, 12:55:29 PM by odnorf »
Logged
fl*p

Jerrot

  • Global Moderator
  • Addicted to WME forum
  • *
  • Karma: 0
  • Offline Offline
  • Gender: Male
  • Posts: 690
    • View Profile
Re:How to crossfade two music files
« Reply #10 on: June 10, 2003, 01:23:33 PM »

the volumes can go to a negative number (I just tested it).

By calculating them with percent values it should work without negative numbers, but I did not test it yet, the current solution works as example. And as you already suggested - just don't let the user change the volume while crossfading. :)

And I have to agry again with you that a built-in function is a much better idea.
Like Crossfade(MusicX, SpeedValue)

Of course it would not be as flexible as it is in the scripted version, but it would be perfect for scripting newbies. Unfortunately it would not be enough for my purposes (I want to do fadings with 3 sound files).
Logged
Mooh!

Mnemonic

  • WME developer
  • Administrator
  • Addicted to WME forum
  • *
  • Karma: 41
  • Offline Offline
  • Gender: Male
  • Posts: 5683
    • View Profile
    • Dead:Code Site
Re:How to crossfade two music files
« Reply #11 on: June 10, 2003, 01:26:17 PM »

Like Crossfade(MusicX, SpeedValue)

Yep, but more like:

Game.PlayMusicCrossfade(Filename, TotalDuration, CrossfadeDuration)

i.e. if you set CrossfadeDuration to zero, one song will fade out THEN second song will fade in.
Logged
Yes, I do have a twitter account
Please don't send me technical questions in private messages, use the forum. ::wave

odnorf

  • w00t?
  • Global Moderator
  • Addicted to WME forum
  • *
  • Karma: 7
  • Offline Offline
  • Gender: Male
  • Posts: 1456
  • Lamp dog!
    • View Profile
Re:How to crossfade two music files
« Reply #12 on: June 10, 2003, 04:21:47 PM »

Quote
Of course it would not be as flexible as it is in the scripted version, but it would be perfect for scripting newbies. Unfortunately it would not be enough for my purposes (I want to do fadings with 3 sound files).

Three sound files? :) :) :) I don't believe that even iMuse system can do that (at least I can't remember it) :) Anyway, I mainly focus on graphics for dreams (many surprises are coming in the next months)... I don't even know if there will be one piece of music in dreams.

Quote
Game.PlayMusicCrossfade(Filename, TotalDuration, CrossfadeDuration)

So... this is a "todo" now? :)
Logged
fl*p

odnorf

  • w00t?
  • Global Moderator
  • Addicted to WME forum
  • *
  • Karma: 7
  • Offline Offline
  • Gender: Male
  • Posts: 1456
  • Lamp dog!
    • View Profile
Re:How to crossfade two music files
« Reply #13 on: June 13, 2003, 12:45:41 PM »

Ok... this crossfade function can handle volume changes in real-time.... It might be even better (like change the volume nicer and not just BUMP the volume ups) but I don't have the energy to do something like that.... Maybe someother day! :) Have fun!

Code: [Select]
global music1, music2;

// if this is the first time we play a music file then load the two music entities
if(music1==null) music1 = Game.LoadEntity("music\music.entity");
if(music2==null) music2 = Game.LoadEntity("music\music.entity");

// Get the global music volume
global MusicVolume = Game.GetGlobalMusicVolume();

function PlayMusicX(musicfile)
{
  //---------------------------------------------------------------------
  // Starts to play a musicfile. Uses a fading/crossover if another music
  // is already playing.
  //
  // Syntax:  PlayMusicX(musicfile)
  // Sample:  PlayMusicX("music\wintermutesong.ogg");
  //---------------------------------------------------------------------
   
  var old_channel, new_channel;

  // when entering a scene, we don't know, which channel entity is
  // playing currently. so we have to check this here:

  if(music1.IsSoundPlaying())
  {
    old_channel = music1;
    new_channel = music2;
  }
  else if(music2.IsSoundPlaying())
  {
    old_channel = music2;
    new_channel = music1;
  }
  else
  {
    // in case no music was playing (e.g. when starting the game) we just have
    // to load the sound file into our channel entity and leave the function.

    new_channel = music1;
    new_channel.SetSoundVolume(MusicVolume);
    new_channel.PlaySound(musicfile,true);
    return;
  }

  // This is a crossover for the two music files. Counting to "MusicVolume", the volume of
  // the old channel is decreased to zero, while the volume of the new_channel is increased
  // to "MusicVolume". If the GlobalMusicVolume change while the two music files crossfading
  // the crossover function changes both file's volumes in real-time.
  // The Sleep() command sets the speed of the crossfading. Bigger number will make the
  // crossfade slower.

  new_channel.SetSoundVolume(0);
  new_channel.PlaySound(musicfile,true);
 
  var VolumeStart = Game.GetGlobalMusicVolume();

  for(var counter=0; counter<=MusicVolume; counter=counter+1)
  {
    var OldMusicVolume, MusicDiff;
    var VolumeOldChannel, VolumeNewChannel;

    // We check the difference in volume changes in %
    // for example, if MusicVolume was 60 and we change it to 100
    // then the difference would be 100/60 = 1.66 (= 166%)
    // If nothing changes then MusicDiff = 1
    OldMusicVolume = MusicVolume;
    MusicVolume = Game.GetGlobalMusicVolume();
    MusicDiff = MusicVolume/OldMusicVolume;
     
    // We calculate the volumes by multiply the old values with the % difference
    VolumeOldChannel = (VolumeStart-counter)*MusicDiff;
    VolumeNewChannel = counter*MusicDiff;
   
    // The volumes must integer numbers
    VolumeOldChannel = ToInt(VolumeOldChannel);
    VolumeNewChannel = ToInt(VolumeNewChannel);

    // We change the volume of the files
    old_channel.SetSoundVolume(VolumeOldChannel);
    new_channel.SetSoundVolume(VolumeNewChannel);

    // We make the volume changes permanent
    VolumeStart = VolumeStart*MusicDiff;
    counter = counter*MusicDiff;
   
    // counter must be an integer number
    counter = ToInt(counter);

    Sleep(50);
  }

  // the old_channel has zero volume now, so we can stop it
  old_channel.StopSound();

  return;
}

EDIT: I added some comments in the for-next loop to be easier to understand the code.
« Last Edit: June 14, 2003, 11:32:12 AM by odnorf »
Logged
fl*p

Jerrot

  • Global Moderator
  • Addicted to WME forum
  • *
  • Karma: 0
  • Offline Offline
  • Gender: Male
  • Posts: 690
    • View Profile
Re:How to crossfade two music files
« Reply #14 on: June 24, 2003, 11:13:43 AM »

Ok... this crossfade function can handle volume changes in real-time...

Yeah, great work, now I got it (and thanks for the advanced comments...) !! ;D

It seems I was just too stupid to test it (I thought the volume values range to be 0-255 instead of 0-100). After I corrected MY code, your updated version worked perfectly, even with some really evil hard-coded volume changes.

 8)
Logged
Mooh!
 

Page created in 0.02 seconds with 24 queries.