Android SensorManager registerListener - not possible to set custom interval of sensor events - android-sensors

I wanted to set an individual interval of sensor events beside:
the given delays: "SENSOR_DELAY_NORMAL, SENSOR_DELAY_U, SENSOR_DELAY_GAME, ENSOR_DELAY_FASTEST".
But non of the "registerListener" methodes seems to support an individual value:
Looking into the implementation of the SensorManager class shows:
public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs,
int maxBatchReportLatencyUs) {
int delay = getDelay(rateUs);
return registerListenerImpl(listener, sensor, delay, null,maxBatchReportLatencyUs, 0);
}
private static int getDelay(int rate) {
int delay = -1;
switch (rate) {
case SENSOR_DELAY_FASTEST:
delay = 0;
break;
case SENSOR_DELAY_GAME:
delay = 20000;
break;
case SENSOR_DELAY_UI:
delay = 66667;
break;
case SENSOR_DELAY_NORMAL:
delay = 200000;
break;
default:
delay = rate;
break;
}
return delay;
}
Is there realy no way to set an individual value for the sensor event interval?

SENSOR_DELAY_NORMAL, SENSOR_DELAY_UI, etc are all simply integers, as shown in your code. Saying you want SENSOR_DELAY_UI is the same as telling the sensor manager to use an interval of 66667 microseconds. However, per the docs, you can simply input your own interval in that field:
The desired delay between two consecutive events in microseconds. This is only a hint to the system. Events may be received faster or slower than the specified rate. Usually events are received faster. Can be one of SENSOR_DELAY_NORMAL, SENSOR_DELAY_UI, SENSOR_DELAY_GAME, SENSOR_DELAY_FASTEST or the delay in microseconds.
However, it's important to note the other part of that quote:
...The desired delay between two consecutive events in microseconds. This is only a hint to the system....
At the end of the day, it's just a suggestion and the Android system doesn't seem to be too good about respecting your request. If you really care about the interval I would suggest adding a method in your callback that checks the time delta between now and the last time you recorded a sensor value and then only recording it if its been sufficiently long.
Source: Android Link

You can simply use a Timer and a boolean flag to handle this problem:
imagine you want to check sensor event values every 1 seconds(for example):
boolean mustReadSensor;
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
mustReadSensor = true;
}
}, 0, 1000); // 1000 ms delay
and here is onSensorChanged:
#Override
public void onSensorChanged(SensorEvent event) {
if (!mustReadSensor) {
return;
}
mustReadSensor = false;
//handle sensor values here
}

Related

How to code latch switch function using STM32?

I am looking a code to get the latch switch function using STM32.
The below code which I have tried is working in stm32 but only a push button function without latch.
while (1)
{
if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13)== GPIO_PIN_RESET )
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
}
else
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);
}
}
Can some one help me to make the GPIOA,GPIO_PIN_5 pin high always on the first press of the button and the GPIOA,GPIO_PIN_5 low always at the second press ?
The function will be similar as in the below video https://www.youtube.com/watch?v=zzWzSPdxA0U
Thank you all in advance.
There are several problems with the code. There is no memory function and you are reading the button at max speed.
This is fixed by sleeping for a period of time to allow for human reaction speed and button noise. You also need a variable to store the previous state.
while (1)
{
if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13)== GPIO_PIN_RESET )
{
static bool state = false;
if(state == false)
{
state = true;
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
}
else
{
state = false
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);
}
while(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13)== GPIO_PIN_RESET){} // wait for button to be released, otherwise it will keep toggling every 500ms
}
delay_ms(500);
}
This is C++ code as it uses bool. int with the values 1 and 0 can be used for C.
What is done is a variable state is declared and kept in heap memory because of the static keyword. (Instead of stack memory which would be destroyed when the scope of the outer if statement is exited) It is initialized to false and then updated when you press the button.
Possible (crude) solution:
#include <stdbool.h>
#define BUTTON_DOWN() (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_RESET)
#define LED(on) HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, (on) ? GPIO_PIN_SET : GPIO_PIN_RESET)
static bool _pressed_before = false;
static bool _led = false;
/* somewhere in main loop */
{
const bool pressed = BUTTON_DOWN();
if (pressed && !_pressed_before) { /* button pressed? */
_led = !_led; /* toggle LED state */
LED(_led);
}
_pressed_before = pressed; /* remember state */
}
Some notes:
Instead of constantly polling the state, you could use an external GPIO interrupt (search for GPIO EXTI). And it is almost always necessary to use hardware debouncing on the button pin (RC filter) and/or use software debouncing to prevent falsely detected edges. - Also: This question is not really STM32 / hardware specific, so you could find more general answers by searching the webs more broadly on these topics.

Check microphone for silence

While recording user voice, i want to know when he/she stopped talking to end the recording and send the audio file to google speech recognition API.
I found this thread here and tried to use it's solution but i am always getting the same value from the average of spectrum data which is 5.004574E-08:
Unity - Microphone check if silent
This is the code i am using for getting the GetSpectrumData value:
public void StartRecordingSpeech()
{
//If there is a microphone
if (micConnected)
{
if (!Microphone.IsRecording(null))
{
goAudioSource.clip = Microphone.Start(null, true, 10, 44100); //Currently set for a 10 second clip max
goAudioSource.Play();
StartCoroutine(StartRecordingSpeechCo());
}
}
else
{
Debug.LogError("No microphone is available");
}
}
IEnumerator StartRecordingSpeechCo()
{
while (Microphone.IsRecording(null))
{
float[] clipSampleData = new float[128];
goAudioSource.GetSpectrumData(clipSampleData, 0, FFTWindow.Rectangular);
Debug.Log(clipSampleData.Average());
yield return null;
}
}
PS: I am able to record the users voice, save it and get the right response from the voice recognition api.
The following method is what worked for me. it detect the volume of the microphone, turn it into decibels. It does not need to play the recorded audio or anything. (credit goes to this old thread in the unity answers: https://forum.unity.com/threads/check-current-microphone-input-volume.133501/).
public float LevelMax()
{
float levelMax = 0;
float[] waveData = new float[_sampleWindow];
int micPosition = Microphone.GetPosition(null) - (_sampleWindow + 1); // null means the first microphone
if (micPosition < 0) return 0;
goAudioSource.clip.GetData(waveData, micPosition);
// Getting a peak on the last 128 samples
for (int i = 0; i < _sampleWindow; i++)
{
float wavePeak = waveData[i] * waveData[i];
if (levelMax < wavePeak)
{
levelMax = wavePeak;
}
}
float db = 20 * Mathf.Log10(Mathf.Abs(levelMax));
return db;
}
In my case, if the value is bigger then -40 then the user is talking!if its 0 or bigger then there is a loud noise, other then that, its silence!
If you are interested in a volume then GetSpectrumData is actually not really what you want. This is used for frequency analysis and returns - as the name says - a frequency spectrum so how laud is which frequency in a given frequency range.
What you rather want to use is GetOutputData which afaik returns an array with amplitudes from -1 to 1. So you have to square all values, get the average and take the square root of this result (source)
float[] clipSampleData = new float[128];
goAudioSource.GetOutputData(clipSampleData, 0);
Debug.Log(Mathf.Sqrt(clipSampleData.Select(f => f*f).Average()));

Unity 2D: How to decrement static int in while loop using deltaTime

In my Player script I set a static int called boost to be used from any script.
I have a few boost pick up coins through out the game, when the player gets one it fills their boost tank by +1
You need a min of 3 boost coins to start boosting in the vehicle. When the player is using boost, the boost will last for about as many seconds as many boost coins collected. Using the boost should decrement the boost tank.
Player Script
public static int boost;
private void OnTriggerEnter2D(Collider2D otherObject)
{
if (otherObject.tag == "Boost")
{
boost++;
GetComponent<AudioSource>().PlaySound(BoostSound, 5.7F);
Destroy(otherObject.gameObject);
}
}
Button call code
public void BoostButton()
{
StartCoroutine("Use_VehicleBoost");
}
Booster code that a button calls.
IEnumerator Use_VehicleBoost()
{
// Check which boost package player picked
int boostLevel = SecurePlayerPrefs.GetInt("BoostLevel");
if (boostLevel == 0)
{
Debug.Log("Boost Level: None");
yield return null;
}
else if (boostLevel == 1)
{
Debug.Log("Boost Level: 1");
float aceleRate = 400, maxFWD = -2500;
while (Player.boost >= 3)
{
vehicleController.GetComponent<CarMovement>().accelerationRate += aceleRate;
vehicleController.GetComponent<CarMovement>().maxFwdSpeed += maxFWD;
// Meant to slowly take one point/ Time second away from boost tank // Problem is here ----->>>
Player.boost = Player.boost - Mathf.RoundToInt(Time.deltaTime);
yield return null;
}
if (Player.boost <= 0)
{
yield return null;
}
}
yield return null;
}
Problem is here in this line
Player.boost = Player.boost - Mathf.RoundToInt(Time.deltaTime);
It is supposed to be decrementing with seconds from Player.boost. For example if player collects 3 boost coins then boost is active when used it will last for 3 seconds before turning off.
Not exactly sure on what to do here. They told me that in the while loop the deltaTime stays at value 0 because its stuck in one frame? Am I supposed to start a timer variable? Thank you.
Not exactly sure on what to do here. They told me that in the while
loop the deltaTime stays at value 0 because its stuck in one frame? Am
I supposed to start a timer variable?
Yes, I did say that but you have fixed the one frame issue with yield return null; which let's the loop to wait one frame therefore giving Time.deltaTime chance to change. Even with that being fixed, there is still 0 issue I told you but because while (Player.boost >= 3) is still true. That is true because Mathf.RoundToInt(Time.deltaTime); is returning zero. You can verify this with Debug.Log(Mathf.RoundToInt(Time.deltaTime)).
If Player.boost type is an int, change it to a float type, to gradually decrease it with Time.deltaTime directly:
while (Player.boost >= 3)
{
vehicleController.GetComponent<CarMovement>().accelerationRate += aceleRate;
vehicleController.GetComponent<CarMovement>().maxFwdSpeed += maxFWD;
// Meant to slowly take one point/ Time second away from boost tank
Player.boost = Player.boost - Time.deltaTime;
//OR Player.boost -= Time.deltaTime;
yield return null;
}
If Player.boost type is an int but you don't want to change it to float, remove the Time.deltaTime as that's used for float values then do the waiting with WaitForSeconds. With this you can subtract one from boost after each WaitForSeconds call.
while (Player.boost >= 3)
{
vehicleController.GetComponent<CarMovement>().accelerationRate += aceleRate;
vehicleController.GetComponent<CarMovement>().maxFwdSpeed += maxFWD;
// Meant to slowly take one point/ Time second away from boost tank
Player.boost = Player.boost - 1;
//OR Player.boost -= 1;
yield return new WaitForSeconds(1f);
}

Part of my PlayerExpChangeEvent is being overridden by vanilla

I'm making a spigot plugin (version 1.8.8) that has an function that I know works because it fires flawlessly through my command. However, when I call it at the end of a PlayerExpChangeEvent, it seems like vanilla leveling overrides the bar, making it go up way more that it is supposed to. Running the command/function after this happens makes the bar go back to how it is supposed to be. I've tried setting my event's priority to highest (and when that didn't work, to lowest) but no matter what my function appears to be completely ignored when called inside the event.
Here is some code:
#EventHandler(priority=EventPriority.HIGHEST)
public void onXpGain(PlayerExpChangeEvent event)
{
// Load custom levels from config
ArrayList<String> levelList = new ArrayList<String>(plugin.getConfig().getStringList("levels"));
if (!((String)levelList.get(0)).equals("none"))
{
Player player = event.getPlayer();
Iterator<String> var4 = levelList.iterator();
while (var4.hasNext())
{
String s = (String)var4.next();
String[] splits = s.split(" ");
int levelCompare = Integer.parseInt(splits[0]);
int playerLvl = player.getLevel();
// Detect if on correct tier, else continue iteration
if (playerLvl == levelCompare - 1)
{
// Calculate the player's new XP amount
int totalXp = player.getTotalExperience() + event.getAmount();
player.setTotalExperience(totalXp);
updateBar(event.getPlayer()); // <-- THIS IS THE FUNCTION
return;
}
}
// At max level
player.setTotalExperience(player.getTotalExperience() + event.getAmount());
player.setLevel(getHighestLevel(levelList));
player.setExp(1.0f);
}
}
And here is the function itself. Keep in mind that it works fine when called through a command and not an event. It's purpose is to use the player's total XP to set the level and bar. Neither set correctly in the event; it instead embraces vanilla leveling.
public static void updateBar(Player player) {
ArrayList<String> levelList = new ArrayList<String>(plugin.getConfig().getStringList("levels"));
int totalXp = player.getTotalExperience();
player.setLevel(getHighestLevelForXp(totalXp, levelList));
if (player.getLevel() < getHighestLevel(levelList)) {
int lvlDiff = getTotalXpToLevel(player.getLevel() + 1,levelList) - getTotalXpToLevel(player.getLevel(),levelList);
int xpDiff = totalXp - getTotalXpToLevel(player.getLevel(),levelList);
player.setExp((float)xpDiff/lvlDiff);
} else {
player.setLevel(getHighestLevel(levelList));
player.setExp(0.0f);
}
return;
}
The command where the function works correctly is a bare-bones call to the function and doesn't need a mention here. Does anyone know how to get my event to override vanilla xp gain? The update works through the command, just not natural xp gain. It is already confirmed that the event DOES fire, as the rest of the event changes the internal xp amount, but the visual effects are overridden by vanilla. Can anyone help? Thanks.
Only setting the Player's EXP won't be enough for your desired behaviour. The Vanilla behaviour will still complete, as you're not changing how the event will add EXP to the player.
Currently, your event is working like this:
And PlayerExpGainEvent isn't cancellable, so you cannot undo it's addition of EXP.
What you can do instead is to set the EXP the event will add to 0, therefore not changing the player's EXP after your interception.
event.setAmount(0); //Cancelling the EXP addition
I would recommend to set your event to a high priority, so that other events that depend on Experience gain won't trigger when you set the amount gained to 0.

How to offset note scheduling for interactive recording of notes via user controls

In the code below I have a note scheduler that increments a variable named current16thNote up to 16 and then looping back around to 1. The ultimate goal of the application is to allow the user to click a drum pad and push the current16thNote value to an array. On each iteration of current16thNote a loop is run on the track arrays looking for the current current16thNote value, if it finds it the sound will play.
//_________________________________________________________General variable declarations
var isPlaying = false,
tempo = 120.0, // tempo (in beats per minute)
current16thNote = 1,
futureTickTime = 0.0,
timerID = 0,
noteLength = 0.05; // length of "beep" (in seconds)
//_________________________________________________________END General variable declarations
//_________________________________________________________Load sounds
var kick = audioFileLoader("sounds/kick.mp3"),
snare = audioFileLoader("sounds/snare.mp3"),
hihat = audioFileLoader("sounds/hihat.mp3"),
shaker = audioFileLoader("sounds/shaker.mp3");
//_________________________________________________________END Load sounds
//_________________________________________________________Track arrays
var track1 = [],
track2 = [5, 13],
track3 = [],
track4 = [1, 3, 5, 7, 9, 11, 13, 15];
//_________________________________________________________END Track arrays
//_________________________________________________________Future tick
function futureTick() {
var secondsPerBeat = 60.0 / tempo;
futureTickTime += 0.25 * secondsPerBeat;
current16thNote += 1;
if (current16thNote > 16) {
current16thNote = 1
}
}
//_________________________________________________________END Future tick
function checkIfRecordedAndPlay(trackArr, sound, beatDivisionNumber, time) {
for (var i = 0; i < trackArr.length; i += 1) {
if (beatDivisionNumber === trackArr[i]) {
sound.play(time);
}
}
}
//__________________________________________________________Schedule note
function scheduleNote(beatDivisionNumber, time) {
var osc = audioContext.createOscillator(); //____Metronome
if (beatDivisionNumber === 1) {
osc.frequency.value = 800;
} else {
osc.frequency.value = 400;
}
osc.connect(audioContext.destination);
osc.start(time);
osc.stop(time + noteLength);//___________________END Metronome
checkIfRecordedAndPlay(track1, kick, beatDivisionNumber, time);
checkIfRecordedAndPlay(track2, snare, beatDivisionNumber, time);
checkIfRecordedAndPlay(track3, hihat, beatDivisionNumber, time);
checkIfRecordedAndPlay(track4, shaker, beatDivisionNumber, time);
}
//_________________________________________________________END schedule note
//_________________________________________________________Scheduler
function scheduler() {
while (futureTickTime < audioContext.currentTime + 0.1) {
scheduleNote(current16thNote, futureTickTime);
futureTick();
}
timerID = window.requestAnimationFrame(scheduler);
}
//_________________________________________________________END Scheduler
The Problem
In addition to the previous code I have some user interface controls as shown in the following image.
When a user mousedowns on a “drum pad” I want to do two things. The first is to hear the sound immediately , and the second is to push the current16thNote value to the respective array.
If I use the following code to do this a few problems emerge.
$("#kick").on("mousedown", function() {
kick.play(audioContext.currentTime)
track1.push(current16thNote)
})
The first problem is that the sound plays twice. This is because when the sound is pushed to the array it is immediately recognized by the next iteration of the note scheduler and immediately plays. I fixed this by creating a delay with setInterval to offset the push to the array.
$("#kick").on("mousedown", function() {
kick.play(audioContext.currentTime)
window.setTimeout(function() {
track1.push(note)
}, 500)
})
The second problem is musical.
When a user clicks a drum pad the value that the user anticipates the drum will be recorded at is one 16th value earlier. In other words if you listen to the metronome and click on the kick drum pad with the intent of landing right on the 1/1 down beat this won't happen. Instead, when the metronome loops back around it will have been “recorded” at one 16th increment later.
This can be remedied by writing code that intentionally offsets the value that is pushed to the array by -1 .
I wrote a helper function named pushNote to do this.
$("#kick").on("mousedown", function() {
var note = current16thNote;
kick.play(audioContext.currentTime)
window.setTimeout(function() {
pushNote(track1, note)
}, 500)
})
//________________________________________________Helper
function pushNote(trackArr, note) {
if (note - 1 === 0) {
trackArr.push(16)
} else {
trackArr.push(note - 1)
}
}
//________________________________________________END Helper
My question is really a basic one. Is there a way to solve this problem without creating these odd “offsets” ?
I suspect there is a way to set/write/place the current16thNote increment without having to create offsets to other parts of the program. But I'm hazy on what it could be.
In the world of professional audio recording there isn't a tick per 16th division value , you usually have 480 ticks per quarter note. I want to begin exploring writing my apps using this larger value but I want to resolve this "offset" issue before I go down that rabbit hole.