1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.example.android.apis.media;
18 
19 import com.example.android.apis.R;
20 
21 import android.app.Activity;
22 import android.content.Context;
23 import android.content.res.AssetFileDescriptor;
24 import android.graphics.Canvas;
25 import android.graphics.Color;
26 import android.graphics.Paint;
27 import android.graphics.Rect;
28 import android.media.AudioManager;
29 import android.media.MediaPlayer;
30 import android.media.audiofx.Equalizer;
31 import android.media.audiofx.Visualizer;
32 import android.net.Uri;
33 import android.os.Bundle;
34 import android.util.Log;
35 import android.view.Gravity;
36 import android.view.View;
37 import android.view.ViewGroup;
38 import android.widget.LinearLayout;
39 import android.widget.SeekBar;
40 import android.widget.TextView;
41 
42 import java.io.IOException;
43 
44 public class AudioFxDemo extends Activity {
45     private static final String TAG = "AudioFxDemo";
46 
47     private static final float VISUALIZER_HEIGHT_DIP = 50f;
48 
49     private MediaPlayer mMediaPlayer;
50     private Visualizer mVisualizer;
51     private Equalizer mEqualizer;
52 
53     private LinearLayout mLinearLayout;
54     private VisualizerView mVisualizerView;
55     private TextView mStatusTextView;
56 
57     @Override
onCreate(Bundle icicle)58     public void onCreate(Bundle icicle) {
59         super.onCreate(icicle);
60 
61         setVolumeControlStream(AudioManager.STREAM_MUSIC);
62 
63         mStatusTextView = new TextView(this);
64 
65         mLinearLayout = new LinearLayout(this);
66         mLinearLayout.setOrientation(LinearLayout.VERTICAL);
67         mLinearLayout.addView(mStatusTextView);
68 
69         setContentView(mLinearLayout);
70 
71         // Create the MediaPlayer
72         mMediaPlayer = MediaPlayer.create(this, R.raw.test_cbr);
73         Log.d(TAG, "MediaPlayer audio session ID: " + mMediaPlayer.getAudioSessionId());
74 
75         setupVisualizerFxAndUI();
76         setupEqualizerFxAndUI();
77 
78         // Make sure the visualizer is enabled only when you actually want to receive data, and
79         // when it makes sense to receive data.
80         mVisualizer.setEnabled(true);
81 
82         // When the stream ends, we don't need to collect any more data. We don't do this in
83         // setupVisualizerFxAndUI because we likely want to have more, non-Visualizer related code
84         // in this callback.
85         mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
86             public void onCompletion(MediaPlayer mediaPlayer) {
87                 mVisualizer.setEnabled(false);
88             }
89         });
90 
91         mMediaPlayer.start();
92         mStatusTextView.setText("Playing audio...");
93     }
94 
setupEqualizerFxAndUI()95     private void setupEqualizerFxAndUI() {
96         // Create the Equalizer object (an AudioEffect subclass) and attach it to our media player,
97         // with a default priority (0).
98         mEqualizer = new Equalizer(0, mMediaPlayer.getAudioSessionId());
99         mEqualizer.setEnabled(true);
100 
101         TextView eqTextView = new TextView(this);
102         eqTextView.setText("Equalizer:");
103         mLinearLayout.addView(eqTextView);
104 
105         short bands = mEqualizer.getNumberOfBands();
106 
107         final short minEQLevel = mEqualizer.getBandLevelRange()[0];
108         final short maxEQLevel = mEqualizer.getBandLevelRange()[1];
109 
110         for (short i = 0; i < bands; i++) {
111             final short band = i;
112 
113             TextView freqTextView = new TextView(this);
114             freqTextView.setLayoutParams(new ViewGroup.LayoutParams(
115                     ViewGroup.LayoutParams.FILL_PARENT,
116                     ViewGroup.LayoutParams.WRAP_CONTENT));
117             freqTextView.setGravity(Gravity.CENTER_HORIZONTAL);
118             freqTextView.setText((mEqualizer.getCenterFreq(band) / 1000) + " Hz");
119             mLinearLayout.addView(freqTextView);
120 
121             LinearLayout row = new LinearLayout(this);
122             row.setOrientation(LinearLayout.HORIZONTAL);
123 
124             TextView minDbTextView = new TextView(this);
125             minDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
126                     ViewGroup.LayoutParams.WRAP_CONTENT,
127                     ViewGroup.LayoutParams.WRAP_CONTENT));
128             minDbTextView.setText((minEQLevel / 100) + " dB");
129 
130             TextView maxDbTextView = new TextView(this);
131             maxDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
132                     ViewGroup.LayoutParams.WRAP_CONTENT,
133                     ViewGroup.LayoutParams.WRAP_CONTENT));
134             maxDbTextView.setText((maxEQLevel / 100) + " dB");
135 
136             LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
137                     ViewGroup.LayoutParams.FILL_PARENT,
138                     ViewGroup.LayoutParams.WRAP_CONTENT);
139             layoutParams.weight = 1;
140             SeekBar bar = new SeekBar(this);
141             bar.setLayoutParams(layoutParams);
142             bar.setMax(maxEQLevel - minEQLevel);
143             bar.setProgress(mEqualizer.getBandLevel(band));
144 
145             bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
146                 public void onProgressChanged(SeekBar seekBar, int progress,
147                         boolean fromUser) {
148                     mEqualizer.setBandLevel(band, (short) (progress + minEQLevel));
149                 }
150 
151                 public void onStartTrackingTouch(SeekBar seekBar) {}
152                 public void onStopTrackingTouch(SeekBar seekBar) {}
153             });
154 
155             row.addView(minDbTextView);
156             row.addView(bar);
157             row.addView(maxDbTextView);
158 
159             mLinearLayout.addView(row);
160         }
161     }
162 
setupVisualizerFxAndUI()163     private void setupVisualizerFxAndUI() {
164         // Create a VisualizerView (defined below), which will render the simplified audio
165         // wave form to a Canvas.
166         mVisualizerView = new VisualizerView(this);
167         mVisualizerView.setLayoutParams(new ViewGroup.LayoutParams(
168                 ViewGroup.LayoutParams.FILL_PARENT,
169                 (int)(VISUALIZER_HEIGHT_DIP * getResources().getDisplayMetrics().density)));
170         mLinearLayout.addView(mVisualizerView);
171 
172         // Create the Visualizer object and attach it to our media player.
173         mVisualizer = new Visualizer(mMediaPlayer.getAudioSessionId());
174         mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]);
175         mVisualizer.setDataCaptureListener(new Visualizer.OnDataCaptureListener() {
176             public void onWaveFormDataCapture(Visualizer visualizer, byte[] bytes,
177                     int samplingRate) {
178                 mVisualizerView.updateVisualizer(bytes);
179             }
180 
181             public void onFftDataCapture(Visualizer visualizer, byte[] bytes, int samplingRate) {}
182         }, Visualizer.getMaxCaptureRate() / 2, true, false);
183     }
184 
185     @Override
onPause()186     protected void onPause() {
187         super.onPause();
188 
189         if (isFinishing() && mMediaPlayer != null) {
190             mVisualizer.release();
191             mEqualizer.release();
192             mMediaPlayer.release();
193             mMediaPlayer = null;
194         }
195     }
196 }
197 
198 /**
199  * A simple class that draws waveform data received from a
200  * {@link Visualizer.OnDataCaptureListener#onWaveFormDataCapture }
201  */
202 class VisualizerView extends View {
203     private byte[] mBytes;
204     private float[] mPoints;
205     private Rect mRect = new Rect();
206 
207     private Paint mForePaint = new Paint();
208 
VisualizerView(Context context)209     public VisualizerView(Context context) {
210         super(context);
211         init();
212     }
213 
init()214     private void init() {
215         mBytes = null;
216 
217         mForePaint.setStrokeWidth(1f);
218         mForePaint.setAntiAlias(true);
219         mForePaint.setColor(Color.rgb(0, 128, 255));
220     }
221 
updateVisualizer(byte[] bytes)222     public void updateVisualizer(byte[] bytes) {
223         mBytes = bytes;
224         invalidate();
225     }
226 
227     @Override
onDraw(Canvas canvas)228     protected void onDraw(Canvas canvas) {
229         super.onDraw(canvas);
230 
231         if (mBytes == null) {
232             return;
233         }
234 
235         if (mPoints == null || mPoints.length < mBytes.length * 4) {
236             mPoints = new float[mBytes.length * 4];
237         }
238 
239         mRect.set(0, 0, getWidth(), getHeight());
240 
241         for (int i = 0; i < mBytes.length - 1; i++) {
242             mPoints[i * 4] = mRect.width() * i / (mBytes.length - 1);
243             mPoints[i * 4 + 1] = mRect.height() / 2
244                     + ((byte) (mBytes[i] + 128)) * (mRect.height() / 2) / 128;
245             mPoints[i * 4 + 2] = mRect.width() * (i + 1) / (mBytes.length - 1);
246             mPoints[i * 4 + 3] = mRect.height() / 2
247                     + ((byte) (mBytes[i + 1] + 128)) * (mRect.height() / 2) / 128;
248         }
249 
250         canvas.drawLines(mPoints, mForePaint);
251     }
252 }
253