2016-02-22 35 views
8

Sto provando a creare un'applicazione Android dove filtro una frequenza specifica di un segnale acustico e far vibrare il telefono.Come attivare la vibrazione all'ingresso audio?

Sto prendendo input dal MIC di mobile e utilizzando la classe MediaRecorder, utilizzando questa classe, posso registrare, salvare e riprodurre l'input. Ora ho bisogno che il mio cellulare vibri ogni volta che viene emesso un segnale acustico o un suono.

L'ingresso è dato da un filo al jack delle cuffie del cellulare, quindi so che è presente una sola frequenza in ingresso.

Ho un pulsante, Facendo clic che avvia la registrazione. Ho permessi per vibrare e registrare già nel mio file manifest.

record.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       try { 
        isRecording=true; 
        myAudioRecorder.prepare(); 
        myAudioRecorder.start(); 
... 
} 

Ho anche provato a cercare in internet e ha trovato il tipo di domanda simile here ma non riesco a trovare alcuna risposta corretta.

Tuttavia, posso fare vibrare il telefono facendo clic su un altro pulsante ed ecco la Questo esempio vi di codice,

Vibrator vibrate; 
    vibrate = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); 

     Btn1.setOnClickListener(new View.OnClickListener() 

           { 
            @Override 
            public void onClick(View v) { 
             vibrate.vibrate(800); 
            } 
           } 

Ho provato a chiamare un vibratore all'interno recorder.start(); funzione ma questo fa vibrare il telefono anche quando non c'è più alcun suono. Ho anche provato ad ottenere aiuto da this question quindi ogni volta che c'è silenzio, il telefono non deve vibrare, ma mi sto confondendo, in qualche modo capisco che dovrebbe esserci un booleano che diventa vero quando c'è il suono e fa vibrare il telefono, ma io Sono incapace di mettere questa logica in codice. Per favore fatemi sapere cosa posso fare in questo contesto e in quale direzione devo cercare?

UPDATE ho trovato this toturial per mostrare la barra di avanzamento di ampiezza del suono in ingresso, funziona bene e ho cercato di far vibrare telefono quando c'è un valore in un tampone, Ora vibra anche quando l'ampiezza è zero, immagino che questo sia dovuto al fatto che ogni vibrazione produce rumore che porta il telefono a vibrare. Non riesco a controllare la funzione tramite TOAST a causa di java.lang.RuntimeException: Impossibile creare il gestore all'interno del thread che non ha chiamato Looper.prepare(). C'è qualche suggerimento?

risposta

0

Prova questo:

Btn1.setOnClickListener(new View.OnClickListener() { 

     @Override 
     public void onClick(View v) { 
      v.post(new Runnable() { 

       @Override 
       public void run() { 

        vibrate.vibrate(800); 
       } 
      }); 

     } 
    }); 
+0

Grazie per la risposta, ma ho bisogno di far vibrare il telefono quando c'è un suono, non sul clic, sono già in grado di farlo. Per favore leggi di nuovo la domanda. –

0

si può provare questo:

Handler handler; 
    Runnable r; 

      handler = new Handler(); 
       r = new Runnable() { 
        public void run() { 

        Vibrator vib = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); 
        vib.vibrate(500); 
        handler.postDelayed(r, 1000); 

        } 
       }; 
      handler.post(r); 
+0

Spiegheresti per favore il codice, sono nuovo ad Android e non ho familiarità con tutti i concetti. –

6

Per il vostro problema principale, forse si può verificare l'ampiezza del suono, e vibrare solo se una soglia minima ha stato raggiuntoQualcosa di simile a questo:

private class DetectAmplitude extends AsyncTask<Void, Void, Void> { 

    private MediaRecorder mRecorder = null; 
    private final static int MAX_AMPLITUDE = 32768; 
    //TODO: Investigate what is the ideal value for this parameter 
    private final static int MINIMUM_REQUIRED_AVERAGE = 5000; 

    @Override 
    protected Void doInBackground(Void... params) { 
     Boolean soundStarted = true; 
     if (mRecorder == null) { 
      mRecorder = new MediaRecorder(); 
      mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); 
      mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); 
      mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); 
      mRecorder.setOutputFile("/dev/null"); 
      try { 
       mRecorder.prepare(); 
      } catch (IllegalStateException e) { 
       soundStarted = false; 
       Log.e(TAG, "Could not detect background noise. Error preparing recorder: " + e.getMessage()); 
      } catch (IOException e) { 
       soundStarted = false; 
       Log.e(TAG, "Could not detect background noise. Error preparing recorder: " + e.getMessage()); 
      } 
      try { 
       mRecorder.start(); 
      } catch (RuntimeException e) { 
       Log.e(TAG, "Could not detect background noise. Error starting recorder: " + e.getMessage()); 
       soundStarted = false; 
       mRecorder.release(); 
       mRecorder = null; 
      } 
     } 

     if (soundStarted) { 
      // Compute a simple average of the amplitude over one 
      // second 
      int nMeasures = 100; 
      int sumAmpli = 0; 
      mRecorder.getMaxAmplitude(); // First call returns 0 
      int n = 0; 
      for (int i = 0; i < nMeasures; i++) { 
       if (mRecorder != null) { 
        int maxAmpli = mRecorder.getMaxAmplitude(); 
        if (maxAmpli > 0) { 
         sumAmpli += maxAmpli; 
         n++; 
        } 
       } else { 
        return null; 
       } 
       try { 
        Thread.sleep(1000/nMeasures); 
       } catch (InterruptedException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 
      } 
      mRecorder.stop(); 
      mRecorder.release(); 
      mRecorder = null; 

      final float avgAmpli = (float) sumAmpli/n; 

      if (avgAmpli > MINIMUM_REQUIRED_AVERAGE) { 
       //TODO: Vibrate the device here 
      } 
     } 
     return null; 
    } 
} 

Per ulteriori informazioni riguardanti il ​​rilevamento di livello sonoro, si prega di fare riferimento ai seguenti:

Per quanto riguarda l'eccezione java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare(), che sta accadendo perché il Toast deve essere eseguito sul thread principale della tua app. Se il codice Thread (come un AsyncTask) è all'interno di un Activity, si può provare il seguente:

runOnUiThread(new Runnable() { 
     @Override 
     public void run() { 
      //Call your Toast here 
     } 
    }); 

In caso contrario, è necessario passare in qualche modo la conclusione del vostro metodo alla Activity per l'esecuzione del Toast.

EDIT:

Se si desidera utilizzare questo da un Button, è possibile impostare il suo OnClickListener sulla s Activity' onCreate() chiamata ed eseguire il AsyncTask lì. Per esempio:

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.your_layout); 
    Button button = (Button)findViewById(R.id.your_button_id); 
    button.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      new DetectAmplitude().execute(new Void[]{}); 
     } 
    }); 
} 

vi consiglio di dare un'occhiata a how AsyncTask works prima di utilizzare questo nel codice di produzione.

+0

Salve, questo suona alla grande ma non riesco a trovare un modo per avviare la registrazione sul pulsante clic, suggeriresti, un pulsante sul metodo onclicklistener all'interno di AsyncTask e poi sul vuoto protetto doInBackground (Void ... params al suo interno? –

+0

Ciao @MomoPomo Ho modificato la mia risposta con un esempio di utilizzo.Spero che sia d'aiuto –

1

Si desidera campionare l'audio e analizzarlo immediatamente.

MediaRecorder sembra ad alto livello per questo, cattura solo per file. Probabilmente vorrai usare lo AudioRecorder, dato che dà accesso diretto ai campioni di input.

Per rilevare il tono specifico , è possibile utilizzare lo Goertzel algorithm sui campioni di input. Ecco un C++ implementation che ho fatto anni fa che potrebbe servire come esempio.

Per rilevare qualsiasi suono su una determinata soglia, è possibile utilizzare l'analisi Root Mean Square sui campioni di input e attivarla quando il volume raggiunge la soglia. Ecco un Python example che reagisce a rumori forti da un microfono.

+0

Puoi usare 'setOutputFile ("/dev/null ")' su 'MediaRecorder' per evitare l'output del file.Inoltre, per rilevare solo se c'è rumore , il registratore multimediale farebbe bene controllando l'ampiezza del suono per un breve periodo di tempo –

+0

La tua risposta è ottima, ma poiché ho bisogno di sviluppare Android e anche molti altri principianti, sarebbe stato grandioso se fossero state introdotte solo le implementazioni di Android tuttavia, considerando la logica eccellente, ho ancora avuto la logica necessaria per la sintassi per implementarla.Anche per scopi di apprendimento non è necessario modificare le classi utilizzate senza prima implementarne una completamente. –