29 | * AudioProcessors are responsible for actual digital signal processing. The 30 | * interface is simple: a process method that works on an AudioEvent object. 31 | * The AudioEvent contains a buffer with some floats and the same information in 32 | * raw bytes. 33 | *
34 | *35 | * AudioProcessors are meant to be chained e.g. execute an effect and 36 | * then play the sound. The chain of audio processor can be interrupted by returning 37 | * false in the process methods. 38 | *
39 | * @author Joren Six 40 | */ 41 | public interface AudioProcessor { 42 | 43 | /** 44 | * Process the audio event. Do the actual signal processing on an 45 | * (optionally) overlapping buffer. 46 | * 47 | * @param audioEvent 48 | * The audio event that contains audio data. 49 | * @return False if the chain needs to stop here, true otherwise. This can 50 | * be used to implement e.g. a silence detector. 51 | */ 52 | boolean process(AudioEvent audioEvent); 53 | 54 | /** 55 | * Notify the AudioProcessor that no more data is available and processing 56 | * has finished. Can be used to deallocate resources or cleanup. 57 | */ 58 | void processingFinished(); 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/be/tarsos/dsp/io/UniversalAudioInputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * _______ _____ _____ _____ 3 | * |__ __| | __ \ / ____| __ \ 4 | * | | __ _ _ __ ___ ___ ___| | | | (___ | |__) | 5 | * | |/ _` | '__/ __|/ _ \/ __| | | |\___ \| ___/ 6 | * | | (_| | | \__ \ (_) \__ \ |__| |____) | | 7 | * |_|\__,_|_| |___/\___/|___/_____/|_____/|_| 8 | * 9 | * ------------------------------------------------------------- 10 | * 11 | * TarsosDSP is developed by Joren Six at IPEM, University Ghent 12 | * 13 | * ------------------------------------------------------------- 14 | * 15 | * Info: http://0110.be/tag/TarsosDSP 16 | * Github: https://github.com/JorenSix/TarsosDSP 17 | * Releases: http://0110.be/releases/TarsosDSP/ 18 | * 19 | * TarsosDSP includes modified source code by various authors, 20 | * for credits and info, see README. 21 | * 22 | */ 23 | 24 | package be.tarsos.dsp.io; 25 | 26 | import java.io.IOException; 27 | import java.io.InputStream; 28 | 29 | public class UniversalAudioInputStream implements TarsosDSPAudioInputStream { 30 | 31 | private final InputStream underlyingStream; 32 | private final TarsosDSPAudioFormat format; 33 | 34 | public UniversalAudioInputStream(InputStream underlyingInputStream, TarsosDSPAudioFormat format){ 35 | this.underlyingStream = underlyingInputStream; 36 | this.format = format; 37 | } 38 | 39 | @Override 40 | public long skip(long bytesToSkip) throws IOException { 41 | //the skip probably 42 | int bytesSkipped = 0; 43 | for(int i = 0 ; i < bytesToSkip ; i++){ 44 | int theByte = underlyingStream.read(); 45 | if(theByte!=-1){ 46 | bytesSkipped++; 47 | } 48 | } 49 | return bytesSkipped; 50 | } 51 | 52 | @Override 53 | public int read(byte[] b, int off, int len) throws IOException { 54 | return underlyingStream.read(b, off, len); 55 | } 56 | 57 | @Override 58 | public void close() throws IOException { 59 | underlyingStream.close(); 60 | } 61 | 62 | @Override 63 | public TarsosDSPAudioFormat getFormat() { 64 | return format; 65 | } 66 | 67 | @Override 68 | public long getFrameLength() { 69 | return -1; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/be/tarsos/dsp/writer/WriterProcessor.java: -------------------------------------------------------------------------------- 1 | package be.tarsos.dsp.writer; 2 | 3 | 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.IOException; 6 | import java.io.RandomAccessFile; 7 | 8 | import be.tarsos.dsp.AudioEvent; 9 | import be.tarsos.dsp.AudioProcessor; 10 | import be.tarsos.dsp.io.TarsosDSPAudioFormat; 11 | 12 | /** 13 | * This class writes the ongoing sound to an output specified by the programmer 14 | * 15 | */ 16 | public class WriterProcessor implements AudioProcessor { 17 | RandomAccessFile output; 18 | TarsosDSPAudioFormat audioFormat; 19 | private int audioLen=0; 20 | private static final int HEADER_LENGTH=44;//byte 21 | 22 | /** 23 | * 24 | * @param audioFormat which this processor is attached to 25 | * @param output randomaccessfile of the output file 26 | */ 27 | public WriterProcessor(TarsosDSPAudioFormat audioFormat,RandomAccessFile output){ 28 | this.output=output; 29 | this.audioFormat=audioFormat; 30 | try { 31 | output.write(new byte[HEADER_LENGTH]); 32 | } catch (IOException e) { 33 | e.printStackTrace(); 34 | } 35 | } 36 | @Override 37 | public boolean process(AudioEvent audioEvent) { 38 | try { 39 | audioLen+=audioEvent.getByteBuffer().length; 40 | //write audio to the output 41 | output.write(audioEvent.getByteBuffer()); 42 | } catch (IOException e) { 43 | e.printStackTrace(); 44 | } 45 | return true; 46 | } 47 | 48 | @Override 49 | public void processingFinished() { 50 | //write header and data to the result output 51 | WaveHeader waveHeader=new WaveHeader(WaveHeader.FORMAT_PCM, 52 | (short)audioFormat.getChannels(), 53 | (int)audioFormat.getSampleRate(),(short)16,audioLen);//16 is for pcm, Read WaveHeader class for more details 54 | ByteArrayOutputStream header=new ByteArrayOutputStream(); 55 | try { 56 | waveHeader.write(header); 57 | output.seek(0); 58 | output.write(header.toByteArray()); 59 | output.close(); 60 | }catch (IOException e){ 61 | e.printStackTrace(); 62 | } 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/be/tarsos/dsp/GainProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * _______ _____ _____ _____ 3 | * |__ __| | __ \ / ____| __ \ 4 | * | | __ _ _ __ ___ ___ ___| | | | (___ | |__) | 5 | * | |/ _` | '__/ __|/ _ \/ __| | | |\___ \| ___/ 6 | * | | (_| | | \__ \ (_) \__ \ |__| |____) | | 7 | * |_|\__,_|_| |___/\___/|___/_____/|_____/|_| 8 | * 9 | * ------------------------------------------------------------- 10 | * 11 | * TarsosDSP is developed by Joren Six at IPEM, University Ghent 12 | * 13 | * ------------------------------------------------------------- 14 | * 15 | * Info: http://0110.be/tag/TarsosDSP 16 | * Github: https://github.com/JorenSix/TarsosDSP 17 | * Releases: http://0110.be/releases/TarsosDSP/ 18 | * 19 | * TarsosDSP includes modified source code by various authors, 20 | * for credits and info, see README. 21 | * 22 | */ 23 | 24 | 25 | package be.tarsos.dsp; 26 | 27 | /** 28 | * With the gain processor it is possible to adapt the volume of the sound. With 29 | * a gain of 1, nothing happens. A gain greater than one is a volume increase a 30 | * gain between zero and one, exclusive, is a decrease. If you need to flip the 31 | * sign of the audio samples, you can by providing a gain of -1.0. but I have no 32 | * idea what you could gain by doing that (pathetic pun, I know). 33 | * 34 | * @author Joren Six 35 | */ 36 | public class GainProcessor implements AudioProcessor { 37 | private double gain; 38 | 39 | public GainProcessor(double newGain) { 40 | setGain(newGain); 41 | } 42 | 43 | public void setGain(double newGain) { 44 | this.gain = newGain; 45 | } 46 | 47 | @Override 48 | public boolean process(AudioEvent audioEvent) { 49 | float[] audioFloatBuffer = audioEvent.getFloatBuffer(); 50 | for (int i = audioEvent.getOverlap(); i < audioFloatBuffer.length ; i++) { 51 | float newValue = (float) (audioFloatBuffer[i] * gain); 52 | if(newValue > 1.0f) { 53 | newValue = 1.0f; 54 | } else if(newValue < -1.0f) { 55 | newValue = -1.0f; 56 | } 57 | audioFloatBuffer[i] = newValue; 58 | } 59 | return true; 60 | } 61 | 62 | @Override 63 | public void processingFinished() { 64 | // NOOP 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/cythara/Sampler.java: -------------------------------------------------------------------------------- 1 | package com.github.cythara; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | class Sampler { 9 | 10 | static PitchDifference calculateAverageDifference(Listlength samples from the input buffer to the given array, starting at the given offset.
56 | * Samples should be in the range -1.0f to 1.0f.
57 | *
58 | * @param array array to hold samples from the input buffer
59 | * @param offset start writing samples here
60 | * @param length write this many samples
61 | */
62 | void produceInput(float[] array, int offset, int length);
63 |
64 | /**
65 | * Copy length samples from the given array to the output buffer, starting at the given offset.
66 | *
67 | * @param array array to read from
68 | * @param offset start reading samples here
69 | * @param length read this many samples
70 | */
71 | void consumeOutput(float[] array, int offset, int length);
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/java/be/tarsos/dsp/util/fft/GaussWindow.java:
--------------------------------------------------------------------------------
1 | /*
2 | * _______ _____ _____ _____
3 | * |__ __| | __ \ / ____| __ \
4 | * | | __ _ _ __ ___ ___ ___| | | | (___ | |__) |
5 | * | |/ _` | '__/ __|/ _ \/ __| | | |\___ \| ___/
6 | * | | (_| | | \__ \ (_) \__ \ |__| |____) | |
7 | * |_|\__,_|_| |___/\___/|___/_____/|_____/|_|
8 | *
9 | * -------------------------------------------------------------
10 | *
11 | * TarsosDSP is developed by Joren Six at IPEM, University Ghent
12 | *
13 | * -------------------------------------------------------------
14 | *
15 | * Info: http://0110.be/tag/TarsosDSP
16 | * Github: https://github.com/JorenSix/TarsosDSP
17 | * Releases: http://0110.be/releases/TarsosDSP/
18 | *
19 | * TarsosDSP includes modified source code by various authors,
20 | * for credits and info, see README.
21 | *
22 | */
23 |
24 | /*
25 | * Copyright (c) 2007 - 2008 by Damien Di Fede This method will always read an integral number of frames.
47 | * If len does not specify an integral number
48 | * of frames, a maximum of len - (len % frameSize)
49 | * bytes will be read.
50 | *
51 | * @param b the buffer into which the data is read
52 | * @param off the offset, from the beginning of array b, at which
53 | * the data will be written
54 | * @param len the maximum number of bytes to read
55 | * @return the total number of bytes read into the buffer, or -1 if there
56 | * is no more data because the end of the stream has been reached
57 | * @throws IOException if an input or output error occurs
58 | * @see #skip
59 | */
60 | int read(byte[] b, int off, int len) throws IOException ;
61 |
62 | /**
63 | * Closes this audio input stream and releases any system resources associated
64 | * with the stream.
65 | * @throws IOException if an input or output error occurs
66 | */
67 | public void close() throws IOException;
68 |
69 | /**
70 | *
71 | * @return The format of the underlying audio
72 | */
73 | TarsosDSPAudioFormat getFormat();
74 |
75 | long getFrameLength();
76 | }
77 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Cythara
2 | A musical instrument tuner for Android.
3 |
4 | [
](https://f-droid.org/packages/com.github.cythara/)
7 |
8 | ## Functionality
9 |
10 | * Provides tunings for various instruments and supports chromatic tuning.
11 | * Changes background color from red to green to indicate that the pitch is in tune (with a tolerance of 10 cents).
12 | * Displays deviations between -60 and 60 cents.
13 | * Supports scientific pitch notation and Solfège.
14 |
15 | ## Tests
16 |
17 | Run `./gradlew test` to run all unit tests. In addition, there are UI tests based on image comparisons which
18 | can be run using `./gradlew connectedCheck`. The reference images are generated using a Nexus 5X emulator
19 | (resolution: 1080 x 1920, 420 dpi) with API level 26.
20 |
21 | ## Libraries
22 |
23 | The Tarsos DSP library (https://github.com/JorenSix/TarsosDSP) is used for pitch detection.
24 |
25 | Current library version: commit [d958352](https://github.com/JorenSix/TarsosDSP/tree/d9583528b9573a97c220d19e6d9ab2929e9bd1c5)
26 |
27 | ## License
28 |
29 | Cythara is licensed under GPLv3. A copy of the license is included in the [LICENSE](https://github.com/gstraube/cythara/blob/master/LICENSE).
30 |
31 | # Contributors
32 |
33 | In chronological order:
34 | * [mtbu](https://github.com/mtbu) added the violin tuning
35 | * [afmachado](https://github.com/afmachado) provided the translation to Brazilian Portuguese
36 | * [tebriz159](https://github.com/tebriz159) created the logo
37 | * [toXel](https://github.com/toXel) provided the translation to German
38 | * [TacoTheDank](https://github.com/TacoTheDank) enabled the installation on external storage, upgraded the language level, and updated dependencies
39 | * [thim](https://github.com/thim) added the cello tuning, fixed issues, and updated library versions
40 | * [obibon](https://github.com/obibon) provided the translation to Basque
41 | * [Daveed9](https://github.com/Daveed9) added the viola tuning
42 | * [SiIky](https://github.com/SiIky) added the Drop C bass tuning and suggested a more reliable way of handling note frequencies
43 | * [romgarb](https://github.com/romgarb) added the Turkish Oud standard tuning
44 | * [klausweiss](https://github.com/klausweiss) added the Banjo tuning and missing translations
45 | * [berkaygunduzz](https://github.com/berkaygunduzz) provided the translation to Turkish
46 | * [gtataranni](https://github.com/gtataranni) added the guitalele tuning
47 |
48 | Thank you all!
49 |
50 | ## Screenshots
51 |
52 | 
53 |
54 | 
55 |
56 | 
57 |
58 | 
59 |
60 | 
61 |
--------------------------------------------------------------------------------
/app/src/main/java/be/tarsos/dsp/wavelet/HaarWaveletFileReader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * _______ _____ _____ _____
3 | * |__ __| | __ \ / ____| __ \
4 | * | | __ _ _ __ ___ ___ ___| | | | (___ | |__) |
5 | * | |/ _` | '__/ __|/ _ \/ __| | | |\___ \| ___/
6 | * | | (_| | | \__ \ (_) \__ \ |__| |____) | |
7 | * |_|\__,_|_| |___/\___/|___/_____/|_____/|_|
8 | *
9 | * -------------------------------------------------------------
10 | *
11 | * TarsosDSP is developed by Joren Six at IPEM, University Ghent
12 | *
13 | * -------------------------------------------------------------
14 | *
15 | * Info: http://0110.be/tag/TarsosDSP
16 | * Github: https://github.com/JorenSix/TarsosDSP
17 | * Releases: http://0110.be/releases/TarsosDSP/
18 | *
19 | * TarsosDSP includes modified source code by various authors,
20 | * for credits and info, see README.
21 | *
22 | */
23 |
24 | package be.tarsos.dsp.wavelet;
25 |
26 | import java.io.FileInputStream;
27 | import java.io.FileNotFoundException;
28 | import java.io.IOException;
29 |
30 | import be.tarsos.dsp.AudioEvent;
31 | import be.tarsos.dsp.AudioProcessor;
32 |
33 | public class HaarWaveletFileReader implements AudioProcessor {
34 |
35 | private final int compression;
36 | private FileInputStream rawInputStream;
37 |
38 | public HaarWaveletFileReader(String fileName, int compression){
39 | this.compression = compression;
40 | try {
41 | this.rawInputStream = new FileInputStream(fileName);
42 | } catch (FileNotFoundException e) {
43 | this.rawInputStream = null;
44 | }
45 | }
46 |
47 | @Override
48 | public boolean process(AudioEvent audioEvent) {
49 |
50 | float[] audioBuffer = new float[32];
51 |
52 | byte[] byteBuffer = new byte[(32-compression)*2];
53 | int placesWithZero = 0;
54 | try {
55 | rawInputStream.read(byteBuffer);
56 | placesWithZero += rawInputStream.read();
57 | placesWithZero += (rawInputStream.read()<<8);
58 | placesWithZero += (rawInputStream.read()<<16);
59 | placesWithZero += (rawInputStream.read()<<24);
60 | } catch (IOException e) {
61 | e.printStackTrace();
62 | }
63 |
64 | int byteBufferIndex = 0;
65 | for(int i = 0 ; i < audioBuffer.length ; i++){
66 | if((placesWithZero & (1< 0;
82 | } catch (IOException e) {
83 |
84 | e.printStackTrace();
85 | }
86 |
87 | return more;
88 | }
89 |
90 | @Override
91 | public void processingFinished() {
92 | try {
93 | rawInputStream.close();
94 | } catch (IOException e) {
95 | e.printStackTrace();
96 | }
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/app/src/main/java/be/tarsos/dsp/resample/SoundTouchRateTransposer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * _______ _____ _____ _____
3 | * |__ __| | __ \ / ____| __ \
4 | * | | __ _ _ __ ___ ___ ___| | | | (___ | |__) |
5 | * | |/ _` | '__/ __|/ _ \/ __| | | |\___ \| ___/
6 | * | | (_| | | \__ \ (_) \__ \ |__| |____) | |
7 | * |_|\__,_|_| |___/\___/|___/_____/|_____/|_|
8 | *
9 | * -------------------------------------------------------------
10 | *
11 | * TarsosDSP is developed by Joren Six at IPEM, University Ghent
12 | *
13 | * -------------------------------------------------------------
14 | *
15 | * Info: http://0110.be/tag/TarsosDSP
16 | * Github: https://github.com/JorenSix/TarsosDSP
17 | * Releases: http://0110.be/releases/TarsosDSP/
18 | *
19 | * TarsosDSP includes modified source code by various authors,
20 | * for credits and info, see README.
21 | *
22 | */
23 |
24 | package be.tarsos.dsp.resample;
25 |
26 | import be.tarsos.dsp.AudioDispatcher;
27 | import be.tarsos.dsp.AudioEvent;
28 | import be.tarsos.dsp.AudioProcessor;
29 |
30 | /**
31 | * Currently not working sample rate transposer, works only for integer factors.
32 | * Changes sample rate by using linear interpolation.
33 | *
34 | * Together with the time stretcher this can be used for pitch shifting.
35 | * @author Joren Six
36 | * @author Olli Parviainen
37 | */
38 | public class SoundTouchRateTransposer implements AudioProcessor {
39 |
40 | private double rate;
41 | int slopeCount;
42 | double prevSample;
43 | private AudioDispatcher dispatcher;
44 |
45 | public void setDispatcher(AudioDispatcher newDispatcher){
46 | this.dispatcher = newDispatcher;
47 | }
48 |
49 | public SoundTouchRateTransposer(double d){
50 | this.rate = d;
51 | }
52 |
53 | @Override
54 | public boolean process(AudioEvent audioEvent) {
55 | int i, used;
56 | float[] src = audioEvent.getFloatBuffer();
57 | float[] dest = new float[(int) Math.round(audioEvent.getBufferSize() / rate)];
58 | used = 0;
59 | i = 0;
60 |
61 | // Process the last sample saved from the previous call first...
62 | while (slopeCount <= 1.0f) {
63 | dest[i] = (float)((1.0f - slopeCount) * prevSample + slopeCount * src[0]);
64 | i++;
65 | slopeCount += rate;
66 | }
67 | slopeCount -= 1.0f;
68 | end:
69 | while(true){
70 | while (slopeCount > 1.0f) {
71 | slopeCount -= 1.0f;
72 | used++;
73 | if (used >= src.length - 1)
74 | break end;
75 | }
76 | if(i < dest.length){
77 | dest[i] = (float)((1.0f - slopeCount) * src[used] + slopeCount * src[used + 1]);
78 | }
79 | i++;
80 | slopeCount += rate;
81 | }
82 |
83 | //Store the last sample for the next round
84 | prevSample = src[src.length - 1];
85 | dispatcher.setStepSizeAndOverlap(dest.length, 0);
86 | audioEvent.setFloatBuffer(dest);
87 | return true;
88 | }
89 |
90 | @Override
91 | public void processingFinished() {
92 |
93 | }
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/app/src/main/java/be/tarsos/dsp/Oscilloscope.java:
--------------------------------------------------------------------------------
1 | /*
2 | * _______ _____ _____ _____
3 | * |__ __| | __ \ / ____| __ \
4 | * | | __ _ _ __ ___ ___ ___| | | | (___ | |__) |
5 | * | |/ _` | '__/ __|/ _ \/ __| | | |\___ \| ___/
6 | * | | (_| | | \__ \ (_) \__ \ |__| |____) | |
7 | * |_|\__,_|_| |___/\___/|___/_____/|_____/|_|
8 | *
9 | * -------------------------------------------------------------
10 | *
11 | * TarsosDSP is developed by Joren Six at IPEM, University Ghent
12 | *
13 | * -------------------------------------------------------------
14 | *
15 | * Info: http://0110.be/tag/TarsosDSP
16 | * Github: https://github.com/JorenSix/TarsosDSP
17 | * Releases: http://0110.be/releases/TarsosDSP/
18 | *
19 | * TarsosDSP includes modified source code by various authors,
20 | * for credits and info, see README.
21 | *
22 | */
23 |
24 |
25 | package be.tarsos.dsp;
26 |
27 | /**
28 | * The oscilloscope generates a float array with
29 | * array[i] an x coordinate in percentage
30 | * array[i+1] the value of the amplitude in audio buffer
31 | * array[i+2] another x coordinate in percentage
32 | * array[i+3] the next amplitude in the audio buffer
33 | *
34 | * The implementation is based on the one by Dan Ellis found at http://www.ee.columbia.edu/~dpwe/resources/Processing/
35 | * @author Dan Ellis
36 | * @author Joren Six
37 | *
38 | */
39 | public class Oscilloscope implements AudioProcessor {
40 | public static interface OscilloscopeEventHandler{
41 | /**
42 | * @param data The data contains a float array with:
43 | * array[i] an x coordinate in percentage
44 | * array[i+1] the value of the amplitude in audio buffer
45 | * array[i+2] another x coordinate in percentage
46 | * array[i+3] the next amplitude in the audio buffer
47 | * @param event An audio Event.
48 | */
49 | void handleEvent(float[] data, AudioEvent event);
50 | }
51 | float[] dataBuffer;
52 | private final OscilloscopeEventHandler handler;
53 | public Oscilloscope(OscilloscopeEventHandler handler){
54 | this.handler = handler;
55 | }
56 |
57 | @Override
58 | public boolean process(AudioEvent audioEvent) {
59 | float[] audioBuffer = audioEvent.getFloatBuffer();
60 | int offset = 0;
61 | float maxdx = 0;
62 | for (int i = 0; i < audioBuffer.length / 4; ++i) {
63 | float dx = audioBuffer[i + 1] - audioBuffer[i];
64 | if (dx > maxdx) {
65 | offset = i;
66 | maxdx = dx;
67 | }
68 | }
69 |
70 | float tbase = audioBuffer.length / 2;
71 |
72 |
73 | int length = Math.min((int) tbase, audioBuffer.length-offset);
74 | if(dataBuffer == null || dataBuffer.length != length * 4){
75 | dataBuffer = new float[length * 4];
76 | }
77 |
78 | int j = 0;
79 | for(int i = 0; i < length - 1; i++){
80 | float x1 = i / tbase;
81 | float x2 = i / tbase;
82 | dataBuffer[j] = x1;
83 | dataBuffer[j+1] = audioBuffer[i+offset];
84 | dataBuffer[j+2] = x2;
85 | dataBuffer[j+3] = audioBuffer[i+1+offset];
86 | j = j + 4;
87 | }
88 | handler.handleEvent(dataBuffer, audioEvent);
89 | return true;
90 | }
91 |
92 | @Override
93 | public void processingFinished() {
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/app/src/main/java/be/tarsos/dsp/beatroot/BeatRootOnsetEventHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * _______ _____ _____ _____
3 | * |__ __| | __ \ / ____| __ \
4 | * | | __ _ _ __ ___ ___ ___| | | | (___ | |__) |
5 | * | |/ _` | '__/ __|/ _ \/ __| | | |\___ \| ___/
6 | * | | (_| | | \__ \ (_) \__ \ |__| |____) | |
7 | * |_|\__,_|_| |___/\___/|___/_____/|_____/|_|
8 | *
9 | * -------------------------------------------------------------
10 | *
11 | * TarsosDSP is developed by Joren Six at IPEM, University Ghent
12 | *
13 | * -------------------------------------------------------------
14 | *
15 | * Info: http://0110.be/tag/TarsosDSP
16 | * Github: https://github.com/JorenSix/TarsosDSP
17 | * Releases: http://0110.be/releases/TarsosDSP/
18 | *
19 | * TarsosDSP includes modified source code by various authors,
20 | * for credits and info, see README.
21 | *
22 | */
23 |
24 | package be.tarsos.dsp.beatroot;
25 |
26 | import java.util.Iterator;
27 |
28 | import be.tarsos.dsp.onsets.OnsetHandler;
29 |
30 | /**
31 | * Forms a bridge between the BeatRoot beat tracking system and an
32 | * interchangeable onset detector. The beat tracker does not work in real-time.
33 | * First all onsets need to be detected. In a post-processing step a beat
34 | * estimation is done using reocurring inter onset intervals (IOI's). To return
35 | * the time of the beats an OnsetHandler is abused.
36 | *
37 | * @author Joren Six
38 | */
39 | public class BeatRootOnsetEventHandler implements OnsetHandler {
40 |
41 | private final EventList onsetList = new EventList();
42 |
43 | @Override
44 | public void handleOnset(double time, double salience) {
45 | double roundedTime = Math.round(time *100 )/100.0;
46 | Event e = newEvent(roundedTime,0);
47 | e.salience = salience;
48 | onsetList.add(e);
49 | }
50 |
51 |
52 | /**
53 | * Creates a new Event object representing an onset or beat.
54 | *
55 | * @param time
56 | * The time of the beat in seconds
57 | * @param beatNum
58 | * The index of the beat or onset.
59 | * @return The Event object representing the beat or onset.
60 | */
61 | private Event newEvent(double time, int beatNum) {
62 | return new Event(time,time, time, 56, 64, beatNum, 0, 1);
63 | }
64 |
65 | /**
66 | * Guess the beats using the populated list of onsets.
67 | *
68 | * @param beatHandler
69 | * Use this handler to get the time of the beats. The salience of
70 | * the beat is not calculated: -1 is returned.
71 | */
72 | public void trackBeats(OnsetHandler beatHandler){
73 | AgentList agents = null;
74 | // tempo not given; use tempo induction
75 | agents = Induction.beatInduction(onsetList);
76 | agents.beatTrack(onsetList, -1);
77 | Agent best = agents.bestAgent();
78 | if (best != null) {
79 | best.fillBeats(-1.0);
80 | EventList beats = best.events;
81 | Iterator