javax.sound.sampled - попытка запустить аудиосэмпл повторно не работает

Я программирую небольшой секвенсор ударных, подделку roland tr808 с 16 шагами / мерой и 16 инструментами (= сэмплы ударных). У пользователя есть графический интерфейс, где он может создать шаблон 16x16.

Однако, если семпл воспроизводится более одного раза подряд, он часто воспроизводится один раз. Скажем, у меня есть бас-гитара на шагах 1, 5, 9 и 13 и темп в 130 ударов в минуту, иногда он играет только bd на 1 и 9, а иногда и на 5 и / или 13. Если сэмпл очень короткий или темп медленный, шансы выше, что каждый шаг в паттерне воспроизводится правильно. Поэтому я предполагаю, что звуковой линии не нравится, когда я пытаюсь воспроизвести семпл снова, когда он еще не закончился.

Но на самом деле я думал, что учел это в своем коде. Я был бы очень благодарен, если бы кто-нибудь сказал мне, что не так с моим кодом.

Вот мой полный код, предложенный Эндрю Томпсоном, модифицированный так, чтобы он брал некоторые примеры из Интернета. Загрузка их занимает немного, хотя. часть, вызывающая проблему, - это, вероятно, метод play() в классе Instrument:

package testbox;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.sound.sampled.*;


public class boomboxtest {
    public static void main(String[] args) {

        Sequencer seq = new Sequencer();
        //bassdrum
        seq.toggleInstrument(0,0);
        seq.toggleInstrument(0,4);
        seq.toggleInstrument(0,8);
        seq.toggleInstrument(0,12);

        //snare
        seq.toggleInstrument(1,4);
        seq.toggleInstrument(1,12);

        //Hihat
        seq.toggleInstrument(2, 2);
        seq.toggleInstrument(2, 6);
        seq.toggleInstrument(2, 10);

        //Bongo
        seq.toggleInstrument(3, 6);
        seq.toggleInstrument(3, 10);

        seq.setTempo(130);
        seq.play();

    }
}


class Sequencer {
    private Mixer mixer;
    private List<SequencerListener> listeners = new ArrayList<SequencerListener>();
    public static final int INSTR_COUNT = 4;
    private int tempo_bpm = 120;
    private ExecutorService executor;
    private int current_step = 0;
    private int current_max_step = 16;
    private boolean[][] pattern = new boolean[32][INSTR_COUNT];
    private ArrayList<Instrument> instruments;
    Line[] lines = new Line[16];
    private SequencerEngine seq;

    private String[] filenames = {"http://www.canadianmusicartists.com/sample/kick_02.wav", "http://www.canadianmusicartists.com/sample/snare01.wav", "http://www.canadianmusicartists.com/sample/H_closedhat_01.wav", "http://www.canadianmusicartists.com/sample/bongo01.wav"};
    public Sequencer() {
        seq = new SequencerEngine();
        try{ 
            Mixer.Info[] mixerInfo = AudioSystem.getMixerInfo();
            mixer = AudioSystem.getMixer(mixerInfo[0]);
        } catch (Exception e) {e.printStackTrace();}


        instruments = new ArrayList<Instrument>(INSTR_COUNT);
        for (int i = 0; i < INSTR_COUNT; i++) {
            System.out.println("Loading instrument " + i);
            Instrument instr = new Instrument(filenames[i], mixer);
            instruments.add(instr);
            lines[i] = instr.getLine();
        }
        syncMixer();

        executor = Executors.newCachedThreadPool();
        executor.submit(seq);
    }




    public void syncMixer() {
        if (mixer.isSynchronizationSupported(lines, false)) {
            mixer.synchronize(lines, false);
        } else {
            System.out.println("No hay synchronisado");
        }
    }

    public boolean isPlaying() {
        return seq.getRunning();
    }

    public boolean toggleInstrument (int instrument, int beat) {
        pattern[beat][instrument] = !pattern[beat][instrument];
        return pattern[beat][instrument];
    }

    public void play() {
        seq.toggleRun(true);
    }

    public void pause() {
        seq.toggleRun(false);
    }

    public void stop() {
        pause();
        setCurrent_step(0);
    }

    public int getTempo() {
        return tempo_bpm;
    }

    public void setTempo(int tempo) {
        if (tempo < 30) {
            tempo = 30;
        } else if (tempo > 200) {
            tempo = 200;
        } else {
            this.tempo_bpm = tempo;
        }
    }

    public int getCurrent_step() {
        return current_step;
    }

    public void setCurrent_step(int current_step) {
        this.current_step = current_step;
    }

    public boolean[][] getPattern() {
        return pattern;
    }

    public void kill() {
        seq.kill();
        executor.shutdownNow();
    }

    public void addListener(SequencerListener toAdd) {
        listeners.add(toAdd);
    }

    public class SequencerEngine implements Runnable{
        private boolean running;
        private boolean alive = true;

        public void run() {
            while( getAlive()) {
                while (getRunning()) {
                    if (current_step >= current_max_step) {
                        current_step = 0;
                    }



                    for (; current_step < current_max_step ; current_step++) {
                        stepListen();                       
                        if(!getRunning()) {
                            break;
                        }
                        long time = System.currentTimeMillis();
                        long steptime = 60000/(4*tempo_bpm);


                        for (int k = 0; k < INSTR_COUNT; k++) {
                            if (pattern[current_step][k]) {
                                instruments.get(k).play();  
                            }
                        }

                        while((System.currentTimeMillis()-time) < steptime) {}
                    }
                }

            }
        }


        public void stepListen() {
            for (SequencerListener sl : listeners) {
                sl.stepEvent(current_step);
            }
        }

        public boolean getRunning() {
            return running;
        }

        public boolean getAlive() {
            return alive;
        }

        public void toggleRun(boolean toggle) {
            running = toggle;
        }

        public void kill() {
            alive = false;
        }
    }
}

class Instrument {
    private String name;
    private File soundFile;
    private AudioInputStream stream;
    private AudioFormat format;
    private DataLine.Info info;
    private Clip clip;
    private Mixer mixer;

    public Instrument(String filename, Mixer mixer ) {
        this.name = filename;
        try {
            //soundFile = new File("sounds/" + filename);

            URL url = new URL(filename);

            this.mixer = mixer;

            //stream = AudioSystem.getAudioInputStream(soundFile);
            stream = AudioSystem.getAudioInputStream(url);
            format = stream.getFormat();
            info = new DataLine.Info(Clip.class, format);
            clip = (Clip) mixer.getLine(info);
            clip.open(stream);

        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }



    public void play() {
        clip.stop();
        clip.setFramePosition(0);
        clip.start();
    }

    public Line getLine() {
        return clip;
    }
}

interface SequencerListener {
    void stepEvent(int current_step);
}

Сэмплы довольно сомнительного качества, но особенно басовый сэмпл хорошо иллюстрирует мою проблему.

0 ответов

Другие вопросы по тегам