- Home /
Affecting all audio with slow motion but can't reset to original pitc
The script can slow down the pitch when it goes into slow motion but it can't go back to the original pitch, it just stays slowed down.Also the more I go in and out of slow-mo the slower the pitch gets.
using UnityEngine;
using System.Collections;
public class SoundModifier : MonoBehaviour
{
public float[] pitchs;
public float[] oldPitchs;
public AudioSource[] audioSources;
void Update ()
{
StartCoroutine("GetPitch");
}
IEnumerator GetPitch()
{
audioSources = FindObjectsOfType(typeof(AudioSource)) as AudioSource[];
if(OverClock.isOverClock == false){
oldPitchs = new float[audioSources.Length];
pitchs = new float[audioSources.Length];
}
for(int i = 0; i <= audioSources.Length; i++)
{
pitchs[i] = audioSources[i].pitch;
if(OverClock.isOverClock == false){
audioSources[i].pitch = oldPitchs[i];
oldPitchs[i] = audioSources[i].pitch;
//pitchs[i] = oldPitchs[i];
}
//when i press q it slow down time and this becomes true
if(OverClock.isOverClock == true)
{
//pitchs[i] = oldPitchs[i] * Time.timeScale;
audioSources[i].pitch = oldPitchs[i] * Time.timeScale;
}
if(i == audioSources.Length)
break;
}
yield return null;
}
}
Answer by iwaldrop · Jan 04, 2014 at 06:54 PM
Its hard to pin down your problem, because the code looks way too complicated to me for what it's doing, so I slapped this together. It currently uses the mouse wheel to dynamically control the pitch, but you can easily change it back to using a button.
AudioPitchController.cs
using UnityEngine;
using System.Collections;
public class AudioPitchController : MonoBehaviour
{
public delegate void PitchChange(float value);
public static event PitchChange OnPitchChange;
private float lastPitch;
void Update()
{
float pitch = Input.GetAxis("Mouse ScrollWheel");
if (pitch != lastPitch)
{
lastPitch = pitch;
if (OnPitchChange != null)
OnPitchChange(pitch * Time.deltaTime);
}
}
}
AudioPitchModifier.cs
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(AudioSource))]
public class AudioPitchModifier : MonoBehaviour
{
const float PITCH_LIMIT = 3;
void OnEnable()
{
AudioPitchController.OnPitchChange += HandleOnPitchChange;
}
void OnDisable()
{
AudioPitchController.OnPitchChange -= HandleOnPitchChange;
}
void HandleOnPitchChange (float value)
{
audio.pitch = Mathf.Clamp(audio.pitch + value, -PITCH_LIMIT, PITCH_LIMIT);
}
}
Explaining thoroughly what this does would help.Because I have no idea what an event or delegate is.Also, my code was fetching all of the audio sources not just one.
An event is a collection of methods that match the delegate's signature used. That is to say, any method which matches the signature of the delegate can be subscribed to the event so that calling a single event is the same as calling all of the subscribed methods. Take note that the method signature of HandleOn$$anonymous$$chChange matches the signature of the delegate $$anonymous$$chChange.
This code uses that so that you don't have to fetch any sources at all. Each source has it's own controller that listens for events from a central place. So, in this example the Controller monitors the "$$anonymous$$ouse ScrollWheel" Input Axis (which is setup by default in every new Unity project), and sends an event which all of the $$anonymous$$ch$$anonymous$$odifiers listen to and take action with.
I posted the code so that you could copy it and check it out for yourself. It really doesn't get any simpler than what's going on here. If you have specific questions, please ask them. I'm happy to answer them, but nothing explains the code better than itself.
Thanks for the explanation and code.It isn't what I wanted but I can make it work.I wanted to dynamically alter all audio sources but, I can just dynamically just attach the Audio$$anonymous$$ch$$anonymous$$odifier code, until I can find a better way. Also where did you learn delegate and events(I would like to learn better solutions and cause I have to refractor a lot of code).
I see. Are you working with prefabs? Simply attach the script at design time. If you're creating new game objects, simply use AddComponent to add the Audio$$anonymous$$ch$$anonymous$$odifier.
Either way, they will automatically subscribe and unsubscribe when activated or deactivated. This may have unintended consequences as well. For instance, if you deactivate a gameObject and then change the pitch, once the game object is enabled again it won't have received the signal. In this case, move the unsubscribe code to OnDestroy ins$$anonymous$$d.
Another corner case that I can see right off the bat is right when you instantiate an object. You'll have to add a little bit of code in the OnEnable method to get the global pitch from the Controller. This will ensure that the pitch on newly created game objects will be what they should be. I don't think your existing code handled this case either. The code might look like this:
Audio$$anonymous$$ch$$anonymous$$odifier.cs
void Awake()
{
audio.pitch = Audio$$anonymous$$chController.Current$$anonymous$$ch;
}
Secondly, I don't recall when or where I learned about using events, but you can always check $$anonymous$$SDN and do some Google searching. I strongly encourage you to check them out, as they're a powerful tool for developers.
Thirdly, Get$$anonymous$$ch is a poorly named method, as it's not returning, or getting, anything (except the obligatory IEnumerator that's used by the Coroutine mechanism).
And finally, I would encourage you to also try fafase's suggested answer. But also keep in $$anonymous$$d that running that logic every frame is pointless. It's best not to start a coroutine inside an update loop. In fact, your coroutine doesn't need to be a coroutine at all, because it simply waits one frame at the end and doesn't do any work over frames, so could just as well be in the update loop, or be a void method called every frame in update (although I think this approach is also wasteful; personally I avoid using the Update method where ever possible, but obviously it's needed to poll input).
Answer by fafase · Jan 04, 2014 at 10:31 AM
I would think the issue comes from your update. You are calling a new coroutine each frame. You should use a boolean to get only one call:
bool isSlow = false;
void Update ()
{
if(!isSlow)
{
StartCoroutine("GetPitch");
isSlow = true;
}
}
Then wherever you stop the slow effect you set isSlow back to false when getting back to normal speed.
I would think you need to modify your scripts in a way that new audio sources are taken care as well. I mean that if during slow motion you create a new sound then it won*t be affected so you need to make it in a way that when creating new ones, they check the value of that boolean and change their pitch in accordance.