2015-04-03 169 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()”),使用静态函数。