Pereiti prie turinio

Java Midi sounds - veikia per lėtai


Rekomenduojami pranešimai

Sveiki,

 

Dirbu ties vienu Java uždaviniu, ir užstrigau, kaip padaryti tvarkingai viską.

Idėja trumpai - reikia padaryti tokią lyg sound machine - eina rodyklė tam tikru greičiu (bpm) ir reikia, kad jei yra pažymėta nata ant dabartinės pozicijos, reikia groti natą. Dvi pagrindinės problemos greityje tai judinti rodyklę ir groti tą natą.

 

Rodyklė judinama taip:

try {
				// Sleep for an appropriate amount
				System.out.println(Math.round(60000 / SimoriOn.getInstance().getBPM()));
				// 60000 ms (1min) / bpm (beats per minute)
				Thread.sleep(Math.round(60000 / SimoriOn.getInstance().getBPM()));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

 

Ir taip paleidžiama nata:

// If selected button is in the current column, play sound
				if (button.getCoordsX() == i) {
					// Sound test
					(new Thread(new Sounds(50 - button.getCoordsY(), velocity)))
							.start();

				}

 

Sound klasė:

/**
 * constructor that takes into account 2 arguments that take into account
 * the note being played and the velocity.
 * 
 * @param note
 * @param velocity
 */
public Sounds(int note, int velocity) {
	this.note = note;
	this.velocity = velocity;
}

/**
 * run method will play initiliase the synthesizer and then play the
 * appropriate instrument at that specific button.
 */
public void run() {
	synthesizer = this.getSynthesizer();
	this.playInstrument();

}

/**
 * a method that reutns the intance of the synthesizer for that specific
 * object.
 * 
 * @return
 */
public Synthesizer getSynthesizer() {
	Synthesizer synthesizer = null;
	try {
		synthesizer = MidiSystem.getSynthesizer();
		synthesizer.open();
	} catch (Exception ex) {
		System.out.println(ex);
		System.exit(1);
	}
	return synthesizer;
}

/**
 * method that has been created in order to delay the current thread that is
 * being used for ms amount of milliseconds.
 * 
 * @param ms
 */
public void delay(int ms) {
	try {
		Thread.sleep(ms);
	} catch (Exception ex) {
		Thread.currentThread().interrupt();
	}
}

/**
 * method that will allow the instrument to be played using the standard
 * java libraries to play the sounds at the given button
 */
public void playInstrument() {
	// get the channel for the synthesizer.
	MidiChannel[] midiChannels = synthesizer.getChannels();
	MidiChannel midiChannel = midiChannels[OTHER_CHANNEL];
	Instrument[] instruments = synthesizer.getDefaultSoundbank()
			.getInstruments();

	synthesizer.loadInstrument(instruments[20]);
	midiChannel.programChange(20);
	midiChannel.noteOn(note, velocity);
	delay(FUDGE_FACTOR * velocity);
	midiChannel.noteOff(note, velocity);

}

 

Dėkui už bet kokią pagalbą dėl greičio, kad viskas greit ir tvarkingai veikia.

Jeigu padės, galiu .jar'ą padaryt, kad geresnę idėją turėtumėt kas per programa.

 

Ačiū!

Nuoroda į pranešimą
Dalintis kituose puslapiuose

Jo rodyklė atskiram thread.

Dabar išprintinau laikus kas kada vyksta, ir atsilikimas yra būtent šioje dalyje (bent 200ms minimum):

// Sound test
					System.out.println(System.currentTimeMillis()+": Creating new sound at column " +i);
					(new Thread(new Sounds(50 - button.getCoordsY(), velocity)))
							.start();

 

Pridedu Sounds klasę, kuri dabar testavimui yra padaryta labai paprasta (vienas garsas). Ar yra kokių idėjų, kodėl atslikimas toks, ir kaip reiktų sumažint tą delay'ų tarp garso sukūrimo ir jo grojimo?

 

package simori;

import javax.sound.midi.Instrument;
import javax.sound.midi.MidiChannel;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Synthesizer;

/**
* 
* this is a class that implements the sounds that will be played when a button
* is clicked and the clock hand is on the button for that time period. if the
* button is pressed and the clock hand isnt on the button, no sound will play
* 
* @author Team G
* @date 10/02/2016.
* @Verson 1.0;
* 
*/
public class Sounds implements Runnable {

private final static int FIVE_SECONDS = 5000; /* milliseconds */
private final static int FUDGE_FACTOR = 10; /* multiplier */
private final static int OTHER_CHANNEL = 12; /* 0..8, 10..15 */
private final static int PIANO = 1;
private final static int PERCUSSION_CHANNEL = 9;
private final static int CRASH_CYMBAL_1 = 49;
private int note = 50;
private int velocity = 64;

Synthesizer synthesizer;

/**
 * constructor that takes into account 2 arguments that take into account
 * the note being played and the velocity.
 * 
 * @param note
 * @param velocity
 */
public Sounds(int note, int velocity) {
	this.note = note;
	this.velocity = velocity;
}

/**
 * run method will play initiliase the synthesizer and then play the
 * appropriate instrument at that specific button.
 */
public void run() {
	synthesizer = this.getSynthesizer();
	this.playInstrument();

}

/**
 * a method that reutns the intance of the synthesizer for that specific
 * object.
 * 
 * @return
 */
public Synthesizer getSynthesizer() {
	Synthesizer synthesizer = null;
	try {
		synthesizer = MidiSystem.getSynthesizer();
		synthesizer.open();
	} catch (Exception ex) {
		System.out.println(ex);
		System.exit(1);
	}
	return synthesizer;
}

/**
 * method that has been created in order to delay the current thread that is
 * being used for ms amount of milliseconds.
 * 
 * @param ms
 */
public void delay(int ms) {
	try {
		Thread.sleep(ms);
	} catch (Exception ex) {
		Thread.currentThread().interrupt();
	}
}

/**
 * method that will allow the instrument to be played using the standard
 * java libraries to play the sounds at the given button
 */
public void playInstrument() {
	// get the channel for the synthesizer.
	MidiChannel[] midiChannels = synthesizer.getChannels();
	MidiChannel midiChannel = midiChannels[PERCUSSION_CHANNEL];
	Instrument[] instruments = synthesizer.getDefaultSoundbank()
			.getInstruments();

	synthesizer.loadInstrument(instruments[20]);
	//midiChannel.programChange(20);
	midiChannel.noteOn(35, velocity);
	System.out.println(System.currentTimeMillis() + ": Playing sound");
	delay(FUDGE_FACTOR * velocity);
	midiChannel.noteOff(35, velocity);

}

}

 

1456229900799: Clockhand enterring column 12
1456229900800: Creating new sound at column 12
1456229900800: Going to sleep for 1000
1456229900878: Playing sound
1456229900970: Playing sound
1456229901801: Clockhand enterring column 13
1456229901801: Creating new sound at column 13
1456229901802: Going to sleep for 1000
1456229902023: Playing sound

 

Kad geriau suprast ką darom, įsivaizduokit Fruity Loops, kur pattern'ą darai.

 

http://www.probeatstudio.com/wp-content/uploads/2015/06/fl_studio_simple_drum_beat.png

 

Dėkui!

Nuoroda į pranešimą
Dalintis kituose puslapiuose

Pirmas negeras dalykas yra tai, kad tu vis kuri naujus Sound objektus.

(new Thread(new Sounds(50 - button.getCoordsY(), velocity))).start();

Tai reiškia, kad kai jau ateina laikas groti kažkokią natą, tu tik tada pradedi pasiruošinėti tos natos grojimui (nėra aišku, kiek trunka klasės klasės Sound inicializavimas, bet jis tikrai uždelsia natos sugrojimą). Reikėtų susikurti sound objektus iš anksto ir kai ateina laikas tiesiog iškviesti Sound.playInstrument() metodą.

 

Kitas negeras dalykas, kad kiekvienam sugrojimui sukuri po naują thread'ą. Tas faktas, kad kažkokiu laiko momentu sukuri ir paleidi thread'ą dar negarantuoja, kad procesorius paims ir iškart pradės vykdyti tą thread'ą.

 

Dar siūlyčiau vengti naudoti Thread.sleep(), nes jis negarantuoja, kad bus uždelsta tiek laiko, kiek tu įrašei kviesdamas metodą:

Two overloaded versions of sleep are provided: one that specifies the sleep time to the millisecond and one that specifies the sleep time to the nanosecond. However, these sleep times are not guaranteed to be precise, because they are limited by the facilities provided by the underlying OS. Also, the sleep period can be terminated by interrupts, as we'll see in a later section. In any case, you cannot assume that invoking sleep will suspend the thread for precisely the time period specified.

 

Tau reikėtų susirasti kažkokią asinchroninę garso biblioteką, kuriai galėtum pasakyt, kad nuo dabar tiek ir tiek laiko grok atitinkamą natą, o po kiek laiko užduodi groti kitą natą. Tokiu būdu nereikės rūpintis naujų thread'ų kūrimu ar pakartotinu Sound objektų inicializavimu.

Redagavo wi_lius
Nuoroda į pranešimą
Dalintis kituose puslapiuose

Pirmas negeras dalykas yra tai, kad tu vis kuri naujus Sound objektus.

(new Thread(new Sounds(50 - button.getCoordsY(), velocity))).start();

Tai reiškia, kad kai jau ateina laikas groti kažkokią natą, tu tik tada pradedi pasiruošinėti tos natos grojimui (nėra aišku, kiek trunka klasės klasės Sound inicializavimas, bet jis tikrai uždelsia natos sugrojimą). Reikėtų susikurti sound objektus iš anksto ir kai ateina laikas tiesiog iškviesti Sound.playInstrument() metodą.

 

Kitas negeras dalykas, kad kiekvienam sugrojimui sukuri po naują thread'ą. Tas faktas, kad kažkokiu laiko momentu sukuri ir paleidi thread'ą dar negarantuoja, kad procesorius paims ir iškart pradės vykdyti tą thread'ą.

 

Dar siūlyčiau vengti naudoti Thread.sleep(), nes jis negarantuoja, kad bus uždelsta tiek laiko, kiek tu įrašei kviesdamas metodą:

 

 

Tau reikėtų susirasti kažkokią asinchroninę garso biblioteką, kuriai galėtum pasakyt, kad nuo dabar tiek ir tiek laiko grok atitinkamą natą, o po kiek laiko užduodi groti kitą natą. Tokiu būdu nereikės rūpintis naujų thread'ų kūrimu ar pakartotinu Sound objektų inicializavimu.

 

Dėkui už atsakymą :)

 

Išsiaiškinom, kad sintezatoriaus gavimas užtruko ilgiausiai. Pakeitėm, kad jį užkrautų prieš tai, ir natos groja žymiai greičiau.

 

Čia universiteto projektas, nemanau kad galim naudot kažkokias 3rd party bibliotekas :)

Kaip išvengti thread sleep? Galvojau naudoti system nanotime ir kažkaip skaičiuoti kada būtent paleisti tuos garsus, ar veiktų taip?

 

Taip pat, vienu metu gali groti iki 256 garsų, todėl nežinau kaip kitaip visus juos paleisti apart kiekvienam sukurti po Thread'ą?

 

Ačiū už pagalbą! :)

Nuoroda į pranešimą
Dalintis kituose puslapiuose

Prisijunkite prie diskusijos

Jūs galite rašyti dabar, o registruotis vėliau. Jeigu turite paskyrą, prisijunkite dabar, kad rašytumėte iš savo paskyros.

Svečias
Parašykite atsakymą...

×   Įdėta kaip raiškusis tekstas.   Atkurti formatavimą

  Only 75 emoji are allowed.

×   Nuorodos turinys įdėtas automatiškai.   Rodyti kaip įprastą nuorodą

×   Jūsų anksčiau įrašytas turinys buvo atkurtas.   Išvalyti redaktorių

×   You cannot paste images directly. Upload or insert images from URL.

Įkraunama...
  • Dabar naršo   0 narių

    Nei vienas registruotas narys šiuo metu nežiūri šio puslapio.

  • Prisijunk prie bendruomenės dabar!

    Uždarbis.lt nariai domisi verslo, IT ir asmeninio tobulėjimo temomis, kartu sprendžia problemas, dalinasi žiniomis ir idėjomis, sutinka būsimus verslo partnerius ir dalyvauja gyvuose susitikimuose.

    Užsiregistruok dabar ir galėsi:

    ✔️ Dalyvauti diskusijose;

    ✔️ Kurti naujas temas;

    ✔️ Rašyti atsakymus;

    ✔️ Vertinti kitų žmonių pranešimus;

    ✔️ Susisiekti su bet kuriuo nariu asmeniškai;

    ✔️ Naudotis tamsia dizaino versija;

    ir dar daugiau.

    Registracija trunka ~30 sek. ir yra visiškai nemokama.

  • Naujausios temos

  • Karštos temos

×
×
  • Pasirinkite naujai kuriamo turinio tipą...