domenica 18 agosto 2013

Equalizer > Android > Java

Chi di voi ha già programmato per android avrà notato quanto è vasto l'ambiente di sviluppo, Google mette a disposizione classi ben documentate per qualsiasi componente presente nel telefono. Tempo fa mi è capitato di utilizzare il componente Equalizer e BassBoost, dei quali però trovai poca documentazione, di seguito vediamo come ottenere questi oggetti e come gestire le loro proprietà in un Activity separata.

Main Activity
package it.test.equalizertest;

import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.audiofx.BassBoost;
import android.media.audiofx.Equalizer;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {

 MediaPlayer mp;
 public static Equalizer equalizer;
 public static BassBoost bassboost;
 String SONG_PATH = "/storage/sdcard0/media/audio/06-soft-rock-star.mp3";
 //Stringa con il percorso della canzone
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  //MediaPlayer
     mp = new MediaPlayer();
     equalizer = new Equalizer(99999999, mp.getAudioSessionId()); //Ottengo l'Equalizer con alta priorità
     bassboost = new BassBoost(999999, mp.getAudioSessionId()); //Ottengo il bassboost con priorità 99999

     setVolumeControlStream(AudioManager.STREAM_MUSIC);

  //Abilita Equalizer
  int val = equalizer.setEnabled(true);
     if(val != Equalizer.SUCCESS)
      Log.v("A", "EQUALIZER NON ATTIVO" + val);
     val = bassboost.setEnabled(true);
     if(val != Equalizer.SUCCESS)
      Log.v("A", "BASSBOOST NON ATTIVO" + val);
     else
      Log.v("A", "SUCCESS!");
     
     //Button Play plays a song in SONG_PATH
     Button btn_play = (Button) findViewById(R.id.button_play);
     btn_play.setOnClickListener(new OnClickListener() {
   
   @Override
   public void onClick(View v) {
    try{
      mp.reset();
      mp.setDataSource(SONG_PATH); //setto il file audio come datasource
      mp.prepare();
      mp.start(); //faccio partire il mediaplayer
     }
    catch(Exception ex){};
   }
  });
     
     Button btn_eq = (Button) findViewById(R.id.button_equalizer);
     btn_eq.setOnClickListener(new OnClickListener() {
   
   @Override
   public void onClick(View v) {
    openEqualizer(); //apro una nuova activity
   }
  });
 }

 @Override
 public void onDestroy()
 {
   super.onDestroy();
   
   if(mp != null){
    mp.release(); //rilascio il media player
   }
   if(equalizer != null)
    equalizer.release();
   if(bassboost != null)
    bassboost.release();
 }
 
 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }
 
 public void openEqualizer()
 {
  Intent i = new Intent(MainActivity.this, EqualizerActivity.class);
  startActivity(i); //apre l'equalizer
  //l'oggetto equalizer è passato come statico
 }

}
Quello che abbiamo fatto fin ora è ottenere dal dispositivo gli oggetti Equalizer e BassBoost, i quali sono unici e per questo motivo va specificata la priorità con la quale li richiamiamo, applicazioni come n7Player hanno processi che mantengono il controllo su equalizer, bassboost e altro con massima priorità, per cui è indispensabile in un applicazione mettere un controllo per specificare se il programma ha i privilegi per modificare le proprieà dell'equalizer. Tramite la costante Equalizer.SUCCESS possiamo verificare quanto detto precedentemente, basta guardare il codice in alto.
In una nuova activity creiamo via codice gli slider necessari per il controllo dell'Equalizer:
EqualizerActivity
package it.test.equalizertest;

import android.app.Activity;
import android.media.audiofx.BassBoost;
import android.media.audiofx.Equalizer;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;

public class EqualizerActivity extends Activity {

    private Equalizer equalizer;
    private BassBoost bassboost;
    private short bbs = 0;
    TextView bbTextView;
    private static final short BASSBOOST_MAX_STRENGTH = 1000; //MIN = 0

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        equalizer = MainActivity.equalizer; //preso dall'activity -> sempre attivo
        bassboost = MainActivity.bassboost;
        int val = equalizer.setEnabled(true);
        if(val != Equalizer.SUCCESS)
         Log.v("A", "EQUALIZER NON ATTIVO " + val);
        setupEqualizerFXandUI();
        
    }
    
    
    //generato dinamicamente a seconda delle bande percepite
    private void setupEqualizerFXandUI()
    {
     TextView eqTextView = new TextView(this);
     eqTextView.setText("Equalizer:");
     LinearLayout ll = new LinearLayout(this);
     ll.setOrientation(LinearLayout.VERTICAL);
     ll.addView(eqTextView);
     
     setContentView(ll);
     
      short bands = equalizer.getNumberOfBands(); //numero di bande di frequenza modificabili
      final short minEQLevel = equalizer.getBandLevelRange()[0]; //minimo per banda
      final short maxEQLevel = equalizer.getBandLevelRange()[1]; //massimo per banda
      
      LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
   layoutParams.weight = 1;
      
      for(short i = 0; i< bands; i++)
      {
       final short band = i;
       //Log.v("A", "B "+ band);
       TextView freqTv = new TextView(this);
       freqTv.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
       freqTv.setGravity(Gravity.CENTER_HORIZONTAL);
       freqTv.setText((equalizer.getCenterFreq(band) /1000) + " Hz");
       ll.addView(freqTv);
       
       LinearLayout row = new LinearLayout(this);
       row.setOrientation(LinearLayout.HORIZONTAL);
       
       TextView minDbTv = new TextView(this);
       minDbTv.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
       minDbTv.setText((minEQLevel / 100) + " dB");
       
       TextView maxDbTv = new TextView(this);
       maxDbTv.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
       maxDbTv.setText((maxEQLevel / 100) + " dB");
       
       SeekBar bar = new SeekBar(this);
       bar.setLayoutParams(layoutParams);
       bar.setMax(maxEQLevel - minEQLevel);
       bar.setProgress(equalizer.getBandLevel(band)); // Volume della banda
       
       bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
    
    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
    }
    
    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
     
    }
    
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress,
      boolean fromUser) {
     equalizer.setBandLevel(band, (short)(progress + minEQLevel));
     Log.v("A", "LEVEL: " + (progress + minEQLevel));
    }
   });
       
       row.addView(minDbTv);
       row.addView(bar);
       row.addView(maxDbTv);
       
       ll.addView(row);
      }
      
     //BASS BOOST
     bbs = bassboost.getRoundedStrength();
     bbTextView = new TextView(this);
      bbTextView.setText("BassBoost: " + bbs);
      
      SeekBar bar = new SeekBar(this);
   bar.setLayoutParams(layoutParams);
   bar.setMax(BASSBOOST_MAX_STRENGTH);
   bar.setProgress(bassboost.getRoundedStrength());
   
   bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
   
   @Override
   public void onStopTrackingTouch(SeekBar seekBar) {
   }
   
   @Override
   public void onStartTrackingTouch(SeekBar seekBar) {
    
   }
   
   @Override
   public void onProgressChanged(SeekBar seekBar, int progress,
     boolean fromUser) {
    bbs = (short) progress;
    bassboost.setStrength(bbs);
    bbTextView.setText("BassBoost: " + bbs);
   }
  });
      
      LinearLayout row = new LinearLayout(this);
  row.setOrientation(LinearLayout.HORIZONTAL);
  
  row.addView(bbTextView);
  row.addView(bar);
  ll.addView(row);
    }
}


Il codice sovrastante è autoesplicativo, per chi non ha troppa confidenza con android consiglio di vedere come si creano dinamicamente i layout e le view, con equalizer.setEnabled ricontrolliamo che l'oggetto sia in funzione per la nostra app,  equalizer.getNumberOfBands() ritorna il numero di bande che possiamo modificare, con equalizer.setBandLevel possiamo settare il volume bassato uno specifico id di banda.


La documentazione completa per questa classe è disponibile a questa pagina.
L'esempio completo può essere scaricato al seguente link: https://dl.dropboxusercontent.com/u/23802589/EqualizerTest.rar