精华内容
下载资源
问答
  • Android开发:仿微信 录音声波

    千次阅读 2016-10-20 18:17:42
    就是录音声波这块。 首先先添加几个图片添加如上三个声波图表 之后建立一个数组private int[] images = {R.mipmap.ico_yuyinhui_1,R.mipmap.ico_yuyinhui_2,R.mipmap.ico_yuyinhui_3};有了数组后就可以建立一个...

    最近在仿微信开发聊天界面:开发到一个有意思的小东西,简单写一写。就是录音声波这块。
    首先先添加几个图片图片描述

    图片描述

    图片描述

    添加如上三个声波图表
    之后建立一个数组

    private int[] images = {R.mipmap.ico_yuyinhui_1,R.mipmap.ico_yuyinhui_2,R.mipmap.ico_yuyinhui_3};

    有了数组后就可以建立一个handler来刷新界面了

    private final Handler mHandler = new Handler(){
            public void handleMessage(android.os.Message msg) {
                switch (msg.what){
                    case 0:
                    case 1:
                    case 2:micImage.setBackground(getResources().getDrawable(micImages[what],getResources().newTheme()));
                        break;
                }
    
            };
        };

    之后建立主要代码区

    private Runnable mUpdateMicStatusTimer = new Runnable() {
            public void run() {
                updateMicStatus();
            }
        };
     private int BASE = 1;  
        private int SPACE = 100;// 间隔取样时间  
        private void updateMicStatus() {  
            if (mMediaRecorder != null) {  
                double ratio = (double)mMediaRecorder.getMaxAmplitude() /BASE;  
                double db = 0;// 分贝  
                if (ratio > 1)  
                    db = 20 * Math.log10(ratio);  
    uiHandler.postDelayed(mUpdateMicStatusTimer, SPACE);
                //分贝在50 - 90 之间
                int min = db - 50;
                if(min<0){
                    min = 0;
                }
                int step = (min)/((90-50)/3);
                if(step>2){
                    step = 2;
                }
                Logger.d(step+"step updateMicStatus");
                uiHandler.sendEmptyMessage(step);
            }  
        }  

    特别要注意的是要在测试完后移除线程

            uiHandler.removeCallbacks(mUpdateMicStatusTimer);

    具体layout代码我就不写了,非常简单。
    如果有什么问题在下面提就好了。
    效果图如下
    图片描述图片描述

    展开全文
  • Android 录音声波

    千次阅读 2015-12-29 16:42:54
    图像类:package .../** * Created by toge on 15/12/9. */ import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint;...import andr

    图像类:

    package com.akm.test;
    
    /**
     * Created by toge on 15/12/9.
     */
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.util.AttributeSet;
    import android.view.SurfaceView;
    
    import java.util.LinkedList;
    
    /**
     * A view that displays audio data on the screen as a waveform.
     */
    public class WaveformView extends SurfaceView {
    
        // The number of buffer frames to keep around (for a nice fade-out visualization).
        private static final int HISTORY_SIZE = 6;
    
        // To make quieter sounds still show up well on the display, we use +/- 8192 as the amplitude
        // that reaches the top/bottom of the view instead of +/- 32767. Any samples that have
        // magnitude higher than this limit will simply be clipped during drawing.
        private static final float MAX_AMPLITUDE_TO_DRAW = 8192.0f;
    
        // The queue that will hold historical audio data.
        private final LinkedList<short[]> mAudioData;
    
        private final Paint mPaint;
    
        public WaveformView(Context context) {
            this(context, null, 0);
        }
    
        public WaveformView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public WaveformView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
    
            mAudioData = new LinkedList<short[]>();
    
            mPaint = new Paint();
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setColor(Color.WHITE);
            mPaint.setStrokeWidth(0);
            mPaint.setAntiAlias(true);
        }
    
        /**
         * Updates the waveform view with a new "frame" of samples and renders it. The new frame gets
         * added to the front of the rendering queue, pushing the previous frames back, causing them to
         * be faded out visually.
         *
         * @param buffer the most recent buffer of audio samples
         */
        public synchronized void updateAudioData(short[] buffer) {
            short[] newBuffer;
    
            // We want to keep a small amount of history in the view to provide a nice fading effect.
            // We use a linked list that we treat as a queue for this.
            if (mAudioData.size() == HISTORY_SIZE) {
                newBuffer = mAudioData.removeFirst();
                System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
            } else {
                newBuffer = buffer.clone();
            }
    
            mAudioData.addLast(newBuffer);
    
            // Update the display.
            Canvas canvas = getHolder().lockCanvas();
            if (canvas != null) {
                drawWaveform(canvas);
                getHolder().unlockCanvasAndPost(canvas);
            }
        }
    
        /**
         * Repaints the view's surface.
         *
         * @param canvas the {@link Canvas} object on which to draw
         */
        private void drawWaveform(Canvas canvas) {
            // Clear the screen each time because SurfaceView won't do this for us.
            canvas.drawColor(Color.BLACK);
    
            float width = getWidth();
            float height = getHeight();
            float centerY = height / 2;
    
            // We draw the history from oldest to newest so that the older audio data is further back
            // and darker than the most recent data.
            int colorDelta = 255 / (HISTORY_SIZE + 1);
            int brightness = colorDelta;
    
            for (short[] buffer : mAudioData) {
                mPaint.setColor(Color.argb(brightness, 128, 255, 192));
    
                float lastX = -1;
                float lastY = -1;
    
                // For efficiency, we don't draw all of the samples in the buffer, but only the ones
                // that align with pixel boundaries.
                for (int x = 0; x < width; x++) {
                    int index = (int) ((x / width) * buffer.length);
                    short sample = buffer[index];
                    float y = (sample / MAX_AMPLITUDE_TO_DRAW) * centerY + centerY;
    
                    if (lastX != -1) {
                        canvas.drawLine(lastX, lastY, x, y, mPaint);
                    }
    
                    lastX = x;
                    lastY = y;
                }
    
                brightness += colorDelta;
            }
        }
    }

    头文件:

    /*
     * Copyright (C) 2015 Google Inc.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package com.akm.test;
    
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    /**
     * Created by Akm at 15/12/1 上午10:07
     * 文件制作
     */
    public class WAVHeader {
        private byte[] mHeader;          // the complete header.
        private int mSampleRate;         // sampling frequency in Hz (e.g. 44100).
        private int mChannels;           // number of channels.
        private int mNumSamples;         // total number of samples per channel.
        private int mNumBytesPerSample;  // number of bytes per sample, all channels included.
    
        public WAVHeader(int sampleRate, int numChannels, int numSamples) {
            mSampleRate = sampleRate;
            mChannels = numChannels;
            mNumSamples = numSamples;
            mNumBytesPerSample = 2 * mChannels;  // assuming 2 bytes per sample (for 1 channel)
            mHeader = null;
            setHeader();
        }
    
        public byte[] getWAVHeader() {
            return mHeader;
        }
    
        public static byte[] getWAVHeader(int sampleRate, int numChannels, int numSamples) {
            return new WAVHeader(sampleRate, numChannels, numSamples).mHeader;
        }
    
        public String toString() {
            String str = "";
            if (mHeader == null) {
                return str;
            }
            int num_32bits_per_lines = 8;
            int count = 0;
            for (byte b : mHeader) {
                boolean break_line = count > 0 && count % (num_32bits_per_lines * 4) == 0;
                boolean insert_space = count > 0 && count % 4 == 0 && !break_line;
                if (break_line) {
                    str += '\n';
                }
                if (insert_space) {
                    str += ' ';
                }
                str += String.format("%02X", b);
                count++;
            }
    
            return str;
        }
    
        private void setHeader() {
            byte[] header = new byte[46];
            int offset = 0;
            int size;
    
            // set the RIFF chunk
            System.arraycopy(new byte[]{'R', 'I', 'F', 'F'}, 0, header, offset, 4);
            offset += 4;
            size = 36 + mNumSamples * mNumBytesPerSample;
            header[offset++] = (byte) (size & 0xFF);
            header[offset++] = (byte) ((size >> 8) & 0xFF);
            header[offset++] = (byte) ((size >> 16) & 0xFF);
            header[offset++] = (byte) ((size >> 24) & 0xFF);
            System.arraycopy(new byte[]{'W', 'A', 'V', 'E'}, 0, header, offset, 4);
            offset += 4;
    
            // set the fmt chunk
            System.arraycopy(new byte[]{'f', 'm', 't', ' '}, 0, header, offset, 4);
            offset += 4;
            System.arraycopy(new byte[]{0x10, 0, 0, 0}, 0, header, offset, 4);  // chunk size = 16
            offset += 4;
            System.arraycopy(new byte[]{1, 0}, 0, header, offset, 2);  // format = 1 for PCM
            offset += 2;
            header[offset++] = (byte) (mChannels & 0xFF);
            header[offset++] = (byte) ((mChannels >> 8) & 0xFF);
            header[offset++] = (byte) (mSampleRate & 0xFF);
            header[offset++] = (byte) ((mSampleRate >> 8) & 0xFF);
            header[offset++] = (byte) ((mSampleRate >> 16) & 0xFF);
            header[offset++] = (byte) ((mSampleRate >> 24) & 0xFF);
            int byteRate = mSampleRate * mNumBytesPerSample;
            header[offset++] = (byte) (byteRate & 0xFF);
            header[offset++] = (byte) ((byteRate >> 8) & 0xFF);
            header[offset++] = (byte) ((byteRate >> 16) & 0xFF);
            header[offset++] = (byte) ((byteRate >> 24) & 0xFF);
            header[offset++] = (byte) (mNumBytesPerSample & 0xFF);
            header[offset++] = (byte) ((mNumBytesPerSample >> 8) & 0xFF);
            System.arraycopy(new byte[]{0x10, 0}, 0, header, offset, 2);
            offset += 2;
    
            // set the beginning of the data chunk
            System.arraycopy(new byte[]{'d', 'a', 't', 'a'}, 0, header, offset, 4);
            offset += 4;
            size = mNumSamples * mNumBytesPerSample;
            header[offset++] = (byte) (size & 0xFF);
            header[offset++] = (byte) ((size >> 8) & 0xFF);
            header[offset++] = (byte) ((size >> 16) & 0xFF);
            header[offset++] = (byte) ((size >> 24) & 0xFF);
    
            mHeader = header;
        }
    
    
        public static byte[] getHeader(  long totalAudioLen,
                                long totalDataLen, long longSampleRate, int channels, long byteRate) throws IOException {
    
    
            byte[] header = new byte[44];
            header[0] = 'R'; // RIFF/WAVE header
            header[1] = 'I';
            header[2] = 'F';
            header[3] = 'F';
            header[4] = (byte) (totalDataLen & 0xff);
            header[5] = (byte) ((totalDataLen >> 8) & 0xff);
            header[6] = (byte) ((totalDataLen >> 16) & 0xff);
            header[7] = (byte) ((totalDataLen >> 24) & 0xff);
            header[8] = 'W';
            header[9] = 'A';
            header[10] = 'V';
            header[11] = 'E';
            header[12] = 'f'; // 'fmt ' chunk
            header[13] = 'm';
            header[14] = 't';
            header[15] = ' ';
            header[16] = 16; // 4 bytes: size of 'fmt ' chunk
            header[17] = 0;
            header[18] = 0;
            header[19] = 0;
            header[20] = 1; // format = 1
            header[21] = 0;
            header[22] = (byte) channels;
            header[23] = 0;
            header[24] = (byte) (longSampleRate & 0xff);
            header[25] = (byte) ((longSampleRate >> 8) & 0xff);
            header[26] = (byte) ((longSampleRate >> 16) & 0xff);
            header[27] = (byte) ((longSampleRate >> 24) & 0xff);
            header[28] = (byte) (byteRate & 0xff);
            header[29] = (byte) ((byteRate >> 8) & 0xff);
            header[30] = (byte) ((byteRate >> 16) & 0xff);
            header[31] = (byte) ((byteRate >> 24) & 0xff);
            header[32] = (byte) (2 * 16 / 8); // block align
            header[33] = 0;
            header[34] = 16; // bits per sample
            header[35] = 0;
            header[36] = 'd';
            header[37] = 'a';
            header[38] = 't';
            header[39] = 'a';
            header[40] = (byte) (totalAudioLen & 0xff);
            header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
            header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
            header[43] = (byte) ((totalAudioLen >> 24) & 0xff);
    
    
    
            return header;
        }
    }
    

    测试:

    package com.akm.test;
    
    import android.app.Activity;
    import android.media.AudioFormat;
    import android.media.AudioManager;
    import android.media.AudioRecord;
    import android.media.AudioTrack;
    import android.media.MediaPlayer;
    import android.media.MediaRecorder;
    import android.os.Bundle;
    import android.os.Environment;
    import android.os.Message;
    import android.os.SystemClock;
    import android.util.DisplayMetrics;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.Chronometer;
    import android.widget.SeekBar;
    import android.widget.TextView;
    
    import com.ringdroid.R;
    
    import java.io.File;
    import java.io.IOException;
    import java.io.RandomAccessFile;
    import java.nio.ByteBuffer;
    import java.nio.ByteOrder;
    import java.nio.ShortBuffer;
    import java.nio.channels.FileChannel;
    
    /**
     * Created by toge on 15/11/30.
     */
    public class Test extends Activity implements View.OnClickListener {
    
        WaveformView waveformView;
        private Button btnStart;
        private Button btnStop;
        private String filePath;
        private boolean mRecordingKeepGoing;
        private SoundFile soundFile;
        private RandomAccessFile randomAccessFile;
        private int totalLength;//总长
        private int duration;//时长
        private int rate;//采样率
        private int channelConfig;//声道
    
        private int samples;
        private int startPos;
        private int bufferSize;//缓冲区大小
        private int minBufferSize;//最小缓冲区
    
        private AudioRecord audioRecord;
        private AudioTrack audioTrack;
        private boolean mThreadFlag;
        private int i;
        private int j;
        private int STATUS = 1;
        private int STATUS_PAUSE = 2;
        private int STATUS_PREPARED = 1;
        private int STATUS_RECORDING = 1;
        private Thread audioTrackThread;
        private Thread thread;
        private int endPos;
        private int curFileLength;
        OnFileChangedListener onFileChangedListener;
        private boolean isRewrite;
        private boolean audioTrackFlag;
        private int frequency = 22050;//22050;
        private int recBufSize;
        private String outPath;
        private byte[] bytes;
        private int time;
        private Button btnPasue;
        private Button btnPlay;
        private Button btnPlay2;
        private long startTime;
        private long restOfTime;
        private int audioFormat;//采集
        private int bufferSizeInBytes;//缓冲区大小
        private Button btnSave;
        //    private ByteBuffer mDecodedBytes;
    //    private ByteBuffer mDecodedSamples;
        private byte[] sampleBytes;
        private MediaPlayer mediaPlayer;
        private SeekBar seekBar;
        private android.os.Handler handler = new android.os.Handler();
        Runnable updateThread = new Runnable() {
            public void run() {
                // 获得歌曲现在播放位置并设置成播放进度条的值
                if (mediaPlayer != null) {
                    seekBar.setProgress(mediaPlayer.getCurrentPosition());
                    Log.e("Test", "run------ updateThread:getCurrentPosition " + mediaPlayer.getCurrentPosition());
                    // 每次延迟100毫秒再启动线程
                    handler.postDelayed(updateThread, 100);
                }
            }
        };
        private Chronometer et_time;
        private long falgTime;
        private long pauseTime;
        private long subtime;
        private long beginTime;
        private TextView currentTime;
        private int currentProgress;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.test);
    
    
            waveformView = (WaveformView) findViewById(R.id.waveform);
            btnStart = (Button) findViewById(R.id.button_start);
            btnPasue = (Button) findViewById(R.id.button_pasue);
            btnStop = (Button) findViewById(R.id.button2_stop);
            btnPlay = (Button) findViewById(R.id.button_play);
            btnPlay2 = (Button) findViewById(R.id.button_play2);
            btnSave = (Button) findViewById(R.id.button_save);
            seekBar = (SeekBar) findViewById(R.id.sb);
            et_time = (Chronometer) this.findViewById(R.id.et_time);
            currentTime = (TextView) this.findViewById(R.id.currentTime);
    
    
            btnStart.setOnClickListener(this);
            btnPasue.setOnClickListener(this);
            btnStop.setOnClickListener(this);
            btnPlay.setOnClickListener(this);
            btnPlay2.setOnClickListener(this);
            btnSave.setOnClickListener(this);
    
    
            initPar();
            initRecorder(true);
            initAudioTack();
        }
    
    
        @Override
        protected void onResume() {
            super.onResume();
    
            initRecorder(false);
        }
    
        private void initAudioTack() {
            minBufferSize = AudioTrack.getMinBufferSize(rate, 3, audioFormat);
            Log.e("Test", "initAudioTack------ minBufferSize:" + minBufferSize);
            audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, rate, 1, audioFormat, minBufferSize, AudioTrack.MODE_STREAM);
        }
    
        private void initPar() {
            duration = 60 * 1000;//毫秒
            rate = 44100;//声卡一般提供11.025kHz、22.05kHz和44.1kHz等不同的采样频率
            channelConfig = AudioFormat.CHANNEL_IN_DEFAULT;
            audioFormat = AudioFormat.ENCODING_PCM_16BIT;
            restOfTime = duration;
        }
    
        private void initRecorder(boolean isNew) {
    
            initAudioFile(isNew);
            bufferSize = AudioRecord.getMinBufferSize(rate, channelConfig, audioFormat);
            Log.d("Test", "initRecorder: bufferSize:" + bufferSize);//44100 1 2 = v fc
    //        int k = audioFormat * rate / 25;
    //        if (bufferSize % k != 0) {
    //            bufferSize = (k * (channelConfig + bufferSize / k));
    //        }
            audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, rate, channelConfig, audioFormat, bufferSize);
    
        }
    
        public boolean isRecording() {
            return audioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING;
        }
    
        private void initAudioFile(boolean isNew) {
    
            filePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/akm/t.wav";
    
            new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/akm").mkdir();
            File f = new File(filePath);
            try {
                if (f.exists() && isNew) {
                    f.delete();
                }
    
                randomAccessFile = new RandomAccessFile(filePath, "rw");
                //文件长度 = 比特率*时间
                //= 采样率*位数*声道 / 8
    
                totalLength = (rate * 1 * 16 / 8) * (duration / 1000);
    //            totalLength = (int) (4l * (duration * rate / 1000l));
                createWaveFile(randomAccessFile, true, totalLength);
                totalLength = 44 + totalLength;
                randomAccessFile = new RandomAccessFile(filePath, "rw");
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        private void createWaveFile(RandomAccessFile randomAccessFile, boolean b, int totalLength) {
    
    
            if (b) {
    
    
                try {
    //                randomAccessFile.write(WAVHeader.getHeader(rate,channels,samples));
                    // long totalAudioLen,long totalDataLen, long longSampleRate, int channels, long byteRate
                    //数据长度 文件长度 采样率 声道 比特率
    
                    //比特率(字节/秒)= (采样频率(Hz)× 采样位数(bit) × 声道数)/ 8
                    //
    
                    long byteRate = (channelConfig * audioFormat * rate) / 8;
                    byte[] bytes = WAVHeader.getHeader(totalLength - 36l, totalLength, rate, channelConfig, byteRate);
                    FileChannel localFileChannel = randomAccessFile.getChannel();
                    localFileChannel.map(FileChannel.MapMode.READ_WRITE, 0l, 44l).put(bytes);
                    localFileChannel.close();
                    Log.e("Test", "createWaveFile------ OK ");
    
    
                } catch (IOException e) {
                    e.printStackTrace();
                }
    
    
            }
    
        }
    
    
        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.button_start:
    
                    try {
    
                        mRecordingKeepGoing = true;
    
                        new Thread() {
                            @Override
                            public void run() {
    
    
                                startRecording();
    
                            }
                        }.start();
    
    
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
    
    
                    break;
    
                case R.id.button_pasue:
                    mRecordingKeepGoing = false;
    
                    pauseRecord();
    
                    try {//暂停后,设置文件索引为末尾
    
                        startPos = (int) randomAccessFile.getFilePointer();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
    
                    pausePlay();
    
                    break;
    
    
                case R.id.button_play:
                    startReview(true);
    
                    break;
                case R.id.button2_stop:
                    mRecordingKeepGoing = false;
    
                    stopRecord();
    
                    stopPlay();
    
                    break;
    
                case R.id.button_save:
    
                    startPos = currentProgress;
                    if (randomAccessFile==null){
                        try {
                            randomAccessFile = new RandomAccessFile(filePath, "rw");
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    try {
                        Log.e("Test", "onClick: pos" + randomAccessFile.getFilePointer());
                        int size = ((rate * 1 * 16 / 8) * (currentProgress / 1000));
                        Log.e("Test", "onClick------ size "+size);
                        if (size<44){
                            size = 44;
                        }
                        randomAccessFile.seek(size);
                        randomAccessFile.write(sampleBytes);
                        randomAccessFile.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    Log.e("Test", "onClick------pos "+currentProgress);
    
                    break;
                case R.id.button_play2:
                    play();
                    break;
    
            }
        }
    
        private void pausePlay() {
    
            if (mediaPlayer != null && mediaPlayer.isPlaying()) {
                // 暂停音乐播放器
                mediaPlayer.pause();
                btnPasue.setText("续播");
                seekBar.setEnabled(false);
                et_time.stop();
    
                pauseTime = SystemClock.elapsedRealtime();
                // System.out.println("1 pauseTime" + pauseTime);
            } else if (mediaPlayer != null
                    && "续播".equals(btnPasue.getText().toString())) {
                subtime += SystemClock.elapsedRealtime() - pauseTime;
                // System.out.println("2 subtime:" + subtime);
                mediaPlayer.start();
                btnPasue.setText("暂停");
                seekBar.setEnabled(true);
                beginTime = falgTime + subtime;
                // System.out.println("3 beginTime" + beginTime);
                et_time.setBase(beginTime);
                et_time.start();
            }
        }
    
        private void stopPlay() {
    
    
            if (mediaPlayer != null && mediaPlayer.isPlaying()) {
                mediaPlayer.stop();
                mediaPlayer = null;
                et_time.setBase(SystemClock.elapsedRealtime());
                et_time.start();
                et_time.stop();
                btnPlay2.setEnabled(true);
                btnPlay2.setClickable(true);
            }
            falgTime = 0;
            subtime = 0;
            seekBar.setProgress(0);
            seekBar.setEnabled(false);
    
        }
    
        private void play() {
    
            mediaPlayer = new MediaPlayer();
            try {
                mediaPlayer.setDataSource(filePath);
                mediaPlayer.prepareAsync();
    
                // 为播放器注册
                mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
    
                    public void onPrepared(MediaPlayer mp) {
                        // TODO Auto-generated method stub
                        mediaPlayer.start();
                        btnPlay2.setEnabled(false);
                        btnPlay2.setClickable(false);
                        seekBar.setMax(mediaPlayer.getDuration());
                        handler.post(updateThread);
                        seekBar.setEnabled(true);
                    }
                });
    
                // 注册播放完毕后的监听事件
                mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
    
                    public void onCompletion(MediaPlayer mp) {
    //                    mediaPlayer.release();
    //                    mediaPlayer = null;
                        btnPlay2.setEnabled(true);
                        btnPlay2.setClickable(true);
                        et_time.setBase(SystemClock.elapsedRealtime());
                        et_time.start();
                        et_time.stop();
                        seekBar.setProgress(0);
                    }
                });
                falgTime = SystemClock.elapsedRealtime();
                et_time.setBase(falgTime);
                et_time.start();
    
                et_time.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
                    @Override
                    public void onChronometerTick(Chronometer chronometer) {
    
    
                    }
                });
    
                seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                    @Override
                    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                        if (fromUser == true && mediaPlayer != null) {
                            Log.e("Test", "onProgressChanged------ progress "+progress);
                            mediaPlayer.seekTo(progress);
                            falgTime = SystemClock.elapsedRealtime();
                            beginTime = falgTime - seekBar.getProgress();
                            et_time.setBase(beginTime);
    //                        et_time.start();
    
    
    //                        final int ctime = mediaPlayer.getDuration() / progress;
                            //时间*比特率 = 大小 (rate * 1 * 16 / 8) * (duration / 1000);
                            //时间 = 大小/比特率
    
                            int ctime = progress/((rate * 1 * 16 / 8) * (duration / 1000));
                            currentTime.setText( ctime+ "s");
    
                        }
                    }
    
                    @Override
                    public void onStartTrackingTouch(SeekBar seekBar) {
    
                    }
    
                    @Override
                    public void onStopTrackingTouch(SeekBar seekBar) {
    //                    startPos = seekBar.getProgress();
                        currentProgress = seekBar.getProgress();
    
                    }
                });
    
    
            } catch (IOException e) {
                e.printStackTrace();
            }
            // mediaPlayer.prepare(); // c/c++ 播放器引擎的初始化
            // 同步方法
            // 采用异步的方式
    
    
        }
    
        private OnEventListener onEventListener;
    
        public void setOnEventListener(OnEventListener onEventListener) {
            this.onEventListener = onEventListener;
        }
    
    
        android.os.Handler errorHandler = new android.os.Handler() {
            @Override
            public void handleMessage(Message msg) {
    
                if (onEventListener != null) {
                    onEventListener.onError("error");
                }
    
            }
        };
    
        private void startThread() {
    
            if (startPos == 0) {//开始位置
                try {
                    randomAccessFile.seek(44);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            mThreadFlag = true;
            i = 0;
            j = -1;
            STATUS = 1;
            thread = new Thread() {
                @Override
                public void run() {
    
                    if (startTime == 0) {
                        startTime = System.currentTimeMillis();
    
                    }
                    byte[] arrayOfByte = new byte[bufferSize];
                    short[] arrayOfShort = new short[bufferSize];
                    while (mThreadFlag) {
    
                        try {
                            if (audioRecord == null || STATUS != 1) {
                                continue;
                            }
                            int bufferReadResult = audioRecord.read(arrayOfByte, 0, bufferSize);
                            int bufferReadResult2 = audioRecord.read(arrayOfShort, 0, bufferSize);
    
                            Log.e("Test", "run------ bufferReadResult "+bufferReadResult);
                            Log.e("Test", "run------ bufferReadResult2 "+bufferReadResult2);
    
                            if (audioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING || bufferReadResult <= 0) {
                                break;
                            }
    
                            i = 1;
    
                            randomAccessFile.write(arrayOfByte);
    
    
    
                            waveformView.updateAudioData(arrayOfShort);
    
                            byte[] tmpBuf = new byte[bufferReadResult];
                            System.arraycopy(arrayOfByte, 0, tmpBuf, 0, bufferReadResult);
                            audioTrack.write(tmpBuf, 0, tmpBuf.length);
    
                            pjByteBuffer(tmpBuf);
    
    
                            curFileLength = (int) randomAccessFile.length() / 1024;
                            Log.e("Test", "run------ curFilelength:" + curFileLength + ",startPos:" + startPos + ",endPos:" + endPos + ",isRewrite:" + isRewrite);
                            int time = (int) (System.currentTimeMillis() - startTime);
                            Log.e("Test", "run------ time: " + time);
                            Log.e("Test", "run------ bytes:" + arrayOfByte.length);
                            Log.e("Test", "run------ getFilePointer:" + randomAccessFile.getFilePointer());
    
                            startPos = (int) randomAccessFile.getFilePointer();
    
    
                            if (time >= restOfTime) {
                                stopRecord();
                            }
                            onFileChangedListener.onBufferRecevied(startPos, endPos, arrayOfByte, curFileLength, isRewrite);
    
    
    //                        Test t1 = Test.this;
    //                        t1.i = 1+t1.i;
    //
    //                        long length = randomAccessFile.getFilePointer() + arrayOfByte.length;
    //                        xxx(this,length);
    //                        if (endPos>curFileLength){
    //                            xxx(this,endPos);
    //                        }
    //                        randomAccessFile.write(arrayOfByte);
    //                        onFileChangedListener.onBufferRecevied(startPos,endPos,arrayOfByte,curFileLength,isRewrite);
    //
    //                        Test t2 =Test.this;
    //                        t2.j = 1+t2.j;
    //                        if (i!=0||j!=0){
    //                            continue;
    //                        }
    //                        xxx(this,false);
    //                        errorHandler.sendEmptyMessage(0);
    
    
                        } catch (Exception e) {
                            e.printStackTrace();
                            errorHandler.sendEmptyMessage(0);
                        }
    
                    }
    
    
                }
            };
            thread.start();
    
    
        }
    
    
        private byte[] pjArray(byte[] src, byte[] dest) {
            byte[] newBytes = new byte[src.length + dest.length];
    
            System.arraycopy(src, 0, newBytes, 0, src.length);
            System.arraycopy(dest, 0, newBytes, src.length, dest.length);
    
            return newBytes;
        }
    
        private void pjByteBuffer(byte[] tmpBuf) {
    
            if (sampleBytes == null) {
                sampleBytes = tmpBuf;
            } else {
                sampleBytes = pjArray(sampleBytes, tmpBuf);
            }
    
    
        }
    
    
        private void pauseReview() {
            audioTrackFlag = false;
            audioTrack.pause();
            audioTrack.flush();
            Log.e("Test", "pauseReview------ ");
    
        }
    
        private void startReview(boolean b) {
            if (audioTrack == null) {
                initAudioTack();
            }
            audioTrack.play();
            audioTrackFlag = true;
            audioTrackThread = new Thread() {
                @Override
                public void run() {
                    try {
                        bytes = new byte[minBufferSize];
                        while (randomAccessFile.read(bytes) != -1 && audioTrackFlag) {
    
                            Log.e("Test", "run------ ");
                            Log.e("Test", "run------audiotrackflag is  " + audioTrackFlag);
                            Log.e("Test", "run------wrtie data in audiotrack ");
    
                        }
                        Log.e("Test", "run------ audiotrack end.");
    
                    } catch (Exception e) {
    
                    }
                }
            };
            audioTrackThread.start();
    
    
        }
    
    
        public void pauseRecord() {
    
            if (audioRecord != null) {
                audioRecord.stop();
                mThreadFlag = false;
            }
        }
    
        private void reset() {
            startPos = 0;
            endPos = 0;
            curFileLength = 44;
            isRewrite = false;
        }
    
    
        private void resumeRecord() {
    
    
            while (isRewrite) {//写文件
    
    
                try {
                    if (randomAccessFile.getFilePointer() != endPos || !isRewrite) {//不可写 ,或者选中位置不是文件指针所在位置
                        startPos = (int) randomAccessFile.getFilePointer(); // 从文件指针位置开始
                    }
                    if (!isRewrite) {//不写文件
    
                        if (44 + startPos >= endPos) {//
                            continue;
                        }
    
                        isRewrite = true;
    
                    }
    
    
                } catch (IOException e) {
                    e.printStackTrace();
                }
    
    
                audioRecord.startRecording();
                if (thread == null || !mThreadFlag) {
                    startThread();
                }
    
            }
        }
    
        private void startRecording() {
            try {
                audioRecord.startRecording();
    
    //            if (thread==null||!mThreadFlag){
    //                startThread();
    //            }
                startThread();
                Log.e("Test", "startRecording------ ");
            } catch (Exception e) {
                initRecorder(true);
            }
    
        }
    
        public int getMinBufferSize() {
            return minBufferSize;
        }
    
        public void getMinBufSize() {
            recBufSize = AudioRecord.getMinBufferSize(frequency, 12, 2);
        }
    
        public void setOnFileChangedListener(OnFileChangedListener onFileChangedListener) {
            this.onFileChangedListener = onFileChangedListener;
        }
    
        public void setDuration(int duration) {
            this.duration = duration;
        }
    
        interface OnFileChangedListener {
            void onBufferRecevied(long startPos, long endPos, byte[] b1, long currenFileLength, boolean isRew);
        }
    
        interface OnEventListener {
            void onError(String s);
    
            void onRecordComplete();
    
            void onVolumnChanged(double vl);
        }
    
        public String creatFile() {
    //        copyWaveFile(filePath,filePath,true);
            return outPath;
        }
    
        private void moveToPrevious(long pl) {
            try {
                long l = 44 + 4 * (pl * rate / 1000l);
                randomAccessFile.seek(l);
                Log.e("Test", "moveToPrevious------ offset:" + l + " length:" + randomAccessFile.length());
    
            } catch (Exception e) {
    
            }
    
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            stopRecord();
        }
    
        @Override
        protected void onStop() {
            super.onStop();
            closeStream();
        }
    
        private void stopRecord() {
    
            try {
                mThreadFlag = false;
                time = 0;
                thread = null;
    
                if (audioRecord != null) {
                    if (audioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {
                        audioRecord.stop();
                        Log.e("Test", "stopRecord------ ");
                    }
                    audioRecord.release();
                    audioRecord = null;
    
                }
                closeStream();
    
    
            } catch (Exception e) {
    
            }
    
    
        }
    
        private void closeStream() {
            try {
                if (randomAccessFile != null) {
                    randomAccessFile.close();
                }
            } catch (Exception e) {
    
            }
    
        }
    
    
        float getDensity() {
            DisplayMetrics metrics = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(metrics);
            return metrics.density;
        }
    
    
    }
    
    展开全文
  • Android录音声波动画

    2015-09-16 09:30:28
    这是一个录音声波动画demo。MediaPlayer录音与播放,自定义View横向显示当前声音的动画,主页是根据分贝来的。
  • 录音时显示的声波

    2012-12-21 05:21:12
    如何显示出类似下面图片中的声波?当用户说话的时候,黄色的条形可以根据录音的音量动态波动。 ![CSDN移动问答][1] 我看了apped的[例子][2]但是没有我想要的这种。 请高手指点。 [1]: ...
  • 录音机 app 支持录音播放 暂停 继续播放 删除 等常见操作 ,声波动画效果 后台可以上传
  • VoiceRipple About []() Voice Record Button that has ripple effect with users voice. Calculation of decibels from max amplitude by using the following: power_db = 20 * log10(amp / amp_ref) ...
  • 录音软件原因吗?还是手机问题?今天就由我给大家科普一个“冷知识”——为啥录制的声音听起来不像自己的声音?声音介质的不同听别人说话时通过空气传播的声波引发鼓膜震动,经由三块听小骨传到耳蜗。螺旋状的耳蜗...
    b7920e7a9f128bf7741aff82a1e15b07.gif

    相信很多人都有这样的经历——

    “点开微信里自己发过的语音消息……Emmm,这谁?!为什么微信里自己的声音变得有点儿奇怪?是录音软件原因吗?还是手机问题?

    b7920e7a9f128bf7741aff82a1e15b07.gif30099b668aa2e18eaa03524c1442648b.png

    今天就由我给大家科普一个“冷知识”——为啥录制的声音听起来不像自己的声音?

    33339763502358a3ebdc67c5594423f9.gif

    声音介质的不同

    b7920e7a9f128bf7741aff82a1e15b07.gif

    听别人说话时

    通过空气传播的声波引发鼓膜震动,经由三块听小骨传到耳蜗。

    螺旋状的耳蜗中充满液体,可以将震动转化成神经冲动被大脑接收并分析。

    听自己说话时

    声音会通过我们的身体组织和骨骼传到大脑。

    波长更长的声音,也就是所谓的低音,更容易穿过我们的身体组织到达耳朵,让我们觉得自己的声音很有厚度。

    而大脑也会扮演一个“欺骗”自己的角色, 过滤掉自己声音里的瑕疵,因此你会觉得自己的声音听上去很有磁性。

    b7920e7a9f128bf7741aff82a1e15b07.gif0e8cbf9f11548efcd23b2a89f5aa03d4.png所以呀,自己的声音在别人耳朵里的样子就是你录音听到的声音,也就可以解释为什么自己觉得录的声音很奇怪,别人却说:你的声音就是这个亚子!33339763502358a3ebdc67c5594423f9.gif

    录音难听的真相

    b7920e7a9f128bf7741aff82a1e15b07.gif

    接下来说说为什么我们会觉得自己的录音难听。

    首先,当我们讲话时,听觉系统可以判断发音是否悦耳,从而协助嘴巴发出我们觉得好听的声音;而一般的录音设备,比如手机,不能对录音作出调整。

    而且,你已经习惯了自己说话的声音,却很少听自己的录音,人类对陌生声音会感到抗拒,所以才会觉得自己的录音里的声音难以接受!

    a4699aa9a5e9231e62a7a012c4bf8bf6.png4e6e0b8ed26f3921d9f5a1ecb250654c.gif 饮泣的你冻吗

    有些同学会对这种现象产生焦虑,其实很好解决:习惯成自然。没事儿多听听自己的录音,慢慢就不会抗拒啦!

    b7920e7a9f128bf7741aff82a1e15b07.gif

    往期精彩

    指甲上的月牙越多越健康吗?

    节食减肥真的靠谱吗?

    关灯玩手机的危害有多大?

    2dc89e9fd285a8e19281391f4c3f2b47.gif

    觉得内容还不错的话,给我点个“在看”呗

    b7920e7a9f128bf7741aff82a1e15b07.gifb8d794515ab11fee90968f4b5e78fd77.gif
    展开全文
  • 机器之心报道参与:路、张倩传统的非视距成像方法多是利用光波进行图像重建,最近斯坦福和英特尔实验室的研究者提出一种新方法,用声波的方式进行穿墙探测,并进行图像重建。该研究表示,声学方法可以「看到」墙那面...

    机器之心报道

    参与:路、张倩

    传统的非视距成像方法多是利用光波进行图像重建,最近斯坦福和英特尔实验室的研究者提出一种新方法,用声波的方式进行穿墙探测,并进行图像重建。该研究表示,声学方法可以「看到」墙那面的多个事物,且允许的距离范围较大,同时成本较低、时间较短。相关研究已被 CVPR 2019 接收。

    c4f8c7a3d1dba4853ec3174a01382edd.png

    我站在墙前,想看到拐角处我视线范围之外的事物,除了伸长脖子或者走过去,还有别的方法吗?

    非视距成像(Non-line-of-sight (NLOS) imaging)技术利用角落或障碍物周围墙壁反射的光波,重建出图像,从而看到视线之外的事物。但这种光学方法中用到的硬件非常昂贵,且对距离的要求较高。

    那么,如果不使用光波,转而使用声波呢?

    来自斯坦福大学与英特尔实验室的研究人员想要试试看,他们构建了一个硬件原型 :一个装有现成麦克风和小型汽车扬声器的垂直杆,参见下图:

    13cba87ac806b96bbcaa8cd33c8f0723.png

    原型系统图。该原型包括一个垂直安装在 1 米平移台上的 16 个扬声器和麦克风线性阵列。功率放大器和一组音频接口驱动扬声器并从麦克风录音。

    在实际操作中,扬声器会发出一串啾啾声,声音以一定角度弹到附近的墙壁上,然后撞到另一面墙上的隐藏物体:一张字母 H 形状的海报板。然后,科学家们一点一点地移动设备,每次都发出更多的声音,最后声音以同样的方式反弹回麦克风。

    34a1d57fac05b9764cf74fd9ba5316ba.gif

    2D 声学 NLOS 扫描系统的可视化。

    接下来,研究人员使用地震成像的算法,对字母 H 的外观进行粗糙重建。

    3891940baba513abc600b762284711c8.gif

    地震学中有类似的问题,利用冲击波进行探测并重建地下结构的图像。

    该研究对字母 H 的重建结果如下图所示:

    2d121fbf8da7b975a0e0095bc10e59a1.gif

    上图只是一个「隐藏物体」的图像重建结果,那么如果有多个隐藏物体,系统也能够很好地执行图像重建吗?

    答案是:YES!

    下图展示了该系统对 4 个隐藏物体的图像重建结果:

    9ca5d77a1187a5867c75b684a8a1a33e.gif

    从这些实验结果上来看,利用声音信号进行 NLOS 成像是可行的。那么,它的效果能不能比得上基于光波的 NLOS 成像方法呢?

    研究者也进行了对比。如下图所示,给出两个字母 L 和 T,光学方法需要使用的设备比较昂贵,且只能生成 T 的图像,对于距离较远的字母 L 则没有成功重建图像,此外,该方法需要花费的时间较长,超过一小时。

    相比之外,该研究所提出的声学方法能够重建出两个字母的图像,且时间较短,只用了四分半钟!距离也比光学方法高出 2 倍。

    07e5a3f3a36b341c07382073069bc4a5.gif

    这项技术距离应用还需要数年的时间,但作者表示,该技术的超声波版本最终可能会应用于自动驾驶汽车上,用来探测看不见的障碍物。或者,你可以用它来监视隔板另一边的同事(可怕!

    原理介绍

    研究者参数化了声学波场,使得发射扬声器和接收麦克风位于 {(x, y, z)∈R×R×R | z = 0} 平面上。该波场是 τ (x_t, y_t, x_r, y_r, t) 的 5D 函数,其中,x_t、y_t 表示扬声器的空间位置,x_r、y_r 表示麦克风位置,t 表示时间(见图 1 和图 2)。

    b0f9b219261493758a3e6344b12002f9.png

    图 1. 该研究提出的声学 NLOS 成像方法概览图。调制声波从扬声器发出,穿过墙角到达隐藏物体,在反射回来时由一个麦克风记录下来。处理后的测量值(左下)包含峰值,表示声音从扬声器直接传播到麦克风的路径长度(A,峰值被剪切)、传播到墙并回返的路径长度(B),以及到隐藏物体并回返的路径长度(C)。从一系列扬声器和麦克风的位置捕捉这些测量值,用于重建隐藏物体的 3D 几何形状(右下)。

    0fccb85497305c3e7c26cc038ac1bab8.png

    图 2:场景几何和测量值捕获示意图。声阵列发出声信号,该声信号通过墙壁反射到隐藏物体,然后反射回来。由于墙壁在声波波长上的镜面散射,测量数据似乎是从位于墙壁后面的镜像体中捕获的,就好像墙壁是透明的一样。发射信号的频率随时间而线性变化。对于单个反射器来说,返回信号是延迟版的发射信号(右上角)。接收和发射信号混合在一起并进行傅里叶变换,在与反射器距离成正比的频率上产生一个波峰(右下角)。

    图 1 和图 2 进一步显示了测量值的几何结构。在声学波长上,墙充当一个类似镜面的反射器,将发射信号 g 散射到拐角,到达隐藏物体,然后返回到声波阵列。

    由于墙的镜面散射,在测量中,隐藏物体似乎位于墙外的一个位置。因此研究者选择忽略墙,以使图像重建步骤建模从位于透明墙后面的虚拟对象捕获的测量值。对于同样具有镜面散射的光滑隐藏物体,研究者假设虚拟物体的表面法线指向声阵,这样就可以观测到信号。这一假设也被提出,例如,雷达系统通过墙壁成像并捕获镜面散射 [1, 3, 42]。

    如何利用声音

    声波散射

    下图 3 概述了声波散射双向反射分布函数(BRDF):

    e0eae8027df4d1c1cb2b8ffd8ef41814.png

    图 3:声波散射 BRDF 示意图。在大于波长的平坦表面上进行镜面散射(中左)。在等于波长的墙角几何结构上进行逆反射散射(retroreflective scattering,中右)。对于小于波长的表面,物体周围的衍射会导致漫散射(右)。

    信号随距离的衰减

    对比光学 NLOS 成像中常见的漫反射,声学信号衰减与 1/(r_t+r_r)^2 成正比,而光学信号衰减与

    2549b3c4d232a5e8c2e8d65eefd57a78.png

    成正比。研究者在图 4 中通过实验验证了这种衰减。

    2fd442e164384e103be8bd16c354e068.png

    图 4:信号衰减(左)和分辨率分析(右)。研究者利用 log-log 尺度上的线性回归,绘制了角反射器和平面镜面散射目标的测量值。角反射器的信号衰减约为 d^ −1.92,而平面目标的信号衰减约为 d^−1.89,与预期的 d^−2 衰减基本吻合。图中还展示了漫反射光学 NLOS 成像的 d^−4 衰减。与典型的光学方法相比,该研究给出了一系列声信号带宽范围下不同距离对应的横向分辨率(lateral resolution)。

    传输信号

    下图 2 描述了信号传输的过程。

    5dd774b044186ee25aa1ea2b6738bd4f.png

    如何生成图像

    当信号发射位置和接收位置相同时,即 x_t = x_r,y_t = y_r,研究者使用闭合解(closed-form solution)进行图像重建。也就是光学 NLOS 成像方法中所说的「共焦」扫描。研究者对空间位置接近的扬声器和麦克风进行声学共焦测量。

    共焦测量能够对隐藏物体的 3D 几何形状进行高效的重建,但是在更常见的非共焦测量情况下如何进行高效重建呢?

    研究者首先调整非共焦测量,使其模拟共焦采样网格捕捉到的共焦测量。然后再执行常规的地震成像步骤,即动校正(NMO, normal moveout correction)和倾角时差校正

    878d2c9be36f58d1619993b23d25c793.png

    图 5:动校正和倾角时差校正图示。

    下图 6 展示了如何通过非共焦测量,来改善信号质量、提升空间采样。

    9cc06545e485ec564313b50767755786.png

    图 6:在有两个隐藏物体时,图像重建的流程。

    实现

    除了本文开头所提原型系统所需的硬件设施之外,在软件方面,该系统中所有步骤都使用 Python 实现。目前,该研究已经开源,包含研究所用数据集和软件。

    GitHub 地址:https://github.com/computational-imaging/AcousticNLOS

    关于该研究更多内容,参见以下视频:

    参考链接:

    https://www.sciencemag.org/news/2019/06/scientists-use-sound-see-around-corners

    http://www.computationalimaging.org/publications/acoustic-non-line-of-sight-imaging/

    http://www.computationalimaging.org/wp-content/uploads/2019/03/cvpr_2019_2059.pdf

    展开全文
  • 在对齐的过程(录音的过程)我就发现了QQ音乐、网易云、Groove的音量似乎跟别人不一样,前两者还有各自特色的淡入淡出方式: 自上到下分别为原始音频、Studio One、Groove、Audition、网易云、QQ音乐播放回录的音频...
  • 录音的气泡会随着时间不断变大 最长支持60秒录音,在最后十秒会震动提示用户 最后十秒会有倒计时,如果超时会自动截取 支持转MP3格式 使用简单,一个回调返回语音文件的地址和语音的时长 效果 这个demo 包含了录音...
  • android 声波曲线自定义控件 录音效果 正余弦效果
  • iOS 根据声波分贝峰值,使用贝塞尔曲线绘制动画,并可录音,使用avfundation系统框架。
  • android 录音时出色的动画效果类似于支付宝声波支付时的动画效果
  • Ios录音功能

    2016-02-26 09:46:09
    Ios的录音功能,能运用到即时聊天信息中发送语音消息。单独的录音实现我就不具体说明了,这里介绍的是在即时聊天中的录音情况  首先需要获取录音对象,即需要录音...最后一个是录音的状态,也就是声波状态的设置
  • 原标题:声卡是实现声波/数字信号相互转换的一种硬件声卡是实现声波/数字信号相互转换的一种硬件。其基本功能是把来自话筒、磁带、光盘的原始声音信号加以转换,输出到耳机、扬声器、扩音机、录音机等声响设备,或...
  • 先看效果图嗯,然后大致就是这样,按住录音,然后有一个倒计时,最外层一个进度条,还有一个类似模拟声波的动画效果(其实中间的波浪会根据声音的大小浪起来的~)2实现思路然后,我们适当的来分析一下这个录音动画的...
  • 该源码是一个不错的轻量级播放录音音频的气泡案例,源码FSVoiceBubble,一个轻量级播放录音音频的气泡,特性:1.支持短时间的音频播放(支持网络音频),2.播放时的声波动画,3.自定义包括声波的颜色,气泡的背景等...
  • 嗯,然后大致就是这样,按住录音,然后有一个倒计时,最外层一个进度条,还有一个类似模拟声波的动画效果(其实中间的波浪会根据声音的大小浪起来的~) 2 实现思路 然后,我们适当的来分析一下这个录音动画的实现...
  • Android进阶——声波振幅显示

    千次阅读 2015-12-20 19:59:12
    最近博主想做一个app,中间有一个是录音的功能。于是博主想把UI做的好看一些,想仿照微信或者QQ语音输入时,能够随着声音的大小显示声波振幅。于是查找了一些资料,现在把这个功能的Demo分享给大家,以后也会把更多...

空空如也

空空如也

1 2 3 4 5 6
收藏数 106
精华内容 42
关键字:

录音声波