2010-01-14 13 views

Odpowiedz

0

This Sun forum post ma interesujący kod do generowania tonów grzechu. Ponadto, biorąc pod uwagę, że format pliku WAV nie jest zbyt skomplikowany, można utworzyć tabelę reprezentującą pożądany przebieg, a następnie zapisać go w pliku. Istnieje kilka przykładów w okolicy, np. a raw audio converter i how to write a wav file.

+3

Link do forum Sun nie działa. – RealHowTo

+0

IIRC, dyskusja obejmowała [podejście] (http://stackoverflow.com/a/7782749/230513) ze względu na [Andrew Thompson] (http://stackoverflow.com/users/418556/andrew-thompson), cytowane [tutaj] (http://stackoverflow.com/a/2065693/230513). – trashgod

39

Używając Andrew's approach, oto przykład odtwarzający kod equal tempered scale.

import javax.sound.sampled.AudioFormat; 
import javax.sound.sampled.AudioSystem; 
import javax.sound.sampled.LineUnavailableException; 
import javax.sound.sampled.SourceDataLine; 

public class Tone { 

    public static void main(String[] args) throws LineUnavailableException { 
     final AudioFormat af = 
      new AudioFormat(Note.SAMPLE_RATE, 8, 1, true, true); 
     SourceDataLine line = AudioSystem.getSourceDataLine(af); 
     line.open(af, Note.SAMPLE_RATE); 
     line.start(); 
     for (Note n : Note.values()) { 
      play(line, n, 500); 
      play(line, Note.REST, 10); 
     } 
     line.drain(); 
     line.close(); 
    } 

    private static void play(SourceDataLine line, Note note, int ms) { 
     ms = Math.min(ms, Note.SECONDS * 1000); 
     int length = Note.SAMPLE_RATE * ms/1000; 
     int count = line.write(note.data(), 0, length); 
    } 
} 

enum Note { 

    REST, A4, A4$, B4, C4, C4$, D4, D4$, E4, F4, F4$, G4, G4$, A5; 
    public static final int SAMPLE_RATE = 16 * 1024; // ~16KHz 
    public static final int SECONDS = 2; 
    private byte[] sin = new byte[SECONDS * SAMPLE_RATE]; 

    Note() { 
     int n = this.ordinal(); 
     if (n > 0) { 
      double exp = ((double) n - 1)/12d; 
      double f = 440d * Math.pow(2d, exp); 
      for (int i = 0; i < sin.length; i++) { 
       double period = (double)SAMPLE_RATE/f; 
       double angle = 2.0 * Math.PI * i/period; 
       sin[i] = (byte)(Math.sin(angle) * 127f); 
      } 
     } 
    } 

    public byte[] data() { 
     return sin; 
    } 
} 

Takie podejście niskiego poziomu może być odpowiednie dla starszych, mniej wydajnych platform. Rozważ także javax.sound.midi; pełny przykład pokazano here i samouczek Synthesizing Sound jest cytowany here.

+0

Pakiet Java javax.sound.sampled nie jest biblioteką syntezy. Ułatwia jedynie przekazywanie cyfrowych reprezentacji, które zostały już zsyntetyzowane w rodzimym systemie audio systemu operacyjnego. –

+0

@DouglasDaseeco: Dziękuję za narysowanie tego rozróżnienia; podczas gdy pytający chciał "programowo generować pliki audio w locie", zaktualizowałem odpowiedź, aby przytoczyć twoje uzasadnienie rozważenia alternatyw. – trashgod

+0

Dziękuję za docenienie tego wyróżnienia. Pytający nie bardzo dokładnie określił, czy poszukiwana biblioteka była biblioteką generującą przebiegi falowe, czy biblioteką falową tell-OS-to-play. Możesz spróbować małego programu używając biblioteki midi. Tworzy notatki w taki sam sposób, jak robi to syntezator sampli. Mniej użyteczne dla dźwięków organowych lub syntetycznych, ale znacznie lepiej dla dźwięków tradycyjnych instrumentów. –

1

Jcollider to interfejs Java do serwera syntezy SuperCollider. Jeśli chcesz zsyntetyzować muzykę, to znacznie ułatwi to (oddziela generator brzmieniowy od syntezatora, dba o takie rzeczy, jak generowanie wykresu, usuwanie wyciszonych syntez z wykresu syntezy, aż będą potrzebne, poprawianie sygnałów między syntezatorami dynamicznie itd.).

7

Najprostszym sposobem na to jest z Javy w wbudowanych bibliotek MIDI:

int channel = 0; // 0 is a piano, 9 is percussion, other channels are for other instruments 

    int volume = 80; // between 0 et 127 
    int duration = 200; // in milliseconds 

    try { 
     Synthesizer synth = MidiSystem.getSynthesizer(); 
     synth.open(); 
     MidiChannel[] channels = synth.getChannels(); 

     // -------------------------------------- 
     // Play a few notes. 
     // The two arguments to the noteOn() method are: 
     // "MIDI note number" (pitch of the note), 
     // and "velocity" (i.e., volume, or intensity). 
     // Each of these arguments is between 0 and 127. 
     channels[channel].noteOn(60, volume); // C note 
     Thread.sleep(duration); 
     channels[channel].noteOff(60); 
     channels[channel].noteOn(62, volume); // D note 
     Thread.sleep(duration); 
     channels[channel].noteOff(62); 
     channels[channel].noteOn(64, volume); // E note 
     Thread.sleep(duration); 
     channels[channel].noteOff(64); 

     Thread.sleep(500); 

     // -------------------------------------- 
     // Play a C major chord. 
     channels[channel].noteOn(60, volume); // C 
     channels[channel].noteOn(64, volume); // E 
     channels[channel].noteOn(67, volume); // G 
     Thread.sleep(3000); 
     channels[channel].allNotesOff(); 
     Thread.sleep(500); 



     synth.close(); 
    } 
    catch (Exception e) { 
     e.printStackTrace(); 
    } 
+0

To jest świetne rozwiązanie, będę się z tym dużo gadać! Twoje zdrowie – Stevo

4

Javy wbudowane funkcje Midi

off-the-shelf Java 8 JRE zdecydowanie ma to, czego konkretnie wymagane: wbudowana biblioteka syntezatorów. Jest to opisane szczegółowo w Synthesizing Sound.

A quite refined example zapewnia wizualny dostęp do klawiatury do próbkowanego syntezatora muzycznego.

Biblioteka javax.sound.midi zawiera instrumenty i umiejętność odtwarzania nut na podstawie MIDI i technologii instrumentów próbkowanych. Dźwięki nie są tak autentyczne jak w klasycznej linii instrumentów muzycznych Kurzweil, ale struktura wspiera ten poziom zaawansowania, jeśli chcesz wykonać własne próbkowanie w wielu zakresach wysokości dla jednego instrumentu i opracować szczegóły dość płynnego przejścia między zakresami.

Trivial Przykład szybki przegląd Wykorzystanie

Oto trywialny przykład klasa.

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

public class PlayMidiNote 
{ 
    private static void sleep(int iUSecs) 
    { 
     try 
     { 
      Thread.sleep(iUSecs); 
     } 
     catch (InterruptedException e) 
     { 
     } 
    } 

    public static void main(String[] args) throws Exception 
    { 
     if (args.length < 3 && args.length > 4) 
     { 
      System.out.println("usage: java PlayNote 
        <8.bit.midi.note.number> <8.bit.velocity> 
        <usec.duration> [<midi.channel>]"); 
      System.exit(1); 
     } 

     int iMidiKey = Math.min(127, Math.max(0, 
       Integer.parseInt(args[0]))); 
     int iVelocity = Math.min(127, Math.max(0, 
       Integer.parseInt(args[1]))); 
     int iUSecsDuration = Math.max(0, 
       Integer.parseInt(args[2])); 
     int iChannel = args.length > 3 
      ? Math.min(15, Math.max(0, 
        Integer.parseInt(args[3]))) 
      : 0; 

     Synthesizer synth = MidiSystem.getSynthesizer(); 
     synth.open(); 

     MidiChannel[] channels = synth.getChannels(); 
     MidiChannel channel = channels[iChannel]; 

     channel.noteOn(iMidiKey, iVelocity); 
     sleep(iUSecsDuration); 
     channel.noteOff(iMidiKey); 

     synth.close(); 
    } 
} 

Korzystanie wielowątkowości lub e implementacje javax.sound.midi.Sequencer jak te dostępne na github.com zapewni strukturę niezbędną do faktycznie tworzyć muzykę.

Waveform Generation

Jeśli chcesz wygenerować własne przebiegi zamiast przy użyciu próbek, to odpowiedź na twoje pytanie brzmi: „Nie”, więc można grać z tego tonu syntezatora pisałem na to pytanie . Ma kilka funkcji.

  • Sterowanie nachyleniem (w cykli na sekundę)
  • kontroli amplitudy (w krokach cyfrowych)
  • min i max statystycznych wskazania, kiedy amplituda jest zbyt wysokie (co powoduje zakłócenia w sygnale z strzyżenie audio)
  • Kontrola czasu trwania tonu (w sekundach)
  • Kontrola względnej amplitudy dowolnej liczby harmonicznych (który określa jakość dźwięku lub fali, która jest jednym z kilku czynników, które tworzą nuty za barwę)

Syntezator ten nie posiada wielu funkcji syntezatorów generujących wysokie częstotliwości.

  • rzeczywistym czas modyfikacji amplitudy zasadniczymi harmonicznych harmonicznych i innych w czasie trwania notatki
  • nie odtwarza sekwencje nut (ale może być zmodyfikowany tak, aby to zrobić stosunkowo łatwo)
  • nr obiekt na przesunięcie fazowe harmonicznych albo (ale to dość istotne niedociągnięcie, gdyż charakterystyki fazowe harmonicznych nie jest czymś ludzkie ucho jest w stanie wykryć)

SimpleSynth to dobra demonstracja

  • Zasady syntezy dźwięku
  • timbral efekt harmonicznych
  • Zastosowanie Java generowania dźwięku tablice próbek
  • Wprowadzanie próbek do tablicy bajtów
  • Dostarczanie takich bajt array do systemu operacyjnego za pomocą linii

Standardową cyfrową terminologię audio użyto zarówno do nazewnictwa stałego, jak i zmiennych. Matematyka jest wyjaśniona w komentarzach.

import javax.sound.sampled.AudioSystem; 
import javax.sound.sampled.AudioFormat; 
import javax.sound.sampled.SourceDataLine; 

class SimpleSynth 
{ 
    private static int SAMPLE_BITS = 16; 
    private static int CHANNELS = 1; 
    private static boolean SIGNED_TRUE = true; 
    private static boolean BIG_ENDIAN_FALSE = false; 
    private static float CDROM_SAMPLE_FREQ = 44100; 

    private SourceDataLine line; 

    private double dDuration; 
    private double dCyclesPerSec; 
    private double dAmplitude; 
    private double[] adHarmonics; 

    private double dMin; 
    private double dMax; 

    public SimpleSynth(String[] asArguments) throws Exception 
    { 
     dDuration = Double.parseDouble(asArguments[0]); 
     dCyclesPerSec = Double.parseDouble(asArguments[1]); 
     dAmplitude = Double.parseDouble(asArguments[2]); 
     adHarmonics = new double[asArguments.length - 3]; 
     for (int i = 0; i < adHarmonics.length; ++ i) 
      adHarmonics[i] = Double.parseDouble(
        asArguments[i + 3]); 

     AudioFormat format = new AudioFormat(
       CDROM_SAMPLE_FREQ, SAMPLE_BITS, 
       CHANNELS, SIGNED_TRUE, BIG_ENDIAN_FALSE); 
     line = AudioSystem.getSourceDataLine(format); 
     line.open(); 
     line.start(); 
    } 

    public void closeLine() 
    { 
     line.drain(); 
     line.stop(); 
    } 

    public void playSound() 
    { 
     // allocate and prepare byte buffer and its index 
     int iBytes = (int) (2.0 * (0.5 + dDuration) 
       * CDROM_SAMPLE_FREQ); 
     byte[] ab = new byte[iBytes]; 
     int i = 0; 

     // iterate through sample radian values 
     // for the specified duration 
     short i16; 
     double dSample; 
     double dRadiansPerSample = 2.0 * Math.PI 
       * dCyclesPerSec/CDROM_SAMPLE_FREQ; 
     double dDurationInRadians = 2.0 * Math.PI 
       * dCyclesPerSec * dDuration; 
     dMin = 0.0; 
     dMax = 0.0; 
     for (double d = 0.0; 
       d < dDurationInRadians; 
       d += dRadiansPerSample) 
     { 
      // add principle and the dot product of harmonics 
      // and their amplitudes relative to the principle 
      dSample = Math.sin(d); 
      for (int h = 0; h < adHarmonics.length; ++ h) 
       dSample += adHarmonics[h] 
         * Math.sin((h + 2) * d); 

      // factor in amplitude 
      dSample *= dAmplitude; 

      // adjust statistics 
      if (dMin > dSample) 
       dMin = dSample; 
      if (dMax < dSample) 
       dMax = dSample; 

      // store in byte buffer 
      i16 = (short) (dSample); 
      ab[i ++] = (byte) (i16); 
      ab[i ++] = (byte) (i16 >> 8); 
     } 

     // send the byte array to the audio line 
     line.write(ab, 0, i); 
    } 

    public void printStats() 
    { 
     System.out.println("sample range was [" 
       + dMin + ", " + dMax + "]" 
       + " in range of [-32768, 32767]"); 

     if (dMin < -32768.0 || dMax > 32767.0) 
      System.out.println("sound is clipping" 
        + "(exceeding its range)," 
        + " so use a lower amplitude"); 
    } 

    public static void main(String[] asArguments) 
      throws Exception 
    { 
     if (asArguments.length < 3) 
     { 
      System.err.println("usage: java SimpleSynth" 
        + " <duration>" 
        + " <tone.cycles.per.sec>" 
        + " <amplitude>" 
        + " [<relative.amplitude.harmonic.2>" 
        + " [...]]"); 
      System.err.println("pure tone:" 
        + " java SimpleSynth 1 440 32767"); 
      System.err.println("oboe-like:" 
        + " java SimpleSynth 1 440 15000 0 1 0 .9"); 
      System.err.println("complex:" 
        + " java SimpleSynth 1 440 800 .3" 
        + " .5 .4 .2 .9 .7 5 .1 .9 12 0 3" 
        + " .1 5.2 2.5 .5 1 7 6"); 

      System.exit(0); 
     } 

     SimpleSynth synth = new SimpleSynth(asArguments); 
     synth.playSound(); 
     synth.closeLine(); 
     synth.printStats(); 

     System.exit(0); 
    } 
} 

tematy badań, które Rozszerz podsumowujące Muzyka Fachowość

Istnieje kilka tematów przeczytać na, jeśli chcesz, aby stać się ekspertem cyfrowy syntezator.

  • Cyfrowe wyjście audio
  • Signal próbkowania
  • kryteria Nyquist
  • Jak zrywać harmonicznych na strunach instrumentu (takich jak gitara)
  • Podstawowe trygonometrii, specjalnie funkcji sinus