IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Diskuze: správné nastavení loopu / opakování metody ANDROID

V předchozím kvízu, Online test znalostí Java, jsme si ověřili nabyté zkušenosti z kurzu.

Aktivity
Avatar
Filip Barák
Člen
Avatar
Filip Barák:9.5.2018 12:50

Zdravím, potřebuji poradit ohledně správného nastavení loopu při přehrávání AudioTrack.
AudioTrack generuje sinus a je spouštěn příkazem

public void startAudio(){
               audioTrack.reloadStaticData();
               audioTrack.setLoopPoints(0, sampleCount, -1);
               audioTrack.play();
       }

který čeká na onTouchListener

switch (event.getAction()) {

                   case MotionEvent.ACTION_DOWN:

                       setAudio(frekvence);
                       startAudio();

                       return true;
                   case MotionEvent.ACTION_UP:

                      stop();

                     return true;
               }
               return false;

problém je, že měním frekvenci na základě údajů z akcelerometru (relativné velké množství MĚNÍCÍCH se dat), ale jakmile se loop jednou chytne, hraje celou dobu na frekvenci, která do něj byla poslaná na začátku nehledě na měnící se údaj frekvence poté.
Potřebuji nějak upravit loop, aby loopoval jen do té doby, dokud je hodnota frekvence stejná, jakmile se změní údaj frekvence, začít loop od znova s novou frekvencí samozřejmě bez (slyšitelné) pauzy. nějaký integer listener? nebo loopovat celou metodu startAudio ? jak ?

loop má formát

int setLoopPoints (int startInFrames,
                int endInFrames,
                int loopCount)

start mám na 0, počet samplů je délka jedné vlny (samplovací frekvence / frekvence zvuku)
a -1 znamená nekonečno, kladná čísla jsou počet loopů.

díky za každou radu.

 
Odpovědět
9.5.2018 12:50
Avatar
Odpovídá na Filip Barák
Matúš Olejník:10.5.2018 11:53

Ak implementuješ SensorEventLis­tener tak v metóde onSensorChanged(Sen­sorEvent event) môžeš nastaviť že ak sa ti údaje z akcelerometra zmenili tak zavolaj startAudio() s novými údajmi.

Asi to nebude také jednoduché, ale za vyskúšanie nič nedáš :)

Editováno 10.5.2018 11:53
Nahoru Odpovědět
10.5.2018 11:53
/* I am not sure why this works but it fixes the problem */
Avatar
Filip Barák
Člen
Avatar
Filip Barák:11.5.2018 16:00

Díky za odpověď,
problém je, že musím zavolat celou metodu onTouchListener s ACTION.DOWN a tam mi to padá (ještě jsem neměl čas na debug, ale myslím že bude problém listener v listeneru). Pokud do SensorEventLis­tener dám jen setAudio(frek­vence);, kde nastavuji frekvenci, tak to frekvenci mění, ale přidává jí k už vytvořenému loopu základní frekvence, takže s každým pohybem se přidá nová frekvence a hrají zároveň.
setAudio vypadá takhle:

public void setSinus(int frekvence) {


       sampleCount = (int) ((float) SAMPLE_RATE / frekvence);
       short ssample[] = new short[sampleCount];
       int amplitude = 32767;

       double twoPi = 8. * Math.atan(1.);
       double phase = 0.0;

       for (int i = 0; i < sampleCount; i++) {
           ssample[i] = (short) (amplitude * Math.sin(phase));
           phase += twoPi * frekvence / SAMPLE_RATE;
       }
       siaudioTrack.write(ssample, 0, sampleCount);

   }
 
Nahoru Odpovědět
11.5.2018 16:00
Avatar
Odpovídá na Filip Barák
Matúš Olejník:11.5.2018 17:03

Nedala by sa poslať celá aktivita?

Prípadne v ontouchlisteneri ak je event down nastav pomocnú premennú ktorá indikuje že je (napr.) button stlačený a v senzor listeneri budeš meniť frekvenciu len ak je premenná true. A nemôžeš v senzor listeneri zavolať stop audio a následne štart s novou frekvenciou? Či bolo by veľmi počuť pauzu?

Akceptované řešení
+20 Zkušeností
Řešení problému
Nahoru Odpovědět
11.5.2018 17:03
/* I am not sure why this works but it fixes the problem */
Avatar
Filip Barák
Člen
Avatar
Filip Barák:11.5.2018 19:50

celá aktivita vypadá asi takhle

public class fullscreen_start extends Activity implements SensorEventListener {
    private Button melodieB;
       private Switch bezDrzeni;
    //  private int frekvence = 500;

    start start = new start();


    @SuppressLint("StaticFieldLeak")
    public static Context context_start;
    private SensorManager mSensorManager;
    private Sensor mAccelerometer;

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

        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        assert mSensorManager != null;
        mAccelerometer = mSensorManager.getDefaultSensor
(Sensor.TYPE_ACCELEROMETER);
        mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL,
 SensorManager.SENSOR_STATUS_ACCURACY_HIGH);

        fullscreen_start.context_start = getApplicationContext();

        melodieB = findViewById(R.id.bmelodie);
        bezDrzeni = findViewById(R.id.switch_melodie);

        button_generator();
        switch_melodie();


        }

    protected void onPause() {
        super.onPause();
        mSensorManager.unregisterListener(this);
    }

    protected void onResume() {
        super.onResume();
        mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
    }

 int konecnafrekvence;

    @Override
    @SuppressLint("SetTextI18n")
    public void onSensorChanged(SensorEvent event) {


        //float x = event.values[0];
        float y = event.values[1];
        //float z = event.values[2];

        double pet = 10.0 / 18;
        double yy = (y / pet);
        int yyy = (int) yy;

        double mocnina1 = Math.pow(2, yyy);
        double odmocnina1 = (Math.pow(mocnina1, (1.0 / 12)));
        double senzorFreq = 440 * odmocnina1;

        konecnafrekvence = (int) Math.round(senzorFreq);


         }


    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }


    @SuppressLint("ClickableViewAccessibility")
    private void button_generator() {

        melodieb.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {


                switch (event.getAction()) {

                    case MotionEvent.ACTION_DOWN:
                        if (tvarsignalu.spinnerHL == null) {
                        start.setSinus(konecnafrekvence);
                         start.startsinus();
                        } else {
                            switch (tvarsignalu.spinnerHL.getSelectedItem().toString()) {
                                case "sinus":

                                    System.out.println("pred play\n");
                                    start.setSinus(konecnafrekvence);
                                    start.startsinus();

                                case "čtverec":
                                    start.setSquare(konecnafrekvence);
                                    start.startsquare();
                                    System.out.println("za setwave\n");
                            }
                        }

                         return true;
                    case MotionEvent.ACTION_UP:

                        start.stop();

                        return true;
                }
                return false;
            }
        });


    }

    private void switch_melodie() {
        System.out.println(bezDrzeni);
        bezDrzeni.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                System.out.println(bezdrzeni);
                if (bezDrzeni.isChecked()) {
                    if (tvarsignalu.spinnerhl == null) {
                        start.setSinus(konecnafrekvence);
                        start.startsinus();
                    } else {
                        switch (tvarsignalu.spinnerhl.getSelectedItem().toString()) {
                            case "sinus":
                                System.out.println("pred play\n");
                                start.setSinus(konecnafrekvence);
                                start.startsinus();
                            case "čtverec":
                                start.setSquare(konecnafrekvence);
                                start.startsquare();
                                System.out.println("za setwave\n");
                        }
                    }


                } else {
                    start.stop();
                }
            }
        });
    }

}

a zdroják pro classu kde definuji vlny vypadá asi takhle

public class start {

    private final int SAMPLE_RATE = 44100;
    private AudioTrack siaudioTrack;
    private AudioTrack sqaudioTrack;
    private int sampleCount;
    private int sampleCountq;

    public start() {


        int buffsize = AudioTrack.getMinBufferSize
(SAMPLE_RATE, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT);
        siaudioTrack = new AudioTrack
(AudioManager.STREAM_MUSIC, SAMPLE_RATE, AudioFormat.CHANNEL_OUT_MONO,
 AudioFormat.ENCODING_PCM_16BIT, buffsize, AudioTrack.MODE_STATIC);
        sqaudioTrack = new AudioTrack
(AudioManager.STREAM_MUSIC, SAMPLE_RATE, AudioFormat.CHANNEL_OUT_MONO,
 AudioFormat.ENCODING_PCM_16BIT, buffsize, AudioTrack.MODE_STATIC);

    }

    public void setSinus(int frekvence) {


        sampleCount = (int) ((float) SAMPLE_RATE / frekvence);
        short ssample[] = new short[sampleCount];
        int amplitude = 32767;

        double twoPi = 8. * Math.atan(1.);
        double phase = 0.0;

        for (int i = 0; i < sampleCount; i++) {
            ssample[i] = (short) (amplitude * Math.sin(phase));
            phase += twoPi * frekvence / SAMPLE_RATE;
        }
        siaudioTrack.write(ssample, 0, sampleCount);

    }

    public void setSquare(int frekvence) {
        sampleCountq = (int) ((float) SAMPLE_RATE / frekvence);
        short sample[] = new short[sampleCountq];
        int amplitude = 32767;
        double phase = 0.0;
        double twoPi = 8. * Math.atan(1.);
        for (int i = 0; i < sampleCountq; i++) {
            sample[i] = (short) (amplitude * Math.sin(phase));
            if (sample[i] >  0.0) {
                sample[i] = 32767;
            }

            if (sample[i] <  0.0) {
                sample[i] = -32767;
            }
            phase += twoPi * frekvence / SAMPLE_RATE;
        }
       sqaudioTrack.write(sample, 0, sampleCountq);

    }

    public void startsinus() {

        siaudioTrack.reloadStaticData();
        siaudioTrack.setLoopPoints(0, sampleCount, -1);
        siaudioTrack.play();
    }

    public void startsquare() {

        sqaudioTrack.reloadStaticData();
        sqaudioTrack.setLoopPoints(0, sampleCountq, -1);
        sqaudioTrack.play();
    }


    public void stop() {
        siaudioTrack.stop();

        siaudioTrack.flush();

    }

}

v senzorListeneru právě .stop použít nemůžu, protože jak se ta activity načítá, tak to spadne s chybou, protože nemá ještě co zastavovat.
jsem v tomhle nový, takže se ještě moc neorientuji, díky za pomoc.

 
Nahoru Odpovědět
11.5.2018 19:50
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 5 zpráv z 5.