├── README.md ├── ic_launcher-web.png ├── res ├── drawable-hdpi │ └── ic_launcher.png ├── drawable-ldpi │ └── ic_launcher.png ├── drawable-mdpi │ └── ic_launcher.png ├── drawable-xhdpi │ └── ic_launcher.png ├── menu │ └── activity_main.xml ├── values-v11 │ └── styles.xml ├── values-v14 │ └── styles.xml ├── values │ ├── strings.xml │ └── styles.xml └── layout │ └── activity_main.xml ├── docs └── research ├── src └── com │ └── github │ └── shadow │ ├── events │ ├── VoiceActivityListeningEvent.java │ ├── MessageEvent.java │ └── VoiceActivityDetectedEvent.java │ ├── config │ └── EventBusConfig.java │ ├── processing │ ├── AudioProcessor.java │ └── processors │ │ ├── AudioSimpleMediaRecorder.java │ │ ├── Audio.java │ │ └── AudioSimpleAudioRecord.java │ ├── services │ └── VoiceActivityDetectorService.java │ └── Shadow.java ├── .gitignore ├── tests └── AndroidManifest.xml ├── proguard-project.txt ├── AndroidManifest.xml ├── shadow.iml └── LICENSE /README.md: -------------------------------------------------------------------------------- 1 | # shadow 2 | -------------------------------------------------------------------------------- /ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/452/shadow/master/ic_launcher-web.png -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/452/shadow/master/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/452/shadow/master/res/drawable-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/452/shadow/master/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/452/shadow/master/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /docs/research: -------------------------------------------------------------------------------- 1 | Voice Activity Detection(VAD) то-есть обнаружение тишины в речевом или аудио сигнале http://habrahabr.ru/post/192954/ 2 | 3 | -------------------------------------------------------------------------------- /src/com/github/shadow/events/VoiceActivityListeningEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.shadow.events; 2 | 3 | public class VoiceActivityListeningEvent { 4 | } -------------------------------------------------------------------------------- /src/com/github/shadow/events/MessageEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.shadow.events; 2 | 3 | public class MessageEvent { 4 | 5 | private final String data; 6 | 7 | public MessageEvent(String data) { 8 | this.data = data; 9 | } 10 | 11 | public String getData() { 12 | return data; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /res/menu/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/com/github/shadow/config/EventBusConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.shadow.config; 2 | 3 | import de.greenrobot.event.EventBus; 4 | 5 | public class EventBusConfig { 6 | 7 | private static EventBus eventBus = EventBus.getDefault(); 8 | 9 | public static EventBus getInstance() { 10 | return eventBus; 11 | } 12 | 13 | } -------------------------------------------------------------------------------- /src/com/github/shadow/processing/AudioProcessor.java: -------------------------------------------------------------------------------- 1 | package com.github.shadow.processing; 2 | 3 | public interface AudioProcessor { 4 | 5 | void start(); 6 | void stop(); 7 | void doIt(); 8 | int getVoiceActivityLevel(); 9 | void setVoiceActivityLevel(int delayTime); 10 | void setDelayTime(int voiceActivityLevel); 11 | } 12 | -------------------------------------------------------------------------------- /src/com/github/shadow/events/VoiceActivityDetectedEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.shadow.events; 2 | 3 | public class VoiceActivityDetectedEvent { 4 | private double level; 5 | 6 | public VoiceActivityDetectedEvent(double level) { 7 | this.level = level; 8 | } 9 | 10 | public double getLevel() { 11 | return level; 12 | } 13 | } -------------------------------------------------------------------------------- /res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /res/values-v14/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | 15 | # Gradle files 16 | .gradle/ 17 | build/ 18 | /*/build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | *~* 29 | .idea 30 | -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Shadow 4 | Play 5 | Start listening 6 | Stop listening 7 | Voice Activity Level: 8 | Time ms: 9 | Audio Files will be saved into \"shadow\" folder 10 | -------------------------------------------------------------------------------- /res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 14 | 15 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /tests/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -keepclassmembers class ** { 22 | public void onEvent*(**); 23 | } 24 | -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 18 | 24 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/com/github/shadow/processing/processors/AudioSimpleMediaRecorder.java: -------------------------------------------------------------------------------- 1 | package com.github.shadow.processing.processors; 2 | 3 | 4 | import android.media.MediaRecorder; 5 | 6 | import com.github.shadow.processing.AudioProcessor; 7 | 8 | import java.io.IOException; 9 | 10 | public class AudioSimpleMediaRecorder implements AudioProcessor { 11 | 12 | private MediaRecorder recorder; 13 | private int maxAmplitude; 14 | 15 | public void stop() { 16 | recorder.stop(); 17 | recorder.release(); 18 | } 19 | 20 | public void start() { 21 | recorder = new MediaRecorder(); 22 | recorder.setAudioSource(MediaRecorder.AudioSource.MIC); 23 | recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); 24 | recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); 25 | recorder.setOutputFile("/dev/null"); 26 | try { 27 | recorder.prepare(); 28 | } catch (IOException e) { 29 | } 30 | recorder.start(); 31 | } 32 | 33 | public int getVoiceActivityLevel() { 34 | if (recorder == null) { 35 | return 0; 36 | } else { 37 | return maxAmplitude = recorder.getMaxAmplitude(); 38 | } 39 | } 40 | 41 | @Override 42 | public void setVoiceActivityLevel(int delayTime) { 43 | 44 | } 45 | 46 | @Override 47 | public void setDelayTime(int voiceActivityLevel) { 48 | 49 | } 50 | 51 | public double getdbLevel() { 52 | int ratio = maxAmplitude; 53 | int db = 0; 54 | if (ratio > 1) 55 | db = (int) (20 * Math.log10(ratio)); 56 | return Math.log10(ratio); 57 | } 58 | 59 | 60 | public void doIt() { 61 | } 62 | 63 | } -------------------------------------------------------------------------------- /src/com/github/shadow/processing/processors/Audio.java: -------------------------------------------------------------------------------- 1 | package com.github.shadow.processing.processors; 2 | 3 | 4 | import android.media.AudioFormat; 5 | import android.media.AudioRecord; 6 | import android.media.MediaRecorder; 7 | 8 | import de.greenrobot.event.EventBus; 9 | 10 | public class Audio { 11 | private EventBus eventBus = EventBus.getDefault(); 12 | int sampleSize = 8000; 13 | double fftOutWindowSize = 0; 14 | 15 | void init() { 16 | int channel_config = AudioFormat.CHANNEL_CONFIGURATION_MONO; 17 | int format = AudioFormat.ENCODING_PCM_16BIT; 18 | 19 | int bufferSize = AudioRecord.getMinBufferSize(sampleSize, channel_config, format); 20 | AudioRecord audioInput = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleSize, channel_config, format, bufferSize); 21 | 22 | int bytesRecorded = 0; 23 | 24 | 25 | byte[] audioBuffer = new byte[bufferSize]; 26 | audioInput.startRecording(); 27 | audioInput.read(audioBuffer, 0, bufferSize); 28 | 29 | double[] micBufferData = new double[bufferSize]; 30 | final int bytesPerSample = 2; // As it is 16bit PCM 31 | final double amplification = 100.0; // choose a number as you like 32 | for (int index = 0, floatIndex = 0; index < bytesRecorded - bytesPerSample + 1; index += bytesPerSample, floatIndex++) { 33 | double sample = 0; 34 | for (int b = 0; b < bytesPerSample; b++) { 35 | int v = audioBuffer[index + b]; 36 | if (b < bytesPerSample - 1 || bytesPerSample == 1) { 37 | v &= 0xFF; 38 | } 39 | sample += v << (b * 8); 40 | } 41 | double sample32 = amplification * (sample / 32768.0); 42 | micBufferData[floatIndex] = sample32; 43 | } 44 | } 45 | 46 | private double ComputeFrequency(int arrayIndex) { 47 | return ((1.0 * sampleSize) / (1.0 * fftOutWindowSize)) * arrayIndex; 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /src/com/github/shadow/services/VoiceActivityDetectorService.java: -------------------------------------------------------------------------------- 1 | package com.github.shadow.services; 2 | 3 | import android.app.Service; 4 | import android.content.Intent; 5 | import android.os.Handler; 6 | import android.os.IBinder; 7 | 8 | import com.github.shadow.config.EventBusConfig; 9 | import com.github.shadow.events.VoiceActivityDetectedEvent; 10 | import com.github.shadow.processing.AudioProcessor; 11 | import com.github.shadow.processing.processors.AudioSimpleAudioRecord; 12 | 13 | import java.util.Timer; 14 | import java.util.TimerTask; 15 | 16 | import de.greenrobot.event.EventBus; 17 | 18 | public class VoiceActivityDetectorService extends Service { 19 | 20 | private static final String TAG = VoiceActivityDetectorService.class.getCanonicalName(); 21 | private EventBus eventBus = EventBusConfig.getInstance(); 22 | private VoiceActivityProcessorThread voiceActivityProcessorThread; 23 | private Timer timer = new Timer(); 24 | private AudioProcessor audioProcessor = new AudioSimpleAudioRecord(); 25 | private final Handler uiHandler = new Handler(); 26 | 27 | @Override 28 | public void onCreate() { 29 | super.onCreate(); 30 | timer.schedule(new TimerTask() { 31 | @Override 32 | public void run() { 33 | uiHandler.post(new Runnable() { 34 | @Override 35 | public void run() { 36 | if (audioProcessor != null) { 37 | double data = audioProcessor.getVoiceActivityLevel(); 38 | eventBus.post(new VoiceActivityDetectedEvent(data)); 39 | } 40 | } 41 | }); 42 | 43 | } 44 | }, 0, 100); 45 | } 46 | 47 | @Override 48 | public int onStartCommand(Intent intent, int flags, int startId) { 49 | String action = intent.getAction(); 50 | if (action.equals("start")) { 51 | voiceActivityProcessorThread = new VoiceActivityProcessorThread(); 52 | audioProcessor.setDelayTime(intent.getIntExtra("delayTime", 1789)); 53 | audioProcessor.setVoiceActivityLevel(intent.getIntExtra("voiceActivityLevel", 379)); 54 | voiceActivityProcessorThread.start(); 55 | } 56 | if (action.equals("stop")) { 57 | voiceActivityProcessorThread.stopThis(); 58 | } 59 | return START_REDELIVER_INTENT; 60 | } 61 | 62 | private class VoiceActivityProcessorThread extends Thread { 63 | 64 | private volatile boolean isStopped; 65 | 66 | public VoiceActivityProcessorThread() { 67 | } 68 | 69 | @Override 70 | public void run() { 71 | audioProcessor.start(); 72 | while (!isStopped) { 73 | audioProcessor.doIt(); 74 | } 75 | } 76 | 77 | public void stopThis() { 78 | isStopped = true; 79 | audioProcessor.stop(); 80 | } 81 | } 82 | 83 | @Override 84 | public void onDestroy() { 85 | if (voiceActivityProcessorThread != null) { 86 | voiceActivityProcessorThread.stopThis(); 87 | } 88 | super.onDestroy(); 89 | } 90 | 91 | @Override 92 | public IBinder onBind(Intent intent) { 93 | return null; 94 | } 95 | 96 | } -------------------------------------------------------------------------------- /res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 9 | 14 | 20 | 21 |