0

I'm working on a project, where I need to show the pitches of the words (from the song) in a GraphView. I wrote a program that would get the pitches from a song and create a .txt file from it.

Then I wrote a class, that reads the file and creates a list from it. So in the end I would have a list that consists of words and word contains pitches. In the MakePitchesList you can see what the pitches output from a song looks like. I have 0,14:23281,61 on every line. The first part of the line is timeOccurance meaning, when this pitch was heard and the second part is the pitch itself. So in this example the timeOccurance would be 0,14 and pitch at that given time 23281,61.

Here are the three classes that make a wordsList out of a pitch .txt file.

public class Pitch{

    float occuranceTime;
    float pitch;


    public void setOccuranceTime(float occuranceTime) {
        this.occuranceTime = occuranceTime;
    }

    public float getOccuranceTime() {
        return occuranceTime;
    }

    public void setPitch(float pitch) {
        this.pitch = pitch;
    }

    public float getPitch() {
        return pitch;
    }
}

public class MakePitchesList {


    String[] pitches;
    List<Pitch> listOfPitches = new ArrayList<Pitch>();

    public List<Pitch> getListOfPitches(){
        getPitches();
        for (String pitchString: pitches) {
            Pitch pitch = new Pitch();
            makeListOfPitches(pitch, pitchString);
        }
        return listOfPitches;
    }

    public void makeListOfPitches(Pitch pitch, String pitchString){
        pitch.setPitch(getPitchesInfo(pitchString, 1));
        pitch.setOccuranceTime(getPitchesInfo(pitchString, 0));
        listOfPitches.add(pitch);
    }


    public String[] getPitches() {
        pitches = pitchesRaw.split("\\r?\\n");
        return pitches;
    }

    private float getPitchesInfo(String pitch, int position){
        String[] frequencyAndTime = pitch.split("\\:");
        if(position == 0){
            return Float.parseFloat(frequencyAndTime[0].replace(',', '.'));
        }
        if(position == 1){
            return Float.parseFloat(frequencyAndTime[1].replace(',', '.'));
        }
        else return 0;
    }

    String pitchesRaw =
            "0,14:23281,61\n" +
            "0,23:53,65\n" +
            "0,37:72,53\n" +
            "0,56:86,09\n" +
            "0,60:88,58\n" +
            "0,65:87,45\n" +
            "0,70:87,11\n" +
            "0,74:89,56\n" +
            "0,79:96,22\n" +
            "0,84:23288,24\n" +
            "0,88:103,92\n" +
            "0,93:107,46\n" +
            "0,98:108,02\n" +
            "1,02:107,51\n" +
            "1,07:104,92\n" +
            "1,11:105,94\n" +
            "1,16:106,40\n" +
            "1,21:104,43\n" +
            "1,25:104,93\n" +
            "1,30:108,01\n" +
            "1,35:316,81\n" +
            "1,39:103,98\n" +
            "1,44:23297,42\n" +
            "1,49:23357,42\n" +
            "1,53:23359,74\n" +
            "1,58:23393,04\n" +
            "1,63:23244,18\n" +
            "1,67:23220,51\n" +
            "1,72:23250,06\n" +
            "1,76:23288,84\n" +
            "1,81:23241,81\n" +
            "1,86:23295,22\n" +
            "1,90:23268,04\n" +
            "1,95:23252,78\n" +
            "2,00:23224,22\n" +
            "2,04:23429,71\n" +
            "2,09:23214,58\n" +
            "2,14:23240,70\n" +
            "2,18:23237,71\n" +
            "2,23:23231,22\n" +
            "2,28:23222,77\n" +
            "2,32:23239,73\n" +
            "2,37:23235,98\n" +
            "2,41:23222,16\n" +
            "2,46:23224,01\n" +
            "2,51:23214,26\n" +
            "2,55:23223,20\n" +
            "2,60:23234,11\n" +
            "2,65:23221,65\n" +
            "2,69:23213,45\n" +
            "2,74:23217,44\n" +
            "2,79:23235,93\n" +
            "2,83:11122,79\n" +
            "2,88:23234,58\n" +
            "2,93:23229,52\n" +
            "2,97:23255,48\n" +
            "3,02:23254,44\n" +
            "3,07:23355,41\n" +
            "3,44:105,48\n" +
            "3,48:115,45\n" +
            "3,53:117,78\n" +
            "3,58:127,36\n" +
            "3,62:131,24\n" +
            "3,67:130,33\n" +
            "3,72:131,93\n" +
            "3,76:127,32\n" +
            "3,81:117,18\n" +
            "3,85:117,80\n" +
            "3,90:117,15\n" +
            "3,95:121,04\n" +
            "3,99:131,22\n" +
            "4,04:130,38\n" +
            "4,09:130,34\n" +
            "4,13:129,57\n" +
            "4,18:120,38\n" +
            "4,23:121,06\n" +
            "4,32:100,12\n" +
            "4,37:23483,16\n" +
            "4,41:112,95\n" +
            "4,46:23448,04\n" +
            "4,50:23396,09\n" +
            "4,55:23292,90\n" +
            "4,60:117,21\n" +
            "4,64:116,58\n" +
            "4,69:116,62\n" +
            "4,74:119,18\n" +
            "4,78:131,19\n" +
            "4,83:130,34\n" +
            "4,88:129,59\n" +
            "4,92:132,64\n" +
            "4,97:129,68\n" +
            "5,02:132,71\n" +
            "5,06:133,57\n" +
            "5,11:128,94\n" +
            "5,15:131,09\n" +
            "5,20:132,75\n" +
            "5,25:129,68\n" +
            "5,29:131,26\n" +
            "5,34:131,22\n" +
            "5,39:130,38\n" +
            "5,43:146,01\n" +
            "5,48:140,43\n" +
            "5,57:23450,16\n" +
            "5,62:130,46\n" +
            "5,67:132,02\n" +
            "5,71:23243,22\n" +
            "5,76:23456,28\n" +
            "5,85:23246,64\n" +
            "5,90:23274,97\n" +
            "5,94:23310,30\n" +
            "5,99:23229,71\n" +
            "6,08:23214,33\n" +
            "6,13:23221,53\n" +
            "6,18:23263,48\n" +
            "6,22:23213,17\n" +
            "6,27:23235,04\n" +
            "6,32:23222,02\n" +
            "6,36:23214,90\n" +
            "6,41:23230,05\n" +
            "6,46:23212,55\n" +
            "6,50:23221,33\n" +
            "6,55:23226,70\n" +
            "6,59:23217,07\n" +
            "6,64:23272,07\n" +
            "6,69:11102,74\n" +
            "6,73:23263,38\n" +
            "6,78:23217,53\n" +
            "6,97:23243,63\n" +
            "7,11:23214,11\n" +
            "7,15:23229,58\n" +
            "7,20:23225,70\n" +
            "7,24:23244,82\n" +
            "7,29:23243,09\n" +
            "7,34:23249,66\n" +
            "7,38:23226,67\n" +
            "7,43:23246,31\n" +
            "7,48:23258,55\n" +
            "7,52:23230,34\n" +
            "7,57:23225,60\n" +
            "7,62:23280,25\n" +
            "7,66:23238,08\n" +
            "7,71:23221,47\n" +
            "7,85:117,87\n" +
            "7,89:117,19\n" +
            "7,94:117,21\n" +
            "7,99:117,21\n" +
            "8,03:116,57\n" +
            "8,08:119,10\n" +
            "8,13:44,01\n" +
            "8,17:129,52\n" +
            "8,22:132,72\n" +
            "8,27:143,19\n" +
            "8,31:141,13\n" +
            "8,36:139,35\n" +
            "8,45:132,82\n" +
            "8,50:129,76\n" +
            "8,54:130,43\n" +
            "8,68:94,20\n" +
            "8,78:132,70\n" +
            "8,82:130,43\n" +
            "8,87:129,60\n" +
            "8,92:130,56\n" +
            "8,96:128,92\n" +
            "9,01:119,19\n" +
            "9,06:118,45\n" +
            "9,10:103,41\n" +
            "9,15:103,41\n" +
            "9,20:103,89\n" +
            "9,24:106,46\n" +
            "9,29:214,93\n" +
            "9,33:23427,95\n" +
            "9,38:23356,01\n" +
            "9,43:106,41\n" +
            "9,47:100,57\n" +
            "9,52:106,39\n" +
            "9,57:104,40\n" +
            "9,61:99,70\n" +
            "9,66:106,42\n" +
            "9,71:103,50\n" +
            "9,75:104,47\n" +
            "9,80:106,97\n" +
            "9,85:99,68\n" +
            "9,89:23454,22\n" +
            "9,94:23299,56\n" +
            "9,98:23275,30\n" +
            "10,03:23222,72\n" +
            "10,08:23246,09\n" +
            "10,12:23221,14\n" +
            "10,17:23240,54\n" +
            "10,22:23246,81\n" +
            "10,26:23224,74\n" +
            "10,31:23249,41\n" +
            "10,36:23214,79\n" +
            "10,40:23213,46\n" +
            "10,45:23259,51\n" +
            "10,50:23217,39\n" +
            "10,54:23215,36\n" +
            "10,59:23224,87\n" +
            "10,63:23242,27\n" +
            "10,68:23270,82\n" +
            "10,73:23243,19\n" +
            "10,77:23222,75\n" +
            "10,82:23268,78\n" +
            "10,87:23321,62\n" +
            "10,91:23259,65\n" +
            "11,05:23226,24\n" +
            "11,10:23222,92\n" +
            "11,15:23218,83\n" +
            "11,19:23211,71\n" +
            "11,24:11112,28\n" +
            "11,28:23261,03\n" +
            "11,33:23265,31\n" +
            "11,38:23245,92\n" +
            "11,42:57,09\n" +
            "11,61:103,45\n" +
            "11,66:103,91\n" +
            "11,70:102,02\n" +
            "11,75:107,96\n" +
            "11,80:105,43\n" +
            "11,84:104,46\n" +
            "11,89:116,64\n" +
            "11,94:115,99\n" +
            "11,98:114,77\n" +
            "12,03:121,72\n" +
            "12,07:123,16\n" +
            "12,12:125,12\n" +
            "12,17:128,85\n" +
            "12,21:120,37\n" +
            "12,26:116,52\n" +
            "12,31:130,55\n" +
            "12,35:131,06\n" +
            "12,40:131,89\n" +
            "12,45:128,88\n" +
            "12,49:23397,75\n" +
            "12,59:118,45\n" +
            "12,63:116,54\n" +
            "12,68:119,70\n" +
            "12,72:115,45\n" +
            "12,77:115,30\n" +
            "12,82:119,86\n" +
            "12,86:116,59\n" +
            "12,91:114,13\n" +
            "12,96:119,04\n" +
            "13,00:118,47\n" +
            "13,05:115,38\n" +
            "13,10:128,92\n";
}

public class MakeWordsList {

    List<Pitch> pitches;

    public List<List<Pitch>> getWordsList(List<Pitch> pitchList) {
        return makeWordsList(pitchList);
    }

    List<Pitch> oneWord = new ArrayList<>();
    List<List<Pitch>> wordList = new ArrayList<>();


    public List<List<Pitch>> makeWordsList(List<Pitch> pitchList){
        pitches = pitchList;
        int pauseCounter = 0;

        for (int i = 0; i < pitchList.size(); i++) {
            if(pitchList.get(i).getPitch() > 10000){
                pauseCounter++;
            } else {

                if(pauseCounter > 0){
                    if(pauseCounter >= 5){
                        wordList.add(oneWord);
                        oneWord = new ArrayList<>();
                    }
                    pauseCounter = 0;
                }
                oneWord.add(pitchList.get(i));
            }
        }
        if(oneWord.size() > 0){
            wordList.add(oneWord);
        }
        return wordList;
    }
}

Now from that wordsList I create a scrollable GraphView that on paper would look something like this. GraphView lookalike on paper

Now I have set the boundaries for the GraphView: MinX = -0.8; MaxX = 0.4. This way I'm showing 1 sec at a time on screen. Then I start a thread so it would change the coordinates of the GraphView by 0.1 every 100ms, which should add up as 1 every sec.

Here it is in code:

    public class SongPlayer extends AppCompatActivity {

    private Viewport graphViewPort;
    private Handler handler;
    private Runnable runnable;


    private GraphView graph;
    private DataPoint[] points;
    private LineGraphSeries<DataPoint> series;
    private int seriesNr;
    final static double GRAPH_STARTING_X = -0.8;
    final static double GRAPH_ENDING_X = 0.4;
    private double orderNr = GRAPH_STARTING_X;

    private List<Pitch> pitchesList;
    List<List<Pitch>> wordsList;

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.song_player);

        Intent intent = getIntent();

        //Get Textview and Button
        playRecordButton = (ImageButton) findViewById(R.id.playRecord);

        //Initialize pitches and words
        MakePitchesList listOfPithes = new MakePitchesList();
        MakeWordsList listOfWords = new MakeWordsList();

        pitchesList = listOfPithes.getListOfPitches();
        wordsList = listOfWords.getWordsList(pitchesList);

        //Initialize graph
        graph = (GraphView) findViewById(R.id.graph);
        initGraph();

        //ViewPort
        graphViewPort = graph.getViewport();

        //Handler
        handler = new Handler();

        playRecordButton.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View view, MotionEvent motionevent) {
                final int action = motionevent.getAction();
                if (action == MotionEvent.ACTION_DOWN) {

                    //Start playing audio
                    playMedia();

                    //Start moving graph
                    drawAndMoveGraph();

                } else if (action == MotionEvent.ACTION_UP) {

                    //Stop moving graph and set them to the beginning
                    resetGraph();

                    //Stop Playing audio
                    stopAudio();

                }//end else
                return false;
            } //end onTouch
        }); //end b my button

    }

    private void drawAndMoveGraph(){
        runnable = new Runnable() {
            public void run() {
                System.out.println(orderNr);
                graphViewPort.setMinX(orderNr);
                graphViewPort.setMaxX(orderNr + 1);
                graph.invalidate();
                if(pitchesList.size() != orderNr){
                    orderNr = orderNr + 0.1;
//                                System.out.println(orderNr);
                }


                handler.postDelayed(this, 100);
            }
        };
        runnable.run();
    }

    private void initGraph(){
        for (int i = 0; i < wordsList.size(); i++) {
            seriesNr = 0;
            points = new DataPoint[wordsList.get(i).size()];
            for (Pitch pitch: wordsList.get(i)) {
                points[seriesNr] = new DataPoint(pitch.getOccuranceTime(), pitch.getPitch());
                seriesNr++;
            }
            series = new LineGraphSeries<>(points);
            series.setThickness(15);
            graph.addSeries(series);
        }

        //VocalTestPoints
        PointsGraphSeries<DataPoint> series = new PointsGraphSeries<>(new DataPoint[] {
                new DataPoint(0, 50),
                new DataPoint(0, 75),
                new DataPoint(0, 100),
                new DataPoint(0, 125),
                new DataPoint(0, 150),
                new DataPoint(0, 175),
                new DataPoint(0, 200),
                new DataPoint(0, 225),
                new DataPoint(0, 250),
                new DataPoint(0, 275),
        });
        series.setSize(5);
        series.setColor(Color.YELLOW);
        graph.addSeries(series);


        // set manual X bounds
        graph.getViewport().setYAxisBoundsManual(true);
        graph.getViewport().setMinY(-50);
        graph.getViewport().setMaxY(400);

        graph.getViewport().setXAxisBoundsManual(true);
        graph.getViewport().setMinX(GRAPH_STARTING_X);
        graph.getViewport().setMaxX(GRAPH_ENDING_X); //mitu korraga näeb

        graph.getViewport().setScrollable(true);
    }

    private void playMedia(int songIndex){
        StorageUtil storage = new StorageUtil(getApplicationContext());
        storage.storeAudio(audioList);
        storage.storeAudioIndex(songIndex);

        mediaPlayer = new MediaPlayer();

        //Reset so that the MediaPlayer is not pointing to another data source
        mediaPlayer.reset();
        mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        try {
            mediaPlayer.setDataSource(storage.loadAudio().get(storage.loadAudioIndex()).getData());
        } catch (IOException e) {
            e.printStackTrace();
        }
        mediaPlayer.prepareAsync();
//        mediaPlayer.prepare(); // might take long! (for buffering, etc)
        mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mp) {
                mediaPlayer.start();

            }
        });


    }

    private void stopAudio(){
        mediaPlayer.stop();
        mediaPlayer.release();

    }

    private void resetGraph(){
        handler.removeCallbacks(runnable);
        graphViewPort.setMinX(GRAPH_STARTING_X);
        graphViewPort.setMaxX(GRAPH_ENDING_X);
        graph.invalidate();
        orderNr = GRAPH_STARTING_X;
    }


}

To sum up what the code does: it gets the wordsList from the pitches, initializes the graph, starts listening button click. When button is clicked, it starts moving graph as described above and plays audio.

The problem is that the audio and moving graphView go out of sync. For the first 10sec or so it works like it should but then the lines start falling behind. I would really appreciate if someone took their time to understand all of this mess.

Maybe picture of the actual final graphView will also help. GraphView on Android device. Blue line is the first incoming word.

  • [This question](https://stackoverflow.com/questions/5242918/android-media-player-and-seekbar-sync-issue) appears to be of a similar nature. Try looking into that. – M. Prokhorov Apr 28 '18 at 13:05
  • @M.Prokhorov will do, than you for the suggestion –  Apr 28 '18 at 13:09
  • @M.Prokhorov tried out everything that was suggested there but they worked the same way as mine did before. Anyways, thank you trying! –  Apr 28 '18 at 17:58

0 Answers0