Im working on a dial that rotates when a user touches it and drags it around. So far so good, but when the dial gets to more than 360, the value goes back to 0, making the animation jump backwards around the dial instead of continuing.
dialRotation = (atan2(event->localY()-circleCenterY, event->localX()-circleCenterX) * (180/M_PI));
Does anyone know how to stop it from jumping?
You can use the existing value to determine if you should go beyond 360 or not. Perhaps something like this:
currentValue = dialRotation;
dialRotation = (atan2(event->localY()-circleCenterY, event->localX()-circleCenterX) * (180/M_PI));
dialRotation = 360.0 * floor(fmod(currentValue, 360.0)) + dialRotation;
I think this will work in the negative direction, too, though I sometimes get confused by fmod()s behavior for negative numbers, so be sure to check it.
Another way to do it would be to get the delta (the change) between the previous value and the current value and just add that to what you already have. As long as the difference is not greater than 180 degrees, that might work better. Something like this:
// In your class declaration:
float normalizedRotation; // Always between 0 and 360 degrees
float previousNormalizedRotation;
float dialRotation; // current value, can be any valid value from -inf to +inf
// In your method:
normalizedRotation = (atan2(event->localY()-circleCenterY, event->localX()-circleCenterX) * (180/M_PI));
if (normalizedRotation < 0.0) normalizedRotation += 360.0;
float delta = normalizedRotation - previousNormalizedRotation;
previousNormalizedRotation = normalizedRotation;
dialRotation += delta;
Let me know if that works.
Related
I need to collect voice pieces from a continuous audio stream. I need to process later the user's voice piece that has just been said (not for speech recognition). What I am focusing on is only the voice's segmentation based on its loudness.
If after at least 1 second of silence, his voice becomes loud enough for a while, and then silent again for at least 1 second, I say this is a sentence and the voice should be segmented here.
I just know I can get raw audio data from the AudioClip created by Microphone.Start(). I want to write some code like this:
void Start()
{
audio = Microphone.Start(deviceName, true, 10, 16000);
}
void Update()
{
audio.GetData(fdata, 0);
for(int i = 0; i < fdata.Length; i++) {
u16data[i] = Convert.ToUInt16(fdata[i] * 65535);
}
// ... Process u16data
}
But what I'm not sure is:
Every frame when I call audio.GetData(fdata, 0), what I get is the latest 10 seconds of sound data if fdata is big enough or shorter than 10 seconds if fdata is not big enough, is it right?
fdata is a float array, and what I need is a 16 kHz, 16 bit PCM buffer. Is it right to convert the data like: u16data[i] = fdata[i] * 65535?
What is the right way to detect loud moments and silent moments in fdata?
No. you have to read starting at the current position within the AudioClip using Microphone.GetPosition
Get the position in samples of the recording.
and pass the optained index to AudioClip.GetData
Use the offsetSamples parameter to start the read from a specific position in the clip
fdata = new float[clip.samples * clip.channels];
var currentIndex = Microphone.GetPosition(null);
audio.GetData(fdata, currentIndex);
I don't understand what exactly you convert this for. fdata will contain
floats ranging from -1.0f to 1.0f (AudioClip.GetData)
so if for some reason you need to get values between short.MinValue (= -32768) and short.MaxValue(= 32767) than yes you can do that using
u16data[i] = Convert.ToUInt16(fdata[i] * short.MaxValue);
note however that Convert.ToUInt16(float):
value, rounded to the nearest 16-bit unsigned integer. If value is halfway between two whole numbers, the even number is returned; that is, 4.5 is converted to 4, and 5.5 is converted to 6.
you might want to rather use Mathf.RoundToInt first to also round up if a value is e.g. 4.5.
u16data[i] = Convert.ToUInt16(Mathf.RoundToInt(fdata[i] * short.MaxValue));
Your naming however suggests that you are actually trying to get unsigned values ushort (or also UInt16). For this you can not have negative values! So you have to shift the float values up in order to map the range (-1.0f | 1.0f ) to the range (0.0f | 1.0f) before multiplaying it by ushort.MaxValue(= 65535)
u16data[i] = Convert.ToUInt16(Mathf.RoundToInt(fdata[i] + 1) / 2 * ushort.MaxValue);
What you receive from AudioClip.GetData are the gain values of the audio track between -1.0f and 1.0f.
so a "loud" moment would be where
Mathf.Abs(fdata[i]) >= aCertainLoudThreshold;
a "silent" moment would be where
Mathf.Abs(fdata[i]) <= aCertainSiltenThreshold;
where aCertainSiltenThreshold might e.g. be 0.2f and aCertainLoudThreshold might e.g. be 0.8f.
I have an if statement that is meant to check a float that increases over time (It's a timer) the current code is this
if (Day.DateTime == 1080){
ClientsTaken = Random.Range(MinNoOfClients, MaxNoOfClients);
GameObject.Find("Canvas").GetComponent(Brothel).Money += (ClientsTaken *(Cost * GirlMorale));
ClientsSeen += ClientsTaken;
Debug.Log("Clients taken = " + ClientsTaken);
}
The timer is definatly hitting 1080 but nothing is happening. I also tried 1080f but had the same result.
Any help would be greatly appreciated, thanks.
Comparing floating point variables this way is not recommended due to "floating point imprecision" - the way the floating point variables are internally stored on PC.
Instead, you can use Mathf.Approximately(), like this:
if (Mathf.Approximately(Day.DateTime, 1080.0))
{
...
{
I would change the check to Day.DateTime >= 1080. When dealing with floating point numbers you may not land directly on an integer value.
I'm currently working on a Time of Day system, and in that system I want to be able to control at which hour SUNRISE starts, DAY start, SUNSET starts and NIGHT starts. At the moment this is possible in the system and when the "clock" hits the next start hour I start a Coroutine to start the rotating of the sun and moon.
My coroutine looks like this:
IEnumerator RotateSun(Vector3 fDegrees, float SecondsDuringTimeSet)
{
Quaternion quaFromPosition = _lSunLight.transform.rotation;
Quaternion quaToPostion = Quaternion.Euler(fDegrees);
for (float t = 0.0f; t < 1; t += Time.deltaTime / SecondsDuringTimeSet)
{
_lSunLight.transform.rotation = Quaternion.Lerp(quaFromPosition, quaToPostion, t);
yield return null;
}
}
And as you see I pass values into that for each time I run it. This is done like this:
if (_fCurrGameHour == _fTimeStartSunrise && _bMoveSunAndMoonOnlyOnce == true)
{
// Which TIMESET should it be:
_en_CurrTimeSet = TimeSet.SUNRISE;
// How long should the SUN move and how many which degree should it reach before that time ends
vec3MoveSun = new Vector3(10.0f, 0, 0);
StartCoroutine(RotateSun(vec3MoveSun, _fConvertSunriseToGTSeconds));
// How long should the MOON move and how many which degree should it reach before that time ends
vec3MoveMoon = new Vector3(180.0f, 0, 0);
StartCoroutine(RotateMoon(vec3MoveMoon, _fConvertSunriseToGTSeconds));
// Tell bool that we don't need to move the sun and moon more then once
_bMoveSunAndMoonOnlyOnce = false;
}
And as I wrote this system works at the moment. However it is kind of a static system. So at the moment I need to make sure that the starting hour of the game is the sunrise hour. Otherwise my coroutine would break since it would not rotate to the correct position before the day start hour. And I can definitly not start the game close to sunset then the sun rotates the complete wrong way since it's closer to rotate the wrong way then (I assume).
So my first question is: Could I somehow make the system more dynamic? I want to be able to still set at which hours SUNRISE, DAY, SUNSET and NIGHT should start so during different season for example I could have different lengths on my day. I want to be able to change these hours in the game and then if the SUNSET would be set later the sun would start to rotate a little slower since it is supposed to take longer to reach it's SUNSET position.
Onto my second question: Would it also be possible to rewrite my coroutine so I could start the game at any hour I want and the sun would still start at the right degree rotation?
The sun will always set at the same rotation (170 degrees) and rise at the same rotation (350 degree). I just want to control the time it takes before it reaches to those rotations. Maybe I could somehow move this to my update phase instead of using a Coroutine for this? I have no clue how to change this in my system so if anyone have any ideas. Please help.
You can get away from the coroutine by using a State design pattern.
public int SunRise = 8;
public int SunSet = 15;
public Quaternion RiseRotation;
public Quaternion SetRotation;
public int StartHour = 8;
float time; // our time on a 24 hr system
bool wasSun; // what was our previous state?
void Start()
{
GoToHour(StartHour);
ToggleState(IsSun());
}
void Update()
{
bool isSun = IsSun();
if (isSun != wasSun)
ToggleState(isSun);
time = (time + Time.deltaTime) % 24; // wrap at 24 hrs back to 0
if (isSun)
UpdateSun();
else
UpdateMoon();
}
bool IsSun()
{
return time >= SunRise && time < SunSet
}
void UpdateSun()
{
float t = (time - SunRise) / (SunSet - SunRise);
UpdateRotation(_lSunLight.transform, RiseRotation, SetRotation, t);
}
void UpdateMoon()
{
float t;
if (time >= SunRise)
t = time - SunRise;
else
t = time + (24 - SunSet);
t = t / ((24 - SunSet) + SunRise));
UpdateRotation(_lMoonLight.transform, RiseRotation, SetRotation, t);
}
void GoToHour(int hour)
{
t = hour / 24;
}
void ToggleState(bool isSun)
{
if (isSun)
{
// Custom logic here, turn on sun, turn off moon?
}
else
{
// Custom logic here, turn on moon, turn off sun?
}
wasSun = isSun;
}
static void SetRotation(Transform target, Quaternion start, Quaternion end, float t)
{
target.rotation = Quaternion.Lerp(start, end, t);
}
Completely untested code, but this is a base idea for how you can use a class to update either the sun or the moon. This is a binary implementation, so either the sun is showing, or the moon is. If you want to have overlap, you can of course customize it do that easily. You will want different hours for the moon rise and moon set, and then not if/else the moon and sun update.
The code is also pretty basic and makes a lot of assumptions (sunrise never overlaps the 24 hour mark.) All of these can be cleaned up. You can also create variables to store calculations that are done each frame (regarding the duration of the sunrise/set) at your discretion. If you want to do that, just set it in the GoToHour method.
The SetRotation isn't super necessary, but it serves to keep the code clean. If you later decide you want to use a Quaternion.Slerp, you only have to change it in one place.
I exposed Quaternions in the inspector, you may rather using just a float for degrees, or a Euler Vecter3. If you do either, you can just do a conversion in the Start.
I hope this answered all your questions, if not, feel free to clarify on what isn't answered.
My question is a little tricky, and I'm not exactly experienced (I might get some terms wrong), so here goes.
I'm declaring an instance of an object called "Singer". The instance is called "singer1". "singer1" produces an audio signal. Now, the following is the code where the specifics of the audio signal are determined:
OSStatus playbackCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData) {
//Singer *me = (Singer *)inRefCon;
static int phase = 0;
for(UInt32 i = 0; i < ioData->mNumberBuffers; i++) {
int samples = ioData->mBuffers[i].mDataByteSize / sizeof(SInt16);
SInt16 values[samples];
float waves;
float volume=.5;
for(int j = 0; j < samples; j++) {
waves = 0;
waves += sin(kWaveform * 600 * phase)*volume;
waves += sin(kWaveform * 400 * phase)*volume;
waves += sin(kWaveform * 200 * phase)*volume;
waves += sin(kWaveform * 100 * phase)*volume;
waves *= 32500 / 4; // <--------- make sure to divide by how many waves you're stacking
values[j] = (SInt16)waves;
values[j] += values[j]<<16;
phase++;
}
memcpy(ioData->mBuffers[i].mData, values, samples * sizeof(SInt16));
}
return noErr;
}
99% of this is borrowed code, so I only have a basic understanding of how it works (I don't know about the OSStatus class or method or whatever this is. However, you see those 4 lines with 600, 400, 200 and 100 in them? Those determine the frequency. Now, what I want to do (for now) is insert my own variable in there in place of a constant, which I can change on a whim. This variable is called "fr1". "fr1" is declared in the header file, but if I try to compile I get an error about "fr1" being undeclared. Currently, my technique to fix this is the following: right beneath where I #import stuff, I add the line
fr1=0.0;//any number will work properly
This sort of works, as the code will compile and singer1.fr1 will actually change values if I tell it to. The problems are now this:A)even though this compiles and the tone specified will play (0.0 is no tone), I get the warnings "Data definition has no type or storage class" and "Type defaults to 'int' in declaration of 'fr1'". I bet this is because for some reason it's not seeing my previous declaration in the header file (as a float). However, again, if I leave this line out the code won't compile because "fr1 is undeclared". B)Just because I change the value of fr1 doesn't mean that singer1 will update the value stored inside the "playbackcallback" variable or whatever is in charge of updating the output buffers. Perhaps this can be fixed by coding differently? C)even if this did work, there is still a noticeable "gap" when pausing/playing the audio, which I need to eliminate. This might mean a complete overhaul of the code so that I can "dynamically" insert new values without disrupting anything. However, the reason I'm going through all this effort to post is because this method does exactly what I want (I can compute a value mathematically and it goes straight to the DAC, which means I can use it in the future to make triangle, square, etc waves easily). I have uploaded Singer.h and .m to pastebin for your veiwing pleasure, perhaps they will help. Sorry, I can't post 2 HTML tags so here are the full links.
(http://pastebin.com/ewhKW2Tk)
(http://pastebin.com/CNAT4gFv)
So, TL;DR, all I really want to do is be able to define the current equation/value of the 4 waves and re-define them very often without a gap in the sound.
Thanks. (And sorry if the post was confusing or got off track, which I'm pretty sure it did.)
My understanding is that your callback function is called every time the buffer needs to be re-filled. So changing fr1..fr4 will alter the waveform, but only when the buffer updates. You shouldn't need to stop and re-start the sound to get a change, but you will notice an abrupt shift in the timbre if you change your fr values. In order to get a smooth transition in timbre, you'd have to implement something that smoothly changes the fr values over time. Tweaking the buffer size will give you some control over how responsive the sound is to your changing fr values.
Your issue with fr being undefined is due to your callback being a straight c function. Your fr variables are declared as objective-c instance variables as part of your Singer object. They are not accessible by default.
take a look at this project, and see how he implements access to his instance variables from within his callback. Basically he passes a reference to his instance to the callback function, and then accesses instance variables through that.
https://github.com/youpy/dowoscillator
notice:
Sinewave *sineObject = inRefCon;
float freq = sineObject.frequency * 2 * M_PI / samplingRate;
and:
AURenderCallbackStruct input;
input.inputProc = RenderCallback;
input.inputProcRefCon = self;
Also, you'll want to move your callback function outside of your #implementation block, because it's not actually part of your Singer object.
You can see this all in action here: https://github.com/coryalder/SineWaver
So I have a very simple game going here..., right now the AI is nearly perfect and I want it to make mistakes every now and then. The only way the player can win is if I slow the computer down to a mind numbingly easy level.
My logic is having a switch case statement like this:
int number = randomNumber
case 1:
computer moves the complete opposite way its supposed to
case 2:
computer moves the correct way
How can I have it select case 2 68% (random percentage, just an example) of the time, but still allow for some chance to make the computer fail? Is a switch case the right way to go? This way the difficulty and speed can stay high but the player can still win when the computer makes a mistake.
I'm on the iPhone. If there's a better/different way, I'm open to it.
Generating Random Numbers in Objective-C
int randNumber = 1 + rand() % 100;
if( randNumber < 68 )
{
//68% path
}
else
{
//32% path
}
int randomNumber = GeneraRandomNumberBetweenZeroAndHundred()
if (randomNumber < 68) {
computer moves the complete opposite way its supposed to
} else {
computer moves the correct way
}
Many PRNGs will offer a random number in the range [0,1). You can use an if-statement instead:
n = randomFromZeroToOne()
if n <= 0.68:
PlaySmart()
else:
PlayStupid()
If you're going to generate an integer from 1 to N, instead of a float, beware of modulo bias in your results.