Lettura del flusso MIDI di uno strumento

# mido_test.py
#
# Questo programma dimostra l'utilizzo della libreria MIDO 
# per la gestione dei dispositivi MIDI.
# In particolare, questo programma cattura e stampa il flusso midi
# prodotto da una tastiera elettronica.
# Dopo aver selezionato il dispositivo tra quelli disponibili,
# viene effettuato un ciclo di lettura continua sino all'interruzione
# tramite tasto CTRL-C.
#
# by Andrea Bianchini (2021)
#


import mido

o=mido.get_output_names()

for i in range(len(o)):
    print(str(i)+"-"+o[i])

print()
k=int(input("Seleziona il numero corrispondente al dispositivo di interesse:"))
print()

port = mido.open_input(o[k])

try:
    while True:
        for msg in port.iter_pending():
            if  msg.type!="clock":
                print(msg)
except KeyboardInterrupt:
    print("Interrupted by user")

port.close()

Esempio:

0-Midi Through:Midi Through Port-0 14:0
1-Digital Keyboard:Digital Keyboard MIDI 1 20:0
2-Midi Through:Midi Through Port-0 14:0
3-Digital Keyboard:Digital Keyboard MIDI 1 20:0

Seleziona il numero corrispondente al dispositivo di interesse:1

start time=0
control_change channel=3 control=120 value=0 time=0
control_change channel=7 control=120 value=0 time=0
control_change channel=5 control=120 value=0 time=0
control_change channel=3 control=7 value=122 time=0
note_on channel=3 note=67 velocity=40 time=0
note_on channel=3 note=48 velocity=39 time=0
note_on channel=3 note=69 velocity=48 time=0
note_off channel=3 note=67 velocity=0 time=0
note_on channel=3 note=59 velocity=45 time=0
note_off channel=3 note=59 velocity=0 time=0
note_on channel=3 note=55 velocity=42 time=0
note_off channel=3 note=69 velocity=0 time=0
note_off channel=3 note=48 velocity=0 time=0
note_on channel=3 note=67 velocity=33 time=0
note_off channel=3 note=67 velocity=0 time=0
note_off channel=3 note=55 velocity=0 time=0
note_on channel=3 note=65 velocity=34 time=0
note_on channel=3 note=53 velocity=39 time=0
note_on channel=3 note=63 velocity=35 time=0
note_off channel=3 note=65 velocity=0 time=0
note_on channel=3 note=52 velocity=50 time=0
note_off channel=3 note=53 velocity=0 time=0
note_off channel=3 note=63 velocity=0 time=0
note_on channel=3 note=62 velocity=42 time=0
note_off channel=3 note=52 velocity=0 time=0
note_off channel=3 note=62 velocity=0 time=0
note_on channel=3 note=53 velocity=41 time=0
note_on channel=3 note=64 velocity=49 time=0

Semplice Sinth MIDI

MidiSinthDeviceService.java

/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * 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.example.android.midisynth;

import android.media.midi.MidiDeviceService;
import android.media.midi.MidiDeviceStatus;
import android.media.midi.MidiReceiver;

import com.example.android.common.midi.synth.SynthEngine;

public class MidiSynthDeviceService extends MidiDeviceService {

    private SynthEngine mSynthEngine = new SynthEngine();
    private boolean mSynthStarted = false;

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public void onDestroy() {
        mSynthEngine.stop();
        super.onDestroy();
    }

    @Override
    public MidiReceiver[] onGetInputPortReceivers() {
        return new MidiReceiver[]{mSynthEngine};
    }

    /**
     * This will get called when clients connect or disconnect.
     */
    @Override
    public void onDeviceStatusChanged(MidiDeviceStatus status) {
        if (status.isInputPortOpen(0) && !mSynthStarted) {
            mSynthEngine.start();
            mSynthStarted = true;
        } else if (!status.isInputPortOpen(0) && mSynthStarted) {
            mSynthEngine.stop();
            mSynthStarted = false;
        }
    }

}

MainActivity.java

/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * 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.example.android.midisynth;

import android.content.pm.PackageManager;
import android.media.midi.MidiDevice.MidiConnection;
import android.media.midi.MidiDeviceInfo;
import android.media.midi.MidiManager;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.WindowManager;
import android.widget.Toast;

import com.example.android.common.midi.MidiOutputPortConnectionSelector;
import com.example.android.common.midi.MidiPortConnector;
import com.example.android.common.midi.MidiTools;

/**
 * Simple synthesizer as a MIDI Device.
 */
public class MainActivity extends AppCompatActivity {

    private MidiOutputPortConnectionSelector mPortSelector;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.setDisplayShowTitleEnabled(false);
        }

        if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI)) {
            setupMidi();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        setKeepScreenOn(menu.findItem(R.id.action_keep_screen_on).isChecked());
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_keep_screen_on:
                boolean checked = !item.isChecked();
                setKeepScreenOn(checked);
                item.setChecked(checked);
                break;
        }
        return super.onOptionsItemSelected(item);
    }

    private void setKeepScreenOn(boolean keepScreenOn) {
        if (keepScreenOn) {
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        } else {
            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        }
    }

    private void setupMidi() {
        // Setup MIDI
        MidiManager midiManager = (MidiManager) getSystemService(MIDI_SERVICE);

        MidiDeviceInfo synthInfo = MidiTools.findDevice(midiManager, "AndroidTest",
                "SynthExample");
        int portIndex = 0;
        mPortSelector = new MidiOutputPortConnectionSelector(midiManager, this,
                R.id.spinner_synth_sender, synthInfo, portIndex);
        mPortSelector.setConnectedListener(new MyPortsConnectedListener());
    }

    private void closeSynthResources() {
        if (mPortSelector != null) {
            mPortSelector.close();
        }
    }

    // TODO A better way would be to listen to the synth server
    // for open/close events and then disable/enable the spinner.
    private class MyPortsConnectedListener
            implements MidiPortConnector.OnPortsConnectedListener {
        @Override
        public void onPortsConnected(final MidiConnection connection) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if (connection == null) {
                        Toast.makeText(MainActivity.this,
                                R.string.error_port_busy, Toast.LENGTH_SHORT)
                                .show();
                        mPortSelector.clearSelection();
                    } else {
                        Toast.makeText(MainActivity.this,
                                R.string.port_open_ok, Toast.LENGTH_SHORT)
                                .show();
                    }
                }
            });
        }
    }

    @Override
    public void onDestroy() {
        closeSynthResources();
        super.onDestroy();
    }

}

profMI

# profMI.py
#
# 
# Il professor MII insegna in una classe universitaria formata da
# ragazzi e ragazze. Viene fornita una lista contenente una lista 
# per ogni studente. Il primo numero della lista è l'idendificativo
# dello studente, il secondo numero della lista rappresenta il sesso;
# (0=MASCHIO,1=FEMMINA,2=LGBT). I restanti numeri indicano i voti
# conseguiti per quello studente.
# Il programma determina la media dei voti per genere sessuale.
#
# by Andrea Bianchini (2021)

from random import randint

N = 50
MIN = 18
MAX = 31
NVOTI = 5

#generazione casuale lista dei voti:
cl=[]
for i in range(N):
    student=[]
    student.append(i)
    student.append(randint(0,2))
    for j in range(NVOTI):
        student.append(randint(MIN,MAX))
    cl.append(student)
                   
#calcolo
mediatot=[0.0,0.0,0.0]
ng=[0,0,0]
for i in range(N):
    medias=[0.0,0.0,0.0]
    student=cl[i]
    sex = student[1]
    ng[sex]+=1
    for j in range(NVOTI):
        medias[sex]+=float(student[2+j])
    medias[sex]/=float(NVOTI)
    mediatot[sex]+=medias[sex]

mediatot[0]/=float(ng[0])
mediatot[1]/=float(ng[1])
mediatot[2]/=float(ng[2])

print("Lista studenti = ", cl)
print()
print("Media voti maschi = %.2f" %mediatot[0])
print("Media voti femmine = %.2f" %mediatot[1])
print("Media voti LGBT = %.2f" %mediatot[2])

Esempio:

Lista studenti =  [[0, 0, 23, 23, 22, 24, 28], [1, 0, 22, 18, 18, 24, 28], [2, 0, 30, 25, 28, 21, 25], [3, 1, 23, 18, 23, 24, 30], [4, 0, 23, 19, 23, 25, 30], [5, 0, 19, 24, 30, 29, 26], [6, 1, 19, 21, 21, 20, 22], [7, 1, 27, 30, 18, 26, 20], [8, 1, 30, 24, 29, 21, 23], [9, 2, 31, 19, 27, 30, 25], [10, 2, 31, 27, 21, 31, 22], [11, 1, 19, 25, 19, 31, 20], [12, 2, 29, 24, 24, 26, 29], [13, 0, 26, 23, 25, 26, 29], [14, 0, 25, 29, 23, 21, 29], [15, 0, 19, 28, 22, 20, 29], [16, 1, 28, 21, 24, 22, 18], [17, 2, 19, 22, 27, 25, 22], [18, 1, 31, 22, 18, 27, 20], [19, 2, 21, 25, 25, 19, 23], [20, 2, 27, 23, 30, 25, 21], [21, 1, 26, 29, 23, 30, 30], [22, 1, 29, 22, 18, 30, 26], [23, 0, 23, 30, 28, 20, 19], [24, 1, 27, 29, 28, 19, 29], [25, 0, 25, 27, 22, 24, 31], [26, 1, 30, 26, 28, 26, 28], [27, 0, 18, 22, 30, 27, 26], [28, 1, 27, 18, 25, 24, 18], [29, 0, 31, 23, 24, 21, 30], [30, 2, 30, 28, 19, 24, 25], [31, 2, 23, 22, 23, 22, 19], [32, 2, 29, 31, 30, 25, 29], [33, 1, 30, 21, 29, 20, 23], [34, 1, 21, 26, 27, 23, 18], [35, 1, 29, 25, 20, 29, 25], [36, 2, 18, 21, 20, 22, 31], [37, 1, 30, 20, 19, 26, 20], [38, 0, 26, 19, 22, 22, 19], [39, 0, 31, 27, 19, 29, 18], [40, 2, 26, 26, 23, 24, 21], [41, 2, 28, 26, 23, 22, 25], [42, 2, 29, 27, 29, 25, 24], [43, 1, 29, 21, 18, 31, 29], [44, 1, 24, 22, 20, 31, 21], [45, 1, 20, 21, 30, 28, 23], [46, 0, 26, 24, 29, 26, 23], [47, 1, 22, 26, 26, 31, 26], [48, 2, 18, 23, 25, 23, 21], [49, 0, 18, 22, 26, 23, 23]]

Media voti maschi = 24.43
Media voti femmine = 24.39
Media voti LGBT = 24.70
>>> 

Coppie di numeri a differenza costante

# kdiff.py
#
# 
# Questo programma risolve il seguente problema :
# Dato un insieme s di N numeri interi trovare
# tutte le coppie di interi la cui differenza è pari a K
#
# by Andrea Bianchini (2021)

from random import randint

N = 50
MIN = 1
MAX = 1000
K = randint(MIN,MAX/2)

s = [randint(MIN,MAX) for _ in range(N)]


def f(x,y):
    global K
    if abs(x-y)==K:
        return True
    else:
        return False
    
res =[]

for x in range(N-1):
    for y in range(x+1,N):
        if f(s[x],s[y]):
            res.append((s[x],s[y]))

print("s =",s)
print()
print("K = %d" %K)
print("coppie =",res)

Esempio 1:

s = [240, 662, 961, 108, 802, 232, 954, 99, 542, 775, 668, 988, 637, 96, 135, 549, 111, 678, 86, 596, 912, 13, 191, 516, 118, 88, 837, 632, 870, 843, 542, 569, 819, 579, 411, 154, 743, 89, 95, 686, 604, 503, 511, 859, 305, 671, 161, 510, 164, 906]

K = 10
coppie = [(108, 118), (99, 89), (668, 678), (96, 86), (569, 579), (154, 164)]
>>> 

Esempio 2:

s = [327, 847, 660, 722, 431, 287, 79, 542, 354, 514, 703, 522, 764, 75, 904, 789, 103, 801, 929, 884, 964, 818, 992, 458, 369, 900, 239, 671, 120, 904, 421, 342, 403, 314, 495, 794, 119, 140, 810, 237, 333, 639, 676, 705, 134, 802, 528, 20, 452, 2]

K = 105
coppie = [(239, 134), (342, 237), (810, 705)]
>>> 

A minimal App in Android

In questo post vi mostro la struttura minimale di una App Android. In realtà potrebbe essere resa ancora più semplice, ma non chiarirebbe bene quali sono le parti che costituiscono l’App.

Iniziamo con il file AndroidManifest.xml (directory app/manifests) :

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.andreabianchini.simpleandroidapp">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.SimpleAndroidApp">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Passiamo al file che contiene il programma principale dell’App, MainActivity.java (directory app/java) :

package com.andreabianchini.simpleandroidapp;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

Al programma (Activity) principale sopra riportato viene associato un file di risorse, activity_main.xml, (directory app/res/layout), che serve a definire l’aspetto ed i contenuti grafici della schermata associata all’attività principale :

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

In questo caso la nostra App Android minimale visualizzerà una schermata con la scritta : ‘Hello World!’.

Con l’ambiente di sviluppo ‘Android Studio’ potete generare automaticamente questa applicazione in un minuto.

Ecco il risultato:

App Android minimale

Catch the note

In questo articolo rendo pubblico, a titolo di esempio, il codice java principale della mia app CatchTheNote, disponibile in versione completa alla voce di menù Android.

package com.andreabianchini.catchthenote;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Bundle;
import android.os.Handler;
import android.text.InputFilter;
import android.text.Spanned;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdView;
import com.google.android.gms.ads.MobileAds;

import java.util.Random;

public class MainActivity extends AppCompatActivity {
    private SoundPool soundPool;
    private int soundID,tone;
    private int a,as,b,c,cs,d,ds,e,f,fs,g,gs;
    boolean plays = false, loaded = false;
    float actVolume, maxVolume, volume;
    AudioManager audioManager;
    int counter;
    int [] notes=new int[8];
    int [] notesId=new int[8];
    int nnotes=1;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // AudioManager audio settings for adjusting the volume
        audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
        actVolume = (float) audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
        maxVolume = (float) audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
        volume = actVolume / maxVolume;

        //Hardware buttons setting to adjust the media sound
        this.setVolumeControlStream(AudioManager.STREAM_MUSIC);

        // the counter will help us recognize the stream id of the sound played  now
        counter = 0;

        // Load the sounds
        soundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
        soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
            @Override
            public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
                loaded = true;
                plays=false;
            }
        });

        a = soundPool.load(this, R.raw.a, 1);
        as = soundPool.load(this, R.raw.as, 1);
        b = soundPool.load(this, R.raw.b, 1);
        c = soundPool.load(this, R.raw.c, 1);
        cs = soundPool.load(this, R.raw.cs, 1);
        d = soundPool.load(this, R.raw.d, 1);
        ds = soundPool.load(this, R.raw.ds, 1);
        e = soundPool.load(this, R.raw.e, 1);
        f = soundPool.load(this, R.raw.f, 1);
        fs = soundPool.load(this, R.raw.fs, 1);
        g = soundPool.load(this, R.raw.g, 1);
        gs = soundPool.load(this, R.raw.gs, 1);

        soundID = a;
        nnotes=1;
        notes[0]=0;
        notesId[0]=a;

        Button button =  findViewById(R.id.btPlay);
        Button button1 =  findViewById(R.id.btA);
        Button btChange =  findViewById(R.id.btChange);
        Button btShow =  findViewById(R.id.btShow);
        Button btInfo =  findViewById(R.id.btInfo);
        EditText etNNotes = findViewById(R.id.etNNotes);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                playSound(v);
           }
        });

        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                playA(v);
            }
        });

        btChange.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                changeNote(v);
            }
        });

        btShow.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showNote(v);
            }
        });

        btInfo.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showInfo(v);
            }
        });

        etNNotes.setFilters(new InputFilter[]{ new InputFilterMinMax("1", "8")});

        // Initialize the Mobile Ads SDK
        MobileAds.initialize(this, getString(R.string.admob_app_id));

        AdView mBannerAd;

        mBannerAd = findViewById(R.id.adView);

        AdRequest adRequest = new AdRequest.Builder()
                .build();
        mBannerAd.loadAd(adRequest);

    }

    public void showInfo(View v) {
        Intent intent = new Intent(MainActivity.this, Info.class);
        startActivity(intent);

    }

    public void showNote(View v) {
        TextView tv  =  findViewById(R.id.tvNote);
        EditText etNNotes = findViewById(R.id.etNNotes);
        nnotes = Integer.parseInt(etNNotes.getText().toString());
        String s;
        s="";
        for(int i=0;i<nnotes;i++) {
            switch (notes[i]) {
                case 0:
                    s+="A ";
                    break;
                case 1:
                    s+="A# ";
                    break;
                case 2:
                    s+="B ";
                    break;
                case 3:
                    s+="C ";
                    break;
                case 4:
                    s+="C# ";
                    break;
                case 5:
                    s+="D ";
                    break;
                case 6:
                    s+="D# ";
                    break;
                case 7:
                    s+="E ";
                    break;
                case 8:
                    s+="F ";
                    break;
                case 9:
                    s+="F# ";
                    break;
                case 10:
                    s+="G ";
                    break;
                case 11:
                    s+="G# ";
                    break;

            }
        }
        tv.setText(s);
    }

    public void changeNote(View v) {
        EditText etNNotes = findViewById(R.id.etNNotes);
        nnotes = Integer.parseInt(etNNotes.getText().toString());
        int last,last1;
        last1=2;
        last=1;
        for(int i=0;i<nnotes;i++) {
            tone=0;
            if (i>1)
            while(tone==last || (Math.abs(tone-last)==1 && Math.abs(last1-last)==1) || (Math.abs(tone-last)==3 && Math.abs(last1-last)==3) || (Math.abs(tone-last)==2 && Math.abs(last1-last)==3) || (Math.abs(tone-last)==3 && Math.abs(last1-last)==2)) {
                tone = new Random().nextInt(12);
            }
            else
                tone = new Random().nextInt(12);
            last1 = last;
            last = tone;
            notes[i]=tone;
            switch (tone) {
                case 0:
                    soundID = a;
                    break;
                case 1:
                    soundID = as;
                    break;
                case 2:
                    soundID = b;
                    break;
                case 3:
                    soundID = c;
                    break;
                case 4:
                    soundID = cs;
                    break;
                case 5:
                    soundID = d;
                    break;
                case 6:
                    soundID = ds;
                    break;
                case 7:
                    soundID = e;
                    break;
                case 8:
                    soundID = f;
                    break;
                case 9:
                    soundID = fs;
                    break;
                case 10:
                    soundID = g;
                    break;
                case 11:
                    soundID = gs;
                    break;

            }
            notesId[i]=soundID;
        }
    }

    public void playSound(View v) {
        // Is the sound loaded does it already play?
        TextView tv  =  findViewById(R.id.tvNote);
        tv.setText(getString(R.string.note));

        for (int i=0;i<nnotes;i++){
        if (loaded && !plays) {
            soundPool.play(notesId[i], 1, 1, 0, 0, 1);
            counter = counter++;
            //Toast.makeText(this, "Played sound", Toast.LENGTH_SHORT).show();
            //plays = true;
        }
            try { Thread.sleep(1600); }
            catch (InterruptedException ex) { android.util.Log.d("Catch the Note", ex.toString()); }        }
    }

    public void playA(View v) {
        // Is the sound loaded does it already play?
        TextView tv  =  findViewById(R.id.tvNote);
        tv.setText(getString(R.string.note));

            if (loaded && !plays) {
                soundPool.play(a, 1, 1, 0, 0, 1);
                counter = counter++;
                //Toast.makeText(this, "Played sound", Toast.LENGTH_SHORT).show();
                //plays = true;
            }
            try { Thread.sleep(1600); }
            catch (InterruptedException ex) { android.util.Log.d("Catch the Note", ex.toString()); }
    }

    public void playLoop(View v) {
        // Is the sound loaded does it already play?
        if (loaded && !plays) {

            // the sound will play for ever if we put the loop parameter -1
            soundPool.play(soundID, volume, volume, 1, -1, 1f);
            counter = counter++;
            Toast.makeText(this, "Plays loop", Toast.LENGTH_SHORT).show();
            plays = true;
        }
    }

    public void pauseSound(View v) {
        if (plays) {
            soundPool.pause(soundID);
//            soundID = soundPool.load(this, R.raw.beep, counter);
            Toast.makeText(this, "Pause sound", Toast.LENGTH_SHORT).show();
            plays = false;
        }
    }

    public void stopSound(View v) {
        if (plays) {
            soundPool.stop(soundID);
//            soundID = soundPool.load(this, R.raw.beep, counter);
            Toast.makeText(this, "Stop sound", Toast.LENGTH_SHORT).show();
            plays = false;
        }
    }

    public class InputFilterMinMax implements InputFilter {

        private int min, max;

        public InputFilterMinMax(int min, int max) {
            this.min = min;
            this.max = max;
        }

        public InputFilterMinMax(String min, String max) {
            this.min = Integer.parseInt(min);
            this.max = Integer.parseInt(max);
        }

        @Override
        public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
            try {
                int input = Integer.parseInt(dest.toString() + source.toString());
                if (isInRange(min, max, input))
                    return null;
            } catch (NumberFormatException nfe) { }
            return "";
        }

        private boolean isInRange(int a, int b, int c) {
            return b > a ? c >= a && c <= b : c >= b && c <= a;
        }
    }
    }