Android Open Source - speech_trainer Audio Event Collector






From Project

Back to project page speech_trainer.

License

The source code is released under:

GNU General Public License

If you think the Android project speech_trainer listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/**
 * This file is part of Speech Trainer.// w ww . ja v  a  2  s  . co  m
 * Copyright (C) 2011 Jan Wrobel <wrr@mixedbit.org>
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package mixedbit.speechtrainer.model;

import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.SortedSet;
import java.util.TreeSet;

import mixedbit.speechtrainer.Assertions;
import mixedbit.speechtrainer.SpeechTrainerConfig;
import mixedbit.speechtrainer.controller.AudioEventListener;

/**
 * The AudioEventCollector is separated from a GUI component ( udioEventView) to
 * simplify testing. The non-trivial logic is encapsulated in the
 * AudioEventCollector and provided to the GUI via AudioHistoryProvider
 * interface. This minimizes the GUI component responsibilities.
 */
public class AudioEventCollector implements AudioEventListener, AudioEventHistory {

    private class AudioBufferInfoImpl implements AudioBufferInfo {
        private final int audioBufferId;
        private final double soundLevel;

        private AudioBufferInfoImpl(int audioBufferId, double soundLevel) {
            this.audioBufferId = audioBufferId;
            this.soundLevel = soundLevel;
        }

        @Override
        public int getAudioBufferId() {
            return audioBufferId;
        }

        @Override
        public double getSoundLevel() {
            return soundLevel;
        }

        @Override
        public boolean isPlayed() {
            synchronized (AudioEventCollector.this) {
                return firstBufferPlayed != null
                && firstBufferPlayed.getAudioBufferId() <= audioBufferId
                && audioBufferId <= lastBufferPlayed.getAudioBufferId();
            }
        }
    }

    // How many most recent AudioBufferInfo to keep.
    public static final int HISTORY_SIZE = SpeechTrainerConfig.NUMBER_OF_AUDIO_BUFFERS;
    // A chained listener to which all audio events are also passed (In
    // production code this is the GUI component that displays audio events).
    private final AudioEventListener nextListener;

    // The two sorted sets are kept in sync. They could be replaced with a
    // single NavigableSet that supports iteration in a reverse order.
    // Unfortunately the NavigableSet is available only from Android API
    // level 9.
    private final SortedSet<AudioBufferInfo> recordedBuffersLastRecordedLast;
    private final SortedSet<AudioBufferInfo> recordedBuffersLastRecordedFirst;

    // Recently recorded buffers are not added directly to recordedBuffers in
    // order not to invalidate iterator that can be in use by the GUI.
    private final Queue<AudioBufferInfo> recentlyRecordedBuffers = new LinkedList<AudioBufferInfo>();
    private double maxSoundLevel;
    private double minSoundLevel;
    private AudioBufferInfoImpl firstBufferPlayed = null;
    private AudioBufferInfoImpl lastBufferPlayed = null;

    /**
     * @param nextListener
     *            A chained listener to which all audio events are passed.
     */
    public AudioEventCollector(AudioEventListener nextListener) {
        this.nextListener = nextListener;
        final Comparator<AudioBufferInfo> lastRecordedBufferLastComparator =
            new Comparator<AudioBufferInfo>() {
            @Override
            public int compare(AudioBufferInfo a, AudioBufferInfo b) {
                if (a.getAudioBufferId() < b.getAudioBufferId()) {
                    return -1;
                }
                if (a.getAudioBufferId() > b.getAudioBufferId()) {
                    return 1;
                }
                return 0;
            }
        };
        recordedBuffersLastRecordedLast = new TreeSet<AudioBufferInfo>(
                lastRecordedBufferLastComparator);
        recordedBuffersLastRecordedFirst = new TreeSet<AudioBufferInfo>(
                Collections.reverseOrder(lastRecordedBufferLastComparator));
        resetHistory();
    }

    @Override
    public void resetHistory() {
        maxSoundLevel = 0.0;
        minSoundLevel = Double.MAX_VALUE;
        recentlyRecordedBuffers.clear();
        recordedBuffersLastRecordedLast.clear();
        recordedBuffersLastRecordedFirst.clear();
    }

    @Override
    public void audioBufferPlayed(int audioBufferId, double soundLevel) {
        synchronized (this) {
            if (firstBufferPlayed == null) {
                firstBufferPlayed = new AudioBufferInfoImpl(audioBufferId, soundLevel);
            }
            lastBufferPlayed = new AudioBufferInfoImpl(audioBufferId, soundLevel);
        }
        nextListener.audioBufferPlayed(audioBufferId, soundLevel);
    }

    @Override
    public void audioBufferRecorded(int audioBufferId, double soundLevel) {
        synchronized (this) {
            Assertions.illegalStateIfFalse(firstBufferPlayed == null,
            "Recorded buffer but recording not started.");
            minSoundLevel = Math.min(soundLevel, minSoundLevel);
            maxSoundLevel = Math.max(soundLevel, maxSoundLevel);
            recentlyRecordedBuffers.add(new AudioBufferInfoImpl(audioBufferId, soundLevel));
        }
        nextListener.audioBufferRecorded(audioBufferId, soundLevel);
    }

    @Override
    public void playingStarted() {
        synchronized (this) {
            firstBufferPlayed = null;
            lastBufferPlayed = null;
        }
        nextListener.playingStarted();
    }

    @Override
    public void playingStopped() {
        nextListener.playingStopped();
    }

    @Override
    public synchronized void recordingStarted() {
        synchronized (this) {
            firstBufferPlayed = null;
            lastBufferPlayed = null;
        }
        nextListener.recordingStarted();
    }

    @Override
    public void recordingStopped() {
        nextListener.recordingStopped();
    }

    @Override
    public void audioBufferRecordingFailed() {
        nextListener.audioBufferRecordingFailed();
    }

    @Override
    public synchronized double getMinSoundLevel() {
        return minSoundLevel;
    }

    @Override
    public synchronized double getMaxSoundLevel() {
        return maxSoundLevel;
    }

    @Override
    public synchronized Iterator<AudioBufferInfo> getIteratorOverAudioEventsToPlot(
            int plotWidth) {
        moveRecentlyRecordedBuffersToRecordedBuffers();
        // This invalidates iterator returned by the previous call to
        // getIteratorOverAudioEventsToPlot, which is OK according to the
        // contract.
        removeOldRecordedBuffers();

        if (isPlaying() && !isOnPlotOfRecentlyRecordedBuffers(firstBufferPlayed, plotWidth)) {
            return centerPlotOn(lastBufferPlayed, plotWidth);
        } else {
            // An iterator pointing at the most recently recorded buffer.
            return recordedBuffersLastRecordedFirst.iterator();
        }
    }

    private boolean isPlaying() {
        return firstBufferPlayed != null;
    }

    private boolean isOnPlotOfRecentlyRecordedBuffers(AudioBufferInfoImpl audioBuffer, int plotWidth) {
        return (recordedBuffersLastRecordedLast.tailSet(audioBuffer).size() <= plotWidth);
    }

    private Iterator<AudioBufferInfo> centerPlotOn(AudioBufferInfoImpl audioBufferToCenter,
            int plotWidth) {
        // Point the iterator at the buffer to be placed in the center.
        final Iterator<AudioBufferInfo> iterator =
            recordedBuffersLastRecordedLast.tailSet(audioBufferToCenter).iterator();
        AudioBufferInfo startBuffer = recordedBuffersLastRecordedLast.last();
        // Move the iterator by half of the plot width, so the centered buffer
        // is actually in the center.
        for (int i = 0; i <= plotWidth / 2; ++i) {
            if (!iterator.hasNext()) {
                break;
            }
            startBuffer = iterator.next();
        }
        // This is equivalent to reversing the direction of the iterator that
        // was adjusted in previous steps.
        return recordedBuffersLastRecordedFirst.tailSet(startBuffer).iterator();
    }

    private void removeOldRecordedBuffers() {
        while (recordedBuffersLastRecordedLast.size() > HISTORY_SIZE) {
            final AudioBufferInfo bufferToRemove = recordedBuffersLastRecordedLast.first();
            recordedBuffersLastRecordedLast.remove(bufferToRemove);
            recordedBuffersLastRecordedFirst.remove(bufferToRemove);
        }
    }

    private void moveRecentlyRecordedBuffersToRecordedBuffers() {
        while (!recentlyRecordedBuffers.isEmpty()) {
            final AudioBufferInfo bufferToAdd = recentlyRecordedBuffers.remove();
            recordedBuffersLastRecordedLast.add(bufferToAdd);
            recordedBuffersLastRecordedFirst.add(bufferToAdd);
        }
    }
}




Java Source Code List

mixedbit.speechtrainer.AssertionsTest.java
mixedbit.speechtrainer.Assertions.java
mixedbit.speechtrainer.SpeechTrainerConfig.java
mixedbit.speechtrainer.TrainingApplication.java
mixedbit.speechtrainer.controller.AudioBufferAllocatorTest.java
mixedbit.speechtrainer.controller.AudioBufferAllocator.java
mixedbit.speechtrainer.controller.AudioEventListener.java
mixedbit.speechtrainer.controller.AutomaticTrainingControllerTest.java
mixedbit.speechtrainer.controller.AutomaticTrainingController.java
mixedbit.speechtrainer.controller.ControllerFactory.java
mixedbit.speechtrainer.controller.InteractiveTrainingControllerTest.java
mixedbit.speechtrainer.controller.InteractiveTrainingController.java
mixedbit.speechtrainer.controller.Player.java
mixedbit.speechtrainer.controller.RecordPlayTaskManagerTest.java
mixedbit.speechtrainer.controller.RecordPlayTaskManager.java
mixedbit.speechtrainer.controller.Recorder.java
mixedbit.speechtrainer.controller.SilenceFilterTest.java
mixedbit.speechtrainer.controller.SilenceFilter.java
mixedbit.speechtrainer.controller.SilenceLevelDetectorTest.java
mixedbit.speechtrainer.controller.SilenceLevelDetector.java
mixedbit.speechtrainer.controller.TrainingControllerTest.java
mixedbit.speechtrainer.controller.TrainingController.java
mixedbit.speechtrainer.model.AudioBufferInfo.java
mixedbit.speechtrainer.model.AudioEventCollectorTest.java
mixedbit.speechtrainer.model.AudioEventCollector.java
mixedbit.speechtrainer.model.AudioEventHistory.java
mixedbit.speechtrainer.view.AudioEventView.java
mixedbit.speechtrainer.view.FileViewerActivity.java
mixedbit.speechtrainer.view.TrainingActivity.java
mixedbit.speechtrainer.view.TrainingPreferenceActivity.java