METRONOMO: IMPOSTARE BEEP AD INTERVALLI REGOLARI

di il
6 risposte

METRONOMO: IMPOSTARE BEEP AD INTERVALLI REGOLARI

Questo è il mio primo post. 

Sto tentando di sviluppare una app android, attraverso Android Studio in linguaggio Java, per realizzare un metronomo.

Il problema che non riesco a risolvere è il seguente: Il primo beep è irregolare rispetto a quelli successivi, che invece si susseguono in modo regolare. Nel simulatore di android studio il problema non si presenta, mentre nello smartphone fisico (note 10 e s22) i primi due beep sono irregolari. Questo è il codice che ho utilizzato:

package com.example.mymetronomo;

import android.app.Activity;
import android.media.AudioManager;
import android.media.ToneGenerator;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends Activity {

    private Timer timer;
    private Handler handler;

    private Button startButton;
    private Button aumentaButton;
    private Button diminuisciButton;
    private Button stopButton;
    private TextView visualizzaBpm;
    private long bpm = 120;
    private String bpmString;
    private long delay;
   private int n = 1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        startButton = findViewById(R.id.start);
        stopButton = findViewById(R.id.stop);
        aumentaButton = findViewById(R.id.aumenta);
        diminuisciButton = findViewById(R.id.diminusci);
        visualizzaBpm = findViewById(R.id.bpmview);

        bpmString = String.valueOf(bpm);
        visualizzaBpm.setText(bpmString);

        startButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (timer == null) {
                    startMetronome();
                }
            }
        });

        stopButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                stopMetronome();
                bpmString = String.valueOf(bpm);
                visualizzaBpm.setText(bpmString);
            }
        });

        aumentaButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                bpm += 5;
                if (timer != null) {
                    timer.cancel();
                    timer = null;
                    startMetronome();
                }
                bpmString = String.valueOf(bpm);
                visualizzaBpm.setText(bpmString);
            }
        });

        diminuisciButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                bpm -= 5;
                if (timer != null) {
                    timer.cancel();
                    timer = null;
                    startMetronome();
                }
                bpmString = String.valueOf(bpm);
                visualizzaBpm.setText(bpmString);
            }
        });
    }

    private void startMetronome() {
        delay = 60000 / bpm; // Ritardo tra i battiti in millisecondi
        timer = new Timer();
        handler = new Handler(Looper.getMainLooper());

        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        playMetronomeBeep();
                    }
                });
            }
        };

        timer.scheduleAtFixedRate(task, delay, delay);


    }

    private void playMetronomeBeep() {
        ToneGenerator toneGenerator = new ToneGenerator(AudioManager.STREAM_NOTIFICATION, 100);


        toneGenerator.startTone(ToneGenerator.TONE_PROP_BEEP, 200); // Durata e frequenza del beep


        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        toneGenerator.stopTone();
        toneGenerator.release();
    }

    private void stopMetronome() {
        if (timer != null) {
            timer.cancel();
            timer = null;
            handler = null;
        }
    }
}

6 Risposte

  • Re: METRONOMO: IMPOSTARE BEEP AD INTERVALLI REGOLARI

    Non credo che, in generale, il timer abbia una precisione sufficiente da poter implementare un metronomo: basta avviare qualche applicazione o servizio che abbia bisogno di più CPU ed è facile che “sbagli” qualche battuta.

  • Re: METRONOMO: IMPOSTARE BEEP AD INTERVALLI REGOLARI

    20/06/2023 - Alka ha scritto:


    Non credo che, in generale, il timer abbia una precisione sufficiente da poter implementare un metronomo: basta avviare qualche applicazione o servizio che abbia bisogno di più CPU ed è facile che “sbagli” qualche battuta.

    Dal secondo beep il ritmo è regolare. Il problema più grande è tra il primo e il secondo. Non capisco perché il problema è solo sul telefono fisico. L'emulatore funziona bene.

  • Re: METRONOMO: IMPOSTARE BEEP AD INTERVALLI REGOLARI

    Questo si era capito.

    Resta il fatto che il sistema non è realtime e quindi il timer non è preciso soprattutto quando c'è un impegno di risorse.

    All'inizio viene creato il processo, gli oggetti, con allocazione di memoria e risorse e quindi il sistema è impegnato e il timer non è preciso per i primi “beep”. Anche dopo, se utilizzi il sistema per altri scopi “pesanti” potresti avere dei rallentamenti temporanei, ovviamente se usi solo il tuo metronomo non te ne accorgerai.

    Puoi tentare di “metterci una pezza” ignorando i primi 2 eventi del timer.

  • Re: METRONOMO: IMPOSTARE BEEP AD INTERVALLI REGOLARI

    20/06/2023 - oregon ha scritto:


    Questo si era capito.

    Resta il fatto che il sistema non è realtime e quindi il timer non è preciso soprattutto quando c'è un impegno di risorse.

    All'inizio viene creato il processo, gli oggetti, con allocazione di memoria e risorse e quindi il sistema è impegnato e il timer non è preciso per i primi “beep”. Anche dopo, se utilizzi il sistema per altri scopi “pesanti” potresti avere dei rallentamenti temporanei, ovviamente se usi solo il tuo metronomo non te ne accorgerai.

    Puoi tentare di “metterci una pezza” ritardando di 1 o 2 secondi la partenza del timer dopo aver avviato il programma.

    Grazie per la risposta. Si possono utilizzare metodi più precisi? Ci sono molte app per metronomo che sembrano funzionare correttamente.

  • Re: METRONOMO: IMPOSTARE BEEP AD INTERVALLI REGOLARI

    Probabilmente sono scritte in C e non in Java o comunque tramite l'uso di codice nativo e l'accesso alle risorse di sistema o direttamente ai timer hardware.

    Java e i suoi timer hanno dei limiti.

  • Re: METRONOMO: IMPOSTARE BEEP AD INTERVALLI REGOLARI

    Ho adottato la soluzione di silenziare il primo “beep”, impostando il volume a zero. I successivi battiti sono regolari.

    Grazie per l'indicazione, è stata decisiva.

    Posso proseguire nello sviluppo dell'app.

Devi accedere o registrarti per scrivere nel forum
6 risposte