2015-04-03 82 views
1

我簡直有一個絕妙的想法,但後來我意識到在Java中我太過小菜了。我的想法是這樣的:通過在JComboBox中選擇將枚舉值傳遞給一個函數

我們有一個名爲測試(現在),有一個枚舉音調 - 你可以看到每個音頻的頻率值。當然,我們有getChord()函數來獲取這些值。

import javax.swing.*; 
import java.awt.*; 
import java.util.*; 

public class test 
{ 
public enum Tones 
{ 
    C(261.6), CSHARP(277.2), D(293.7), DSHARP(311.2), E(329.6), F(349.6), FSHARP(370), G(391.9), GSHARP(415.3), A(440), B(466.2), H(493.9); 

    private double frequencyVal; 

    Tones(double frequencyVal) 
    { 
     this.frequencyVal = frequencyVal; 
    } 

    public double getChord() 
    { 
     return frequencyVal; 
    } 
    }; 
} 

然後,我們有一個名爲Chords的類,其中JComboBox是。我們可以簡單地從中選擇一個和絃。

import java.awt.event.ItemEvent; 
import java.awt.event.ItemListener; 

import javax.swing.*; 


class Chords extends JPanel 
{ 
private JComboBox chooseChord = new JComboBox(new String[]{"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "B", "H"}); 

public Chords() 
{ 
    chooseChord.setSelectedItem(null); 

    chooseChord.addItemListener(new ItemListener() 
    { 
     @Override 
     public void itemStateChanged(ItemEvent e) 
     { 
      Object item = chooseChord.getSelectedItem(); 

      if ("A".equals(item)) 
      { 

      } 

      else if ("B".equals(item)) 
      { 

      } 

      else if ("H".equals(item)) 
      { 

      } 

      else if ("C".equals(item)) 
      { 

      } 

      else if ("C#".equals(item)) 
      { 

      } 

      else if ("D".equals(item)) 
      { 

      } 

      else if ("D#".equals(item)) 
      { 

      } 

      else if ("E".equals(item)) 
      { 

      } 

      else if ("F".equals(item)) 
      { 

      } 

      else if ("F#".equals(item)) 
      { 

      } 

      else if ("G".equals(item)) 
      { 

      } 

      else if ("G#".equals(item)) 
      { 

      } 
     } 
    }); 

    add(chooseChord); 
} 
} 

這就是困難部分進來的地方。我希望我會盡可能簡單地描述它。

通過選擇JComboBox中的和絃,我想從枚舉中選擇一組三個特定的音調。然後我想讓這三個特定的值傳遞給另一個類(代碼結束)中的playChord()函數。我只是在那裏輸入隨機的頻率值。

import java.applet.*; 
import java.io.*; 
import java.net.*; 

import javax.sound.sampled.*; 

public final class Audio 
{ 

    public static final int SAMPLE_RATE = 44100; 

    private static final int BYTES_PER_SAMPLE = 2;    // 16-bit audio 
    private static final int BITS_PER_SAMPLE = 16;    // 16-bit audio 
    private static final double MAX_16_BIT = Short.MAX_VALUE;  // 32,767 
    private static final int SAMPLE_BUFFER_SIZE = 4096; 

    private static SourceDataLine line; // to play the sound 
    private static byte[] buffer;   // our internal buffer 
    private static int bufferSize = 0;  

    private static double amplitude, frequency, phase; 

    // not-instantiable 
    private Audio() { } 

    // static initializer 
    static { init(); } 

    // open up an audio stream 
private static void init() 
{ 

try 
{ 
    // 44,100 samples per second, 16-bit audio, mono, signed PCM, little Endian 
    AudioFormat format = new AudioFormat((float) SAMPLE_RATE, BITS_PER_SAMPLE, 1, true, false); 
    DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); 

    line = (SourceDataLine) AudioSystem.getLine(info); 
    line.open(format, SAMPLE_BUFFER_SIZE * BYTES_PER_SAMPLE); 

    buffer = new byte[SAMPLE_BUFFER_SIZE * BYTES_PER_SAMPLE/3]; 
} 

catch (Exception e) 
{ 
    System.out.println(e.getMessage()); 
    System.exit(1); 
} 

// no sound gets made before this call 
line.start(); 
} 

public void setAmplitude(double a) 
{ 
    amplitude = a; 
} 

public static void setFrequency(double f) 
{ 
    frequency = f; 
} 

public void SetPhase(double p) 
{ 
    phase = p; 
} 

public static double getAmplitude() 
{ 
    return amplitude; 
} 

public static double getFrequency() 
{ 
    return frequency; 
} 

public static double getPhase() 
{ 
    return phase; 
} 

/** 
* Close standard audio. 
*/ 
public static void close() 
{ 
line.drain(); 
line.stop(); 
} 

/** 
* Write one sample (between -1.0 and +1.0) to standard audio. If the sample 
* is outside the range, it will be clipped. 
*/ 
public static void play(double in) 
{ 

// clip if outside [-1, +1] 
if (in < -1.0) in = -1.0; 
if (in > +1.0) in = +1.0; 

// convert to bytes 
short s = (short) (MAX_16_BIT * in); 
buffer[bufferSize++] = (byte) s; 
buffer[bufferSize++] = (byte) (s >> 8); // little Endian 

// send to sound card if buffer is full   
if (bufferSize >= buffer.length) 
{ 
    line.write(buffer, 0, buffer.length); 
    bufferSize = 0; 
} 
} 

/** 
* Write an array of samples (between -1.0 and +1.0) to standard audio. If a  sample 
* is outside the range, it will be clipped. 
*/ 
public static void play(double[] input) 
{ 
for (int i = 0; i < input.length; i++) 
{ 
    play(input[i]); 
} 
} 

private static double[] tone(double hz, double duration, double amplitude, double phase) 
{ 
int N = (int) (Audio.SAMPLE_RATE * duration); 
double[] a = new double[N+1]; 
for (int i = 0; i <= N; i++) 
    a[i] = amplitude * Math.sin(2 * Math.PI * i * hz/Audio.SAMPLE_RATE + phase); 
return a; 
} 

public static void playChord() throws LineUnavailableException 
{ 
double[] a = tone(415.3, 1.0, 1, 0); 
double[] b = tone(329.6, 1.0, 1, 0); 
double[] c = tone(493.9, 1.0, 1, 0); 

for(int i=0; i<a.length; ++ i) 
    a[i] = (a[i] + b[i] + c[i])/3; 

Audio.play(a); 
} 

public static void playSound() throws LineUnavailableException 
{ 
double[] a = tone(getFrequency(), 1.0, getAmplitude(), getPhase()); 

for(int i = 0; i < a.length; ++ i) 
     a[i] = (a[i]); 

Audio.play(a); 
} 
} 

我的程序假定用戶可以從列表中選擇一個和絃,然後只需按「播放」按鈕,聽到它,這就是爲什麼我希望它可以自動完成,因爲我真的不知道是否確定?12個單獨的函數/變量/數組存儲的色調值是最好的方式

任何線索或幫助如何實現這一複雜的目標,我覺得只是被它壓倒

編輯: 實施Radiodef的解決方案到我的代碼對我來說有點困難,我想我理解你的代碼,但是我不能將它實現爲min即你會幫忙嗎?我的主要功能如下所示:

import java.awt.*; 
import java.awt.event.*; 
import javax.sound.sampled.LineUnavailableException; 
import javax.swing.*; 
import javax.swing.border.BevelBorder; 
import javax.swing.event.*; 

import java.awt.*; 

public class Window extends JPanel implements ActionListener 
{ 
private JMenuBar mainMenu = new JMenuBar(); 

private Plot plot = new Plot(); 
private Parameters param = new Parameters(); 

private JButton playSound = new JButton("Play"); 
private JButton getSample = new JButton("Save wave"); 
private JButton getPlot = new JButton("Save plot"); 

private Chords music = new Chords(); 

private JPanel mainPanel = new JPanel(); 
private JPanel subPanel = new JPanel(); 
private JPanel buttonsPanel = new JPanel(); 
private JPanel slidersPanel = new JPanel(); 

private JLabel chord = new JLabel("Chord:"); 

private JTextField aValue = new JTextField(); 
private JTextField fValue = new JTextField(); 
private JTextField pValue = new JTextField(); 

public Window() 
{ 
    mainPanel.setLayout(new FlowLayout()); 
    buttonsPanel.setLayout(new BoxLayout(buttonsPanel, BoxLayout.Y_AXIS)); 
    slidersPanel.setLayout(new BorderLayout()); 
    subPanel.setLayout(new BorderLayout()); 

    buttonsPanel.add(chord); 
    buttonsPanel.add(music); 
    buttonsPanel.add(Box.createRigidArea(new Dimension(0,10))); 
    buttonsPanel.add(playSound); 
    buttonsPanel.add(Box.createRigidArea(new Dimension(0,10))); 
    buttonsPanel.add(getSample); 
    buttonsPanel.add(Box.createRigidArea(new Dimension(0,10))); 
    buttonsPanel.add(getPlot); 
    buttonsPanel.setBorder(BorderFactory.createTitledBorder("Menu")); 

    JMenu langMenu = new JMenu("Language"); 

    param.addAmplitudeListener(new ChangeListener() 
    { 
     public void stateChanged(ChangeEvent a) 
     { 
      int ampValue = param.getAmplitudeValue(); 
      aValue.setText(String.valueOf(ampValue)); 
     } 
    } 
    ); 


    param.addFrequencyListener(new ChangeListener() 
    { 
     public void stateChanged(ChangeEvent f) 
     { 
      double frValue = param.getFrequencyValue(); 
      fValue.setText(String.valueOf(frValue)); 
     } 
    } 
    ); 


    param.addPhaseListener(new ChangeListener() 
    { 
     public void stateChanged(ChangeEvent p) 
     { 
      double phValue = param.getPhaseValue(); 
      pValue.setText(String.valueOf(phValue)); 
     } 
    } 
    ); 

    playSound.addActionListener(this); 
    getPlot.addActionListener(this); 
    getSample.addActionListener(this); 

    mainMenu.add(langMenu); 
    slidersPanel.add(param); 
    subPanel.add(buttonsPanel, BorderLayout.NORTH); 
    subPanel.add(slidersPanel, BorderLayout.SOUTH); 
    mainPanel.add(subPanel); 
    mainPanel.add(plot); 
    add(mainPanel); 


} 

public void actionPerformed(ActionEvent a) 
{ 
    Object button = a.getSource(); 

    if(button==playSound) 
     try 
     { 
      Audio.playChord(frequencies); 
     } 

     catch (LineUnavailableException e) 
     { 
      System.out.println("Error"); 
     } 
} 

public JMenuBar getmainMenu() 
{ 
    return mainMenu; 
} 

private static void GUI() 
{ 
    Window mainPanel = new Window(); 
    JFrame frame = new JFrame(); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame.getContentPane().add(mainPanel); 
    frame.setJMenuBar(mainPanel.getmainMenu()); 
    frame.pack(); 
    frame.setVisible(true); 
    Menu theme = new Menu(); 
    theme.setVisible(true); 
    theme.pack(); 
} 

public static void main(String[] args) 
{ 
    SwingUtilities.invokeLater(new Runnable() 
    { 
     public void run() 
     { 
      GUI(); 
     } 
     } 
    ); 
} 
} 

這是我定義按鈕時的地方,actionlisteners。由於我的聲望太低以至於無法發佈圖像,所以我無法向您展示完整的GUI。發佈所有課程太困難。

回答

1

您需要做的一件事是修改playChord方法,以便它接受您的頻率數組(您以某種方式從用戶中檢索到)。您可能會使用類似以下的內容。這幾乎和你現在做的一樣,除了使用數組而不是硬編碼的abc

public static void playChord(double[] frequencies) 
    throws LineUnavailableException 
{ 
    double[] buffer = tone(frequencies[0], 1.0, 1, 0); 

    for(int i = 1; i < frequencies.length; ++i) { 
     double[] harmonic = tone(frequencies[i], 1.0, 1, 0); 

     for(int i = 0; i < buffer.length; ++i) { 
      buffer[i] += harmonic[i]; 
     } 
    } 

    for(int i = 0; i < buffer.length; ++i) { 
     buffer[i] /= frequencies.length; 
    } 

    Audio.play(buffer); 
} 

所以,順其自然。我不確定你是否意味着用戶應該選擇一個音符,然後再彈奏3個和絃的相應音符。 (例如,用戶選擇C,其播放主要黑社會的註釋C,EG。)

tone box

import java.util.*; 
import javax.swing.*; 
import java.awt.BorderLayout; 

class ToneBox implements Runnable { 
    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new ToneBox()); 
    } 

    enum Tone { 
     C(261.6), 
     CSHARP(277.2), 
     D(293.7), 
     DSHARP(311.2), 
     E(329.6), 
     F(349.6), 
     FSHARP(370), 
     G(391.9), 
     GSHARP(415.3), 
     A(440), 
     ASHARP(466.2), // note: there was an error here 
     B(493.9);  // A -> A# -> B, not A -> B -> H 

     final double hz; 

     Tone(double hz) { 
      this.hz = hz; 
     } 

     double[] triad() { 
      List<Tone> values = Arrays.asList(Tone.values()); 
      double[] chord = new double[3]; 

      int myIndex = values.indexOf(this); 

      // form a triad using the intervals 
      // as relative indexes in to the list 
      chord[0] = this.hz; 
      chord[1] = values.get((myIndex + 4) % values.size()).hz; 
      chord[2] = values.get((myIndex + 7) % values.size()).hz; 

      return chord; 
     } 

     // override toString, which JComboBox 
     // uses to display, so we can put 
     // Tone objects in the box directly 

     @Override 
     public String toString() { 
      return this.name().replace("SHARP", "#"); 
     } 
    } 

    @Override 
    public void run() { 
     final JFrame frame = new JFrame(); 
     final JPanel content = new JPanel(new BorderLayout()); 
     final JComboBox box = new JComboBox(Tone.values()); 
     final JButton button = new JButton("Play"); 

     button.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent ae) { 
       // overriding toString makes it much 
       // easier for us to retrieve the 
       // enum values from the JComboBox 

       Tone tone = (Tone)box.getSelectedItem(); 
       double[] chord = tone.triad(); 

       JOptionPane.showMessageDialog(null, 
        "Chord selected: " + Arrays.toString(chord) 
       ); 
      } 
     }); 

     content.add(box, BorderLayout.CENTER); 
     content.add(button, BorderLayout.SOUTH); 

     frame.setContentPane(content); 
     frame.pack(); 
     frame.setResizable(false); 
     frame.setLocationRelativeTo(null); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setVisible(true); 
    } 
} 

如果你的想法是,用戶單獨選擇的和絃的音符,您也可以考慮使用JList爲這種事情。只是一個建議。 JList允許用戶選擇多個項目。

tone list

import java.util.*; 
import javax.swing.*; 
import java.awt.BorderLayout; 

class ToneList implements Runnable { 
    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new ToneList()); 
    } 

    enum Tone {…} // same as above 

    @Override 
    public void run() { 
     final JFrame frame = new JFrame(); 
     final JPanel content = new JPanel(new BorderLayout()); 
     final JList  list = new JList(Tone.values()); 
     final JButton button = new JButton("Play"); 

     button.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent ae) { 
       Object[] values = list.getSelectedValues(); 
       double[] chord = new double[values.length]; 

       for(int i = 0; i < chord.length; ++i) { 
        Tone tone = (Tone)values[i]; 
        chord[i] = tone.hz; 
       } 

       JOptionPane.showMessageDialog(null, 
        "Chord selected: " + Arrays.toString(chord) 
       ); 
      } 
     }); 

     content.add(list, BorderLayout.CENTER); 
     content.add(button, BorderLayout.SOUTH); 

     frame.setContentPane(content); 
     frame.pack(); 
     frame.setResizable(false); 
     frame.setLocationRelativeTo(null); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setVisible(true); 
    } 
} 

我希望這給你一些想法,以填補你錯過了什麼。

+0

嗨,非常感謝您的回覆。你的第一個例子看起來就像我需要的,我會在一分鐘內嘗試一下 – Colonder 2015-04-04 12:20:14

+0

我剛剛發佈了我的主要功能。問題是我在那裏定義了所有的按鈕actionlisteners。說實話,我們應該在大學裏寫一個這樣的程序作爲一個項目,而不需要任何Java的知識。當然,我們有講座和實驗室,但它們非常混亂,以至於無論如何我都無法學到任何東西。 – Colonder 2015-04-04 13:22:14

+0

具體有什麼問題?既然你在Chords類中有一個私有的JComboBox,如果你想在其他地方添加一個動作監聽器,你需要公開它。假設你有一些類似'aButton.addActionListener(new ActionListener(){public void actionPerformed(...){JComboBox box = music.getComboBox(); ...}})'的代碼。希望有所幫助。如果您需要超出此問題的原始範圍,您可能會考慮提出一個新問題。 – Radiodef 2015-04-04 15:29:39

0

如果你願意,你可以讓你的枚舉成爲主類,然後讓它返回一個用於組合框的字符串列表,獲取音調和所有內容。把它當作你的「數據庫」類。然後讓其他人請求來自它的數據並對這些值進行操作。對於「全局」函數(不是針對枚舉的一個實例,例如「Tones.C.function()」,而是「Tones.function()」),使用靜態函數。

相關問題