Java Android GraphView和Mediaplayer失去同步

Java Android GraphView和Mediaplayer失去同步,java,android,synchronization,android-mediaplayer,android-graphview,Java,Android,Synchronization,Android Mediaplayer,Android Graphview,我正在做一个项目,我需要在图形视图中显示歌词的音高。我编写了一个程序,可以从一首歌中获得音高,并从中创建一个.txt文件 然后我编写了一个类,它读取文件,并从中创建一个列表。所以最后我会有一个列表,它由单词和单词组成,包含音高。在makepitchslist中,您可以看到歌曲的pitchs输出是什么样子的。我每行都有0,14:23281,61。行的第一部分是timeOccurance意思,当听到这个音调时,第二部分是音调本身。因此,在本例中,timeOccurance将为0,14,并在给定时间2

我正在做一个项目,我需要在
图形视图中显示歌词的
音高。我编写了一个
程序
,可以从一首歌中获得
音高
,并从中创建一个
.txt文件

然后我编写了一个类,它读取
文件
,并从中创建一个
列表
。所以最后我会有一个
列表
,它由
单词
单词
组成,包含
音高
。在
makepitchslist
中,您可以看到歌曲的
pitchs
输出是什么样子的。我每行都有
0,14:23281,61
。行的第一部分是
timeOccurance
意思,当听到这个音调时,第二部分是音调本身。因此,在本例中,
timeOccurance
将为
0,14
,并在给定时间
23281,61

下面是三个类,它们从
pitch.txt文件中生成
wordsList

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;
    }
}
总结一下代码的作用:它从音高中获取
单词列表
,初始化图形,单击开始收听按钮。当点击按钮时,它开始如上所述移动图形并播放音频

问题是音频和移动的
graphView
不同步。在前10秒左右,它的工作原理与它应该的一样,但随后
行开始落后。如果有人能花时间去理解这一切,我会非常感激的

也许实际的最终
图形视图的图片也会有所帮助

蓝线是第一个输入字

音频的计时和线路应在“0”处相交

我还创建了一个只包含上述类和主题的小示例。 可从此处访问:

这段代码在它的原始文件夹中包含了一首歌,所以它比应该的要大一点,但这是演示我想说的内容的最快方式

欢迎提出任何想法、建议和帮助。或对代码样式的注释

public class MainActivity extends AppCompatActivity {

    final static double GRAPH_STARTING_X = -0.8;
    final static double GRAPH_ENDING_X = 0.4;
    List<java.util.List<Pitch>> wordsList;
    private Viewport graphViewPort;
    private Handler handler;
    private Runnable runnable;
    private GraphView graph;
    private DataPoint[] points;
    private LineGraphSeries<DataPoint> series;
    private int seriesNr;
    private double orderNr = GRAPH_STARTING_X;
    private ImageButton playRecordButton;
    private List<Pitch> pitchesList;
    private int songIndex;
    private MediaPlayer mediaPlayer;
    private boolean isPlaying = false;


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

        //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.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(!isPlaying){
                    playMedia(songIndex);

                    //Start moving graph
                    //Moved to PlayMedia - setOnPreparedListen
//                    drawAndMoveGraph();

                    isPlaying = true;
                } else if(isPlaying){

                    //Move graph to starting position
                    resetGraph();

                    //Stop Playing audio
                    stopAudio();

                    isPlaying = false;

                }
            }
        });


    }

    //Moves the graph every 100ms by 0.1 which results in 1 every second
    private void drawAndMoveGraph() {
        runnable = new Runnable() {
            public void run() {
                graphViewPort.setMinX(orderNr);
                graphViewPort.setMaxX(orderNr + 1);
                graph.invalidate();
                if (pitchesList.size() != orderNr) {
                    orderNr = orderNr + 0.1;
                }


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

    //Load up and paint the graph
    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 - Just for vocal testing
        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);
        graph.getViewport().setScrollable(true);
    }


//    Play the chosen song and start moving the graph
    private void playMedia(int songIndex) {

        Uri uri = Uri.parse("android.resource://com.example.thermaltakei7.testsinging/" + R.raw.perfect);

        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(getApplicationContext(), uri);
        } catch (IOException e) {
            e.printStackTrace();
        }
        mediaPlayer.prepareAsync();
        mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mp) {
                mediaPlayer.start();
                drawAndMoveGraph();
            }
        });


    }

    //Stop audio from playing
    private void stopAudio() {
        mediaPlayer.stop();
        mediaPlayer.release();

    }

    //Reset graph to its initial position
    private void resetGraph() {
        handler.removeCallbacks(runnable);
        graphViewPort.setMinX(GRAPH_STARTING_X);
        graphViewPort.setMaxX(GRAPH_ENDING_X);
        graph.invalidate();
        orderNr = GRAPH_STARTING_X;
    }


}