package at.tugraz.ist.musicdroid; import java.io.File; import java.io.IOException; import java.text.DecimalFormat; import java.util.ArrayList; import org.puredata.android.service.PdService; import org.puredata.android.utils.PdUiDispatcher; import org.puredata.core.PdBase; import org.puredata.core.PdListener; import org.puredata.core.utils.IoUtils; import org.puredata.core.utils.PdDispatcher; import android.app.Activity; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.content.res.Resources; import android.media.AudioManager; import android.media.MediaPlayer; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.Button; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import at.tugraz.ist.musicdroid.common.Constants; public class PitchDetectionActivity extends Activity { private final static String Appname = "Pitchdetection"; private File dir; private PdService pdService = null; private String path; private int patchID = 0; private Handler myProgressHandler = new Handler(); private String input_wav; private DrawTonesView toneView; ArrayList<Integer> values; private final ServiceConnection pdConnection = new ServiceConnection() { public void onServiceConnected(ComponentName name, IBinder service) { pdService = ((PdService.PdBinder)service).getService(); try { initPd(); loadPatch(); doAnalyze(); } catch (IOException e) { Log.e(Appname, e.toString()); finish(); } } public void onServiceDisconnected(ComponentName name) { } }; /* We'll use this to catch print statements from Pd when the user has a [print] object */ private final PdDispatcher myDispatcher = new PdUiDispatcher() { @Override public void print(String s) { Log.i("Pd print", s); } }; /* We'll use this to listen out for messages from Pd. Later we'll hook this up to a named receiver. */ private final PdListener myListener = new PdListener() { public void receiveMessage(String source, String symbol, Object... args) { Log.i("receiveMessage symbol:", symbol); for (Object arg: args) { Log.i("receiveMessage atom:", arg.toString()); } } /* What to do when we receive a list from Pd. In this example we're collecting the list from Pd and outputting each atom */ public void receiveList(String source, Object... args) { for (Object arg: args) { Log.i("receiveList atom:", arg.toString()); } } /* When we receive a symbol from Pd */ public void receiveSymbol(String source, String symbol) { Log.i("receiveSymbol", symbol); } /* When we receive a float from Pd */ public void receiveFloat(String source, float x) { Log.i("receiveFloat", ((Float)x).toString()); if(x < 0) { printResults(); return; } values.add( (int)x); } /* When we receive a bang from Pd */ public void receiveBang(String source) { Log.i("receiveBang", "bang!"); } }; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.pitchdetection); values = new ArrayList<Integer>(); Bundle b = getIntent().getExtras(); path = b.getString("path"); File inputFile = new File(path); if(!inputFile.exists()) { Toast.makeText(this, "Sound-file not found!", Toast.LENGTH_LONG); Log.e("Pitchdet","Sound-file not found!"); return; } input_wav = inputFile.getAbsolutePath(); calculateWavLength(); Resources r = getResources(); int radius = r.getInteger(R.integer.radius); int topline = r.getInteger(R.integer.topmarginlines); LinearLayout layout = (LinearLayout)findViewById(R.id.parentLayout); toneView = new DrawTonesView(this, R.drawable.violine, radius , topline, false); toneView.clearList(); toneView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,300)); layout.addView(toneView,0); bindService(new Intent(this, PdService.class),pdConnection,BIND_AUTO_CREATE); } private void calculateWavLength() { MediaPlayer mp = MediaPlayer.create(this, Uri.parse(input_wav)); int duration_msec = mp.getDuration(); int duration_sec = duration_msec / 1000; mp.release(); TextView t = (TextView)findViewById(R.id.progressText); DecimalFormat df = new DecimalFormat ( "00" ); if(duration_sec < 60) t.setText("00:" + df.format(duration_sec)); else { int temp = duration_sec; int min = 0; while(temp > 60) { min++; temp = temp - 60; } t.setText(df.format(min) + ":" + df.format(temp)); } ProgressBar p = (ProgressBar)findViewById(R.id.progressBar); p.setMax(duration_msec/100); p.setProgress(0); } public void doAnalyze() { try { ProgressBar p = (ProgressBar)findViewById(R.id.progressBar); p.setProgress(0); toneView.clearList(); toneView.invalidate(); values.clear(); TextView t = (TextView)findViewById(R.id.outTextView); t.setText(""); Button b = (Button)findViewById(R.id.synthesizeButton); b.setEnabled(false); File f = new File(input_wav); if(!f.exists()) { Toast.makeText(this, "Sound-file not found!", Toast.LENGTH_LONG); Log.e("Pitchdet","Sound-file not found!"); return; } int ret = PdBase.sendSymbol("input-wav", input_wav); if(ret != 0) Log.i("PitchDet", "PdBase.sendSymbol() returns " + Integer.toString(ret)); myProgressHandler.removeCallbacks(myHandlerTask); myProgressHandler.postDelayed(myHandlerTask, 100); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); Log.e("pitchdet", e.getMessage()); } } private void printResults() { myProgressHandler.removeCallbacks(myHandlerTask); ProgressBar p = (ProgressBar)findViewById(R.id.progressBar); p.setProgress(p.getMax()); String out = ""; MidiTable midi = new MidiTable(); for(int i=0;i< values.size();i++) { out += /*values.get(i).toString() + " -> " +*/ (i+1) + ": \t" + midi.midiToName(values.get(i)) + "\n"; } TextView t = (TextView)findViewById(R.id.outTextView); t.setText(out); doDraw(); if(values.size() > 0){ Button b = (Button)findViewById(R.id.synthesizeButton); b.setEnabled(true); } } private void writeMidiFile(int instrument) { if(instrument <= 0) return; MidiFile mf = new MidiFile(); try { mf.progChange(instrument); //select instrument for(int i=0;i< values.size();i++) { mf.noteOnOffNow(MidiFile.QUAVER, values.get(i), 127); } File f = new File(path); File syntFile = new File(Constants.MAIN_DIRECTORY + Constants.RECORDS_SUB_DIRECTORY, "synt.mid"); String filename = syntFile.getAbsolutePath(); mf.writeToFile(filename); if(!((new File(filename)).exists())) throw new Exception("Midi file could not be created!"); playfile(filename); } catch (Exception e) { Log.e("Midi", e.getMessage()); } } public void onMidiClick(View view) { if(values.size() <= 0) return; registerForContextMenu(view); openContextMenu(view); unregisterForContextMenu(view); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); MenuInflater inflater = getMenuInflater(); inflater.inflate(R.layout.context_menu_instruments, menu); } @Override public boolean onContextItemSelected(MenuItem item) { AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); switch (item.getItemId()) { case R.id.instrument_piano: writeMidiFile(1); return true; case R.id.instrument_guitar: writeMidiFile(25); return true; case R.id.instrument_violin: writeMidiFile(41); return true; case R.id.instrument_panflute: writeMidiFile(76); return true; case R.id.instrument_accordion: writeMidiFile(22); return true; case R.id.instrument_sax: writeMidiFile(66); return true; case R.id.instrument_trumpet: writeMidiFile(57); return true; case R.id.instrument_xylophone: writeMidiFile(14); return true; default: return super.onContextItemSelected(item); } } public void playfile(String filename) { File f = new File(filename); if(!f.exists()) return; Uri myUri = Uri.fromFile(f); MediaPlayer mediaPlayer = new MediaPlayer(); try { mediaPlayer.reset(); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.setDataSource(getApplicationContext(), myUri); mediaPlayer.prepare(); mediaPlayer.start(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); Log.e("playfile()", e.getMessage()); } } private void loadPatch() throws IOException { dir = getFilesDir(); IoUtils.extractZipResource(getResources().openRawResource(R.raw.pitchdet), dir, true); File patchFile = new File(dir, "pitchdet.pd"); patchID = PdBase.openPatch(patchFile.getAbsolutePath()); } private void initPd() throws IOException { String name = getResources().getString(R.string.app_name); pdService.initAudio(-1, 0, -1, -1); pdService.startAudio(); PdBase.setReceiver(myDispatcher); myDispatcher.addListener("pitch-midi", myListener); } @Override public void onDestroy() { PdBase.closePatch(patchID); unbindService(pdConnection); super.onDestroy(); } public void doDraw() { toneView.clearList(); for(int i=0;i< values.size();i++) { toneView.addElement(values.get(i)); } } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.layout.menu, menu); menu.getItem(1).setVisible(false); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menuAnalyze: doAnalyze(); break; } return true; } private Runnable myHandlerTask = new Runnable() { public void run() { ProgressBar p = (ProgressBar)findViewById(R.id.progressBar); if(p.getProgress() < p.getMax() - 1) { p.incrementProgressBy(1); myProgressHandler.postDelayed(myHandlerTask, 100); } } }; }