[Already In] Per-actor sound pitch shifting

Moderator: GZDoom Developers

Per-actor sound pitch shifting

Postby bLUEbYTE » Sat Dec 28, 2019 2:14 am

Hi,
I have looked through ZScript functions and Actor properties but couldn't find anything that comes close to what I want to do.

I've made a simple & universal monster randomiser mod in ZScript. It randomly resizes the monsters, making 'midget' or 'giant' versions of them randomly. It then scales the monster horizontally and vertically scaling via A_SetScale, sets its mass, etc. Hence I have a single float value that's designating the 'weight' of the monster. Now, it would be great to do pitch scaling on actor's sounds based on such a scalar value held in the actor's properties.

My code looks like the following:
Code: Select allExpand view
         let resized = a.A_SetSize(a.Radius * width, a.Height * height, true);
         if (resized)
         {
                                let weight = width * height;
                                a.A_SetScale(a.Scale.X * width, a.Scale.Y * height);
                                ...


So if there was a function such as A_ScaleSound(), I could just pass the weight value (which is centered around 1.0) to pitch shift its voice dynamically, creating a ton of sonic variety and a semblance of realism using a one liner.

I think that would be like the sonic version of A_ScaleVelocity.

Or, I could have a ton of SNDINFO defini... Naah, don't even want to think about that :blergh:
bLUEbYTE
 
Joined: 15 Nov 2019
Location: Australia
Graphics Processor: Intel with Vulkan Support

Re: Per-actor sound pitch shifting

Postby bLUEbYTE » Sat Dec 28, 2019 2:39 am

Hmm, just found out about the A_SoundPitch function added in 4.2.4, and there's https://github.com/coelckers/gzdoom/blo ... s.cpp#L145

Maybe there is a way to accomplish this already?
bLUEbYTE
 
Joined: 15 Nov 2019
Location: Australia
Graphics Processor: Intel with Vulkan Support

Re: Per-actor sound pitch shifting

Postby _mental_ » Sat Dec 28, 2019 2:45 am

A_SoundPitch() was added in 4.2.0, and it does exactly what you need.
_mental_
 
 
 
Joined: 07 Aug 2011

Re: Per-actor sound pitch shifting

Postby bLUEbYTE » Sat Dec 28, 2019 4:31 am

Hi _mental_,

I don't want to turn this into a support topic but I can't do what I want without replacing every monster class explicitly it seems.

This doesn't work:
Code: Select allExpand view
class ReVoicedActor : Actor replaces Actor
{
   override void Tick()
   {
      Super.Tick();
      if (bIsMonster)
      {
         A_SoundPitch(CHAN_VOICE, 0.5);
      }
   }
}


If instead of Actor, I use e.g. ZombieMan, it works.

What I wanted is to be able to statefully set an actor's voice pitch from within such a scope:
Code: Select allExpand view
class UEHandler : EventHandler
{
   override void WorldThingSpawned(WorldEvent e)
   {
      super.WorldThingSpawned(e);

      Actor a = e.Thing;
      
      if (a.bIsMonster)
      {
                      ...


It seems I won't be able to do this as I don't know how to / seems impossible to override the actor's Tick() method in the above context. If you have an idea on how, please let me know. Another method I though of was maybe setting a custom attribute in the matched actors above (inside the if scope), and then do the Tick() override in a replacement for the Actor class, but that won't work as the first example illustrates.

Thanks anyway.
bLUEbYTE
 
Joined: 15 Nov 2019
Location: Australia
Graphics Processor: Intel with Vulkan Support

Re: Per-actor sound pitch shifting

Postby Player701 » Sat Dec 28, 2019 4:38 am

bLUEbYTE wrote:
Code: Select allExpand view
Actor replaces Actor

This will never work, since "replaces" can only replace instances of actors that get spawned into a level. It is not possible to modify an existing class this way.

You can probably achieve what you want with an inventory item. Any actor, not just a player, can possess an inventory item. Put whatever code you need in the Tick override of your item class. The actor currently in possession of the item is accessed via the Owner variable (make sure it's not null before you attempt to dereference it, or you may get an address zero abort).
User avatar
Player701
 
Joined: 13 May 2009
Location: Russia
Discord: Player701#8214
Operating System: Windows 10/8.1/8/201x 64-bit
OS Test Version: No (Using Stable Public Version)
Graphics Processor: nVidia with Vulkan support

Re: Per-actor sound pitch shifting

Postby bLUEbYTE » Sat Dec 28, 2019 4:46 am

Hi Player701,
Really appreciate your idea as I had literally started in ZScript today.

I think I get what you mean. So through the Owner reference in the dummy item, I will be able to override the owner actor's Tick() method? I'll try to find some example code. Might get back to you with a question or two.
bLUEbYTE
 
Joined: 15 Nov 2019
Location: Australia
Graphics Processor: Intel with Vulkan Support

Re: Per-actor sound pitch shifting

Postby Player701 » Sat Dec 28, 2019 5:30 am

bLUEbYTE wrote:So through the Owner reference in the dummy item, I will be able to override the owner actor's Tick() method?

No, not the owner's Tick, but the item's Tick. In there, you reference the owner and do the stuff you want with it. Example code:

Code: Select allExpand view
class UEHandler : EventHandler
{
    override void WorldThingSpawned(WorldEvent e)
    {
        super.WorldThingSpawned(e);

        Actor a = e.Thing;
     
        if (a.bIsMonster)
        {
            a.A_GiveInventory('PitchShifter');
        }
    }
}

class PitchShifter : Inventory
{
    override void Tick()
    {
        Super.Tick();
       
        if (Owner != null)
        {
            Owner.A_SoundPitch(CHAN_VOICE, 0.5);
        }
    }
}

Please do keep in mind that I haven't actually tested this code, but chances are it will probably work just fine.
User avatar
Player701
 
Joined: 13 May 2009
Location: Russia
Discord: Player701#8214
Operating System: Windows 10/8.1/8/201x 64-bit
OS Test Version: No (Using Stable Public Version)
Graphics Processor: nVidia with Vulkan support

Re: Per-actor sound pitch shifting

Postby Graf Zahl » Sat Dec 28, 2019 5:35 am

It's not that simple. Pitch is tracked per played sound, not per actor, so this only works with explicit sound play calls, there are no facilities to automatically apply a general pitch shift to an actor and the pitch randomization functionality is useless. It may make sense to allow setting pitches per defined sound in SNDINFO but even then it'd require a new actor to use the pitched sounds.
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
 
Joined: 19 Jul 2003
Location: Germany

Re: Per-actor sound pitch shifting

Postby bLUEbYTE » Sat Dec 28, 2019 5:39 am

I was about to give up and then saw your response.

It works! There is only one thing I need to do now; save the unique scalar value somehow in the item per actor rather than always scaling the pitch by 0.5.

Here's the full code so far:
Code: Select allExpand view
version "4.2.4"

const RR = 0.33; // Randomise the values by this much, -/+

class UEHandler : EventHandler
{
   override void WorldThingSpawned(WorldEvent e)
   {
      super.WorldThingSpawned(e);

      Actor a = e.Thing;
      
      if (a.bIsMonster)
      {
         let width =  frandom(1.0 - RR, 1.0 + RR);
         let height = frandom(1.0 - RR, 1.0 + RR);
         
         let resized = a.A_SetSize(a.Radius * width, a.Height * height, true);
         if (resized)
         {
            let weight = width * height;

            a.Health *= weight;
            a.Mass *= weight;
            a.PainChance /= weight;
            a.SetDamage(a.Damage * weight);
            a.A_SetSpeed(a.Speed / weight);
            a.A_SetScale(a.Scale.X * width, a.Scale.Y * height);
            
            a.A_GiveInventory('PitchShifter');
         }
      }
   }
}

class PitchShifter : Inventory
{
    override void Tick()
    {
        Super.Tick();
       
        if (Owner != null)
        {
            Owner.A_SoundPitch(CHAN_VOICE, 0.5);
        }
    }
}
bLUEbYTE
 
Joined: 15 Nov 2019
Location: Australia
Graphics Processor: Intel with Vulkan Support

Re: Per-actor sound pitch shifting

Postby bLUEbYTE » Sat Dec 28, 2019 5:46 am

Graf Zahl wrote:It's not that simple. Pitch is tracked per played sound, not per actor, so this only works with explicit sound play calls, there are no facilities to automatically apply a general pitch shift to an actor and the pitch randomization functionality is useless. It may make sense to allow setting pitches per defined sound in SNDINFO but even then it'd require a new actor to use the pitched sounds.


Yep, definitely would like to avoid redefining / duplicating the classes. And the mod will be universal that way. Player701's suggestion got me almost there, I just need to carry over the weight parameter to the actors now, somehow. Perhaps using https://zdoom.org/wiki/ZScript_custom_properties ? I hope I won't have to have unique dummy items per pitch shift amount.
bLUEbYTE
 
Joined: 15 Nov 2019
Location: Australia
Graphics Processor: Intel with Vulkan Support

Re: Per-actor sound pitch shifting

Postby Player701 » Sat Dec 28, 2019 5:53 am

bLUEbYTE wrote:There is only one thing I need to do now; save the unique scalar value somehow in the item per actor rather than always scaling the pitch by 0.5.

You need to add a variable to PitchShifter:

Code: Select allExpand view
class PitchShifter : Inventory
{
    double pitchFactor;
   
    ...
}

In A_SoundPitch call, replace 0.5 with pitchFactor.

Then, add to UEHandler after the call to A_GiveInventory:

Code: Select allExpand view
let shifter = PitchShifter(a.FindInventory('PitchShifter'));

if (shifter != null)
{
    shifter.pitchFactor = YourValueHere; // <-- Put your value here
}

Again, please do keep in mind that I haven't tested this, but I think it should work.
User avatar
Player701
 
Joined: 13 May 2009
Location: Russia
Discord: Player701#8214
Operating System: Windows 10/8.1/8/201x 64-bit
OS Test Version: No (Using Stable Public Version)
Graphics Processor: nVidia with Vulkan support

Re: Per-actor sound pitch shifting

Postby bLUEbYTE » Sat Dec 28, 2019 6:26 am

Player701, you're a legend. Works flawlessly.
Thanks guys. I'll release the first version of the mod today in this forum.

edit: here it is viewtopic.php?f=43&t=66778
bLUEbYTE
 
Joined: 15 Nov 2019
Location: Australia
Graphics Processor: Intel with Vulkan Support


Return to Closed Feature Suggestions

Who is online

Users browsing this forum: No registered users and 0 guests