/* Author: James Pate Williams (c) 2001 Noise based music from _Elements of Computer Music_ by F. Richard Moore (c) 1990 pages 442 - 453 */ import java.awt.*; import java.awt.event.*; import java.util.*; import javax.sound.midi.*; import javax.swing.*; import javax.swing.border.*; import javax.swing.table.*; import javax.swing.event.*; /* * @(#)MidiSynth.java 1.15 99/12/03 * * Copyright (c) 1999 Sun Microsystems, Inc. All Rights Reserved. * * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use, * modify and redistribute this software in source and binary code form, * provided that i) this copyright notice and license appear on all copies of * the software; and ii) Licensee does not utilize the software in a manner * which is disparaging to Sun. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * * This software is not designed or intended for use in on-line control of * aircraft, air traffic, aircraft navigation or aircraft communications; or in * the design, construction, operation or maintenance of any nuclear * facility. Licensee represents and warrants that it will not use or * redistribute the Software for such purposes. */ /** * Table for 128 general MIDI melody instuments. */ class InstrumentsTable extends JPanel { private String names[] = { "Piano", "Chromatic Perc.", "Organ", "Guitar", "Bass", "Strings", "Ensemble", "Brass", "Reed", "Pipe", "Synth Lead", "Synth Pad", "Synth Effects", "Ethnic", "Percussive", "Sound Effects" }; private int col = 0, row = 0; private int nRows = 8; private int nCols = names.length; // just show 128 instruments // Pate added the following private data private String[] instrument = new String[128]; private Synthesizer synthesizer; private JTable table; public InstrumentsTable() { instrument[0] = "Piano"; instrument[1] = "Bright Piano"; instrument[2] = "Electric Grand"; instrument[3] = "Honky Tonk Piano"; instrument[4] = "Electric Piano 1"; instrument[5] = "Electric Piano 2"; instrument[6] = "Harpsichord"; instrument[7] = "Clavinet"; instrument[8] = "Celesta"; instrument[9] = "Glockenspiel"; instrument[10] = "Music Box"; instrument[11] = "Vibraphone"; instrument[12] = "Marimba"; instrument[13] = "Xylophone"; instrument[14] = "Tubular Bell"; instrument[15] = "Dulcimer"; instrument[16] = "Hammond Organ"; instrument[17] = "Perc Organ"; instrument[18] = "Rock Organ"; instrument[19] = "Church Organ"; instrument[20] = "Reed Organ"; instrument[21] = "Accordion"; instrument[22] = "Harmonica"; instrument[23] = "Tango Accordion"; instrument[24] = "Nylon Str Guitar"; instrument[25] = "Steel String Guitar"; instrument[26] = "Jazz Electric Gtr"; instrument[27] = "Clean Guitar"; instrument[28] = "Muted Guitar"; instrument[29] = "Overdrive Guitar"; instrument[30] = "Distortion Guitar"; instrument[31] = "Guitar Harmonics"; instrument[32] = "Acoustic Bass"; instrument[33] = "Fingered Bass"; instrument[34] = "Picked Bass"; instrument[35] = "Fretless Bass"; instrument[36] = "Slap Bass 1"; instrument[37] = "Slap Bass 2"; instrument[38] = "Syn Bass 1"; instrument[39] = "Syn Bass 2"; instrument[40] = "Violin"; instrument[41] = "Viola"; instrument[42] = "Cello"; instrument[43] = "Contrabass"; instrument[44] = "Tremolo Strings"; instrument[45] = "Pizzicato Strings"; instrument[46] = "Orchestral Harp"; instrument[47] = "Timpani"; instrument[48] = "Ensemble Strings"; instrument[49] = "Slow Strings"; instrument[50] = "Synth Strings 1"; instrument[51] = "Synth Strings 2"; instrument[52] = "Choir Aahs"; instrument[53] = "Voice Oohs"; instrument[54] = "Syn Choir"; instrument[55] = "Orchestra Hit"; instrument[56] = "Trumpet"; instrument[57] = "Trombone"; instrument[58] = "Tuba"; instrument[59] = "Muted Trumpet"; instrument[60] = "French Horn"; instrument[61] = "Brass Ensemble"; instrument[62] = "Syn Brass 1"; instrument[63] = "Syn Brass 2"; instrument[64] = "Soprano Sax"; instrument[65] = "Alto Sax"; instrument[66] = "Tenor Sax"; instrument[67] = "Baritone Sax"; instrument[68] = "Oboe"; instrument[69] = "English Horn"; instrument[70] = "Bassoon"; instrument[71] = "Clarinet"; instrument[72] = "Piccolo"; instrument[73] = "Flute"; instrument[74] = "Recorder"; instrument[75] = "Pan Flute"; instrument[76] = "Bottle Blow"; instrument[77] = "Shakuhachi"; instrument[78] = "Whistle"; instrument[79] = "Ocarina"; instrument[80] = "Syn Square Wave"; instrument[81] = "Syn Saw Wave"; instrument[82] = "Syn Calliope"; instrument[83] = "Syn Chiff"; instrument[84] = "Syn Charang"; instrument[85] = "Syn Voice"; instrument[86] = "Syn Fifths Saw"; instrument[87] = "Syn Brass and Lead"; instrument[88] = "Fantasia"; instrument[89] = "Warm Pad"; instrument[90] = "Polysynth"; instrument[91] = "Space Vox"; instrument[92] = "Bowed Glass"; instrument[93] = "Metal Pad"; instrument[94] = "Halo Pad"; instrument[95] = "Sweep Pad"; instrument[96] = "Ice Rain"; instrument[97] = "Soundtrack"; instrument[98] = "Crystal"; instrument[99] = "Atmosphere"; instrument[100] = "Brightness"; instrument[101] = "Goblins"; instrument[102] = "Echo Drops"; instrument[103] = "Sci Fi"; instrument[104] = "Sitar"; instrument[105] = "Banjo"; instrument[106] = "Shamisen"; instrument[107] = "Koto"; instrument[108] = "Kalimba"; instrument[109] = "Bag Pipe"; instrument[110] = "Fiddle"; instrument[111] = "Shanai"; instrument[112] = "Tinkle Bell"; instrument[113] = "Agogo"; instrument[114] = "Steel Drums"; instrument[115] = "Woodblock"; instrument[116] = "Taiko Drum"; instrument[117] = "Melodic Tom"; instrument[118] = "Syn Drum"; instrument[119] = "Reverse Cymbal"; instrument[120] = "Guitar Fret Noise"; instrument[121] = "Breath Noise"; instrument[122] = "Seashore"; instrument[123] = "Bird"; instrument[124] = "Telephone"; instrument[125] = "Helicopter"; instrument[126] = "Applause"; instrument[127] = "Gunshot"; setLayout(new BorderLayout()); TableModel dataModel = new AbstractTableModel() { public int getColumnCount() { return nCols; } public int getRowCount() { return nRows;} public Object getValueAt(int r, int c) { if (instrument != null) { return instrument[c*nRows+r]; } else { return Integer.toString(c*nRows+r); } } public String getColumnName(int c) { return names[c]; } public Class getColumnClass(int c) { return getValueAt(0, c).getClass(); } public boolean isCellEditable(int r, int c) {return false;} public void setValueAt(Object obj, int r, int c) {} }; table = new JTable(dataModel); table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); ListSelectionModel lsm = table.getSelectionModel(); // Listener for row changes //ListSelectionModel lsm = table.getSelectionModel(); lsm.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { ListSelectionModel sm = (ListSelectionModel) e.getSource(); if (!sm.isSelectionEmpty()) { row = sm.getMinSelectionIndex(); } programChange(col*nRows+row); } }); // Listener for column changes lsm = table.getColumnModel().getSelectionModel(); lsm.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { ListSelectionModel sm = (ListSelectionModel) e.getSource(); if (!sm.isSelectionEmpty()) { col = sm.getMinSelectionIndex(); } programChange(col*nRows+row); } }); table.setPreferredScrollableViewportSize(new Dimension(nCols*110, 200)); table.setCellSelectionEnabled(true); table.setColumnSelectionAllowed(true); for (int i = 0; i < names.length; i++) { TableColumn column = table.getColumn(names[i]); column.setPreferredWidth(110); } table.setAutoResizeMode(table.AUTO_RESIZE_OFF); JScrollPane sp = new JScrollPane(table); sp.setVerticalScrollBarPolicy(sp.VERTICAL_SCROLLBAR_NEVER); sp.setHorizontalScrollBarPolicy(sp.HORIZONTAL_SCROLLBAR_ALWAYS); add(sp); } public Dimension getPreferredSize() { return new Dimension(800,170); } public Dimension getMaximumSize() { return new Dimension(800,170); } private void programChange(int program) { if (synthesizer != null) { //synthesizer.loadInstrument(instruments[program]); // Pate added the next three lines MidiChannel midiChannels[] = synthesizer.getChannels(); for (int i = 0; i < midiChannels.length; i++) midiChannels[i].programChange(program); } /*cc.channel.programChange(program); if (record) { createShortEvent(PROGRAM, program); }*/ } // Pate added this method String[] getInstrument() { return instrument; } void setData(Synthesizer s) { synthesizer = s; } public void initTable() { ListSelectionModel lsm = table.getSelectionModel(); lsm.setSelectionInterval(0,0); lsm = table.getColumnModel().getSelectionModel(); lsm.setSelectionInterval(0,0); } } // end InstrumentsTable /** * A collection of MIDI controllers. */ class Controls extends JPanel implements /*ActionListener,*/ ChangeListener, ItemListener { //public JButton recordB; //JMenu menu; //int fileNum = 0; final int REVERB = 91; int beats = 108, velocity = 64; JCheckBox soloCB, monoCB, muteCB/*, sustCB*/; JSlider veloS, presS, bendS, revbS, beatS; MidiChannel midiChannel; public Controls() { setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); setBorder(new EmptyBorder(5,10,5,10)); JPanel p = new JPanel(); p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS)); veloS = createSlider("Velocity", p, 0, 127, 64); presS = createSlider("Pressure", p, 0, 127, 64); revbS = createSlider("Reverb", p, 0, 127, 64); beatS = createSlider("BPM", p, 40, 208, beats); // create a slider with a 14-bit range of values for pitch-bend bendS = create14BitSlider("Bend", p); p.add(Box.createHorizontalStrut(10)); add(p); p = new JPanel(); p.setBorder(new EmptyBorder(10,0,10,0)); p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS)); /*JComboBox combo = new JComboBox(); combo.setPreferredSize(new Dimension(120,25)); combo.setMaximumSize(new Dimension(120,25)); for (int i = 1; i <= 16; i++) { combo.addItem("Channel " + String.valueOf(i)); } combo.addItemListener(this); p.add(combo); p.add(Box.createHorizontalStrut(20));*/ muteCB = createCheckBox("Mute", p); soloCB = createCheckBox("Solo", p); monoCB = createCheckBox("Mono", p); //sustCB = createCheckBox("Sustain", p); /*createButton("All Notes Off", p); p.add(Box.createHorizontalStrut(10)); p.add(mouseOverCB); p.add(Box.createHorizontalStrut(10)); recordB = createButton("Record...", p); add(p);*/ } /*public JButton createButton(String name, JPanel p) { JButton b = new JButton(name); b.addActionListener(this); p.add(b); return b; }*/ private JCheckBox createCheckBox(String name, JPanel p) { JCheckBox cb = new JCheckBox(name); cb.addItemListener(this); p.add(cb); return cb; } private JSlider createSlider(String name, JPanel p, int min, int max, int value) { JSlider slider = new JSlider(JSlider.HORIZONTAL, min, max, value); slider.addChangeListener(this); TitledBorder tb = new TitledBorder(new EtchedBorder()); tb.setTitle(name + " = " + Integer.toString(value)); slider.setBorder(tb); p.add(slider); p.add(Box.createHorizontalStrut(5)); return slider; } private JSlider create14BitSlider(String name, JPanel p) { JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 16383, 8192); slider.addChangeListener(this); TitledBorder tb = new TitledBorder(new EtchedBorder()); tb.setTitle(name + " = 8192"); slider.setBorder(tb); p.add(slider); p.add(Box.createHorizontalStrut(5)); return slider; } public void stateChanged(ChangeEvent e) { JSlider slider = (JSlider) e.getSource(); int value = slider.getValue(); TitledBorder tb = (TitledBorder) slider.getBorder(); String s = tb.getTitle(); tb.setTitle(s.substring(0, s.indexOf('=')+1) + s.valueOf(value)); if (s.startsWith("Velocity")) { velocity = value; } else if (s.startsWith("Pressure")) { midiChannel.setChannelPressure(value); } else if (s.startsWith("Bend")) { midiChannel.setPitchBend(value); } else if (s.startsWith("Reverb")) { midiChannel.controlChange(REVERB, value); } else if (s.startsWith("BPM")) { beats = value; } slider.repaint(); } public void itemStateChanged(ItemEvent e) { /*if (e.getSource() instanceof JComboBox) { JComboBox combo = (JComboBox) e.getSource(); cc = channels[combo.getSelectedIndex()]; cc.setComponentStates(); } else {*/ JCheckBox cb = (JCheckBox) e.getSource(); String name = cb.getText(); if (name.startsWith("Mute")) { midiChannel.setMute(/*cc.mute = */cb.isSelected()); } else if (name.startsWith("Solo")) { midiChannel.setSolo(/*cc.solo = */cb.isSelected()); } else if (name.startsWith("Mono")) { midiChannel.setMono(/*cc.mono = */cb.isSelected()); }/* else if (name.startsWith("Sustain")) { cc.sustain = cb.isSelected(); cc.channel.controlChange(SUSTAIN, cc.sustain ? 127 : 0); }*/ //} } /*public void actionPerformed(ActionEvent e) { JButton button = (JButton) e.getSource(); if (button.getText().startsWith("All")) { for (int i = 0; i < channels.length; i++) { channels[i].channel.allNotesOff(); } for (int i = 0; i < keys.size(); i++) { ((Key) keys.get(i)).setNoteState(OFF); } } else if (button.getText().startsWith("Record")) { if (recordFrame != null) { recordFrame.toFront(); } else { recordFrame = new RecordFrame(); } } }*/ // Pate added the following methods public int getBeats() { return beats; } public int getVelocity() { return velocity; } public void setMidiChannel(MidiChannel mc) { midiChannel = mc; } } // End class Controls // end of Sun's contribution to the program class NoiseMusicPanel extends JPanel { int deltaX, deltaY, number; int x0, x1, y0, y1, y2, y3; int[] note, duration; Color penColor; public NoiseMusicPanel(int iWidth, int iHeight) { number = 0; x0 = iWidth / 16; x1 = 15 * x0; y0 = iHeight / 24; y1 = 2 * y0; deltaY = (y1 - y0) / 4; } public void paintComponent(Graphics g) { super.paintComponent(g); penColor = g.getColor(); y2 = y0; y3 = y1; drawStaff(0, number/ 2, g); y2 += 10 * deltaY; y3 = y2 + 4 * deltaY; drawStaff(number / 2, number, g); } public boolean sharp(int iNote) { boolean s = false; int[] sharps = {61, 63, 66, 68, 70, 73, 75, 78}; for (int i = 0; i < sharps.length; i++) { if (iNote == sharps[i]) { s = true; break; } } return s; } int delta(int iNote) { if (iNote == 79) return 0; if (iNote == 77 || iNote == 78) return 1; if (iNote == 76) return 2; if (iNote == 74 || iNote == 75) return 3; if (iNote == 72 || iNote == 73) return 4; if (iNote == 71) return 5; if (iNote == 69 || iNote == 70) return 6; if (iNote == 67 || iNote == 68) return 7; if (iNote == 65 || iNote == 66) return 8; if (iNote == 64) return 9; if (iNote == 62 || iNote == 63) return 10; else return 11; } public void drawSharp(int iNote, int x, int y, Graphics g) { if (sharp(iNote)) { g.drawLine(x - deltaX / 4 - 2, y - deltaY / 4, x - deltaX / 4 - 2, y + deltaY / 4); g.drawLine(x - deltaX / 4 - 4, y - deltaY / 4, x - deltaX / 4 - 4, y + deltaY / 4); g.drawLine(x - deltaX / 4 - 5, y - deltaY / 8, x - deltaX / 4 - 1, y - deltaY / 8); g.drawLine(x - deltaX / 4 - 5, y + deltaY / 8, x - deltaX / 4 - 1, y + deltaY / 8); } } public void durationCase(int iDuration, int x, int y, Graphics g) { switch (iDuration) { case 0: // whole note g.drawArc(x, y, deltaX, deltaY, 0, 360); break; case 1: // half note g.fillArc(x, y, deltaX, deltaY, 0, 360); break; case 2: // quarter note g.fillArc(x, y, deltaX, deltaY, 0, 360); g.drawLine(x + deltaX, y + deltaY / 2, x + deltaX, y - 2 * deltaY); break; case 3: // eighth note g.fillArc(x, y, deltaX, deltaY, 0, 360); g.drawLine(x + deltaX, y + deltaY / 2, x + deltaX, y - 2 * deltaY); g.drawLine(x + deltaX, y - 2 * deltaY, x + deltaX + deltaX / 2, y - 2 * deltaY); break; } } public void drawStaff(int lo, int hi, Graphics g) { int i, j, n, x, y; y = y2; for (i = 0; i < 5; i++) { g.drawLine(x0, y, x1, y); y += deltaY; } g.drawLine(x0, y2, x0, y3); g.drawLine(x1, y2, x1, y3); if (lo == 0) deltaX = (x1 - x0) / (2 * (hi - lo) + 1); for (i = lo; i < hi; i++) { if (lo == 0) x = x0 + (2 * i + 1) * deltaX; else x = x0 + (2 * (i - lo) + 1) * deltaX; n = note[i]; if (n == - 1) { y = y2 + 3 * deltaY / 2; g.fillArc(x, y, deltaX / 2, deltaY / 2, 0, 360); g.drawLine(x + deltaX / 2, y + deltaY, x + deltaX / 2, y - deltaY); continue; } y = delta(n) * deltaY / 2 + y2 - deltaY; drawSharp(n, x, y, g); durationCase(duration[i], x, y, g); } } public void drawNote(boolean red, int i, int iNote, int iDuration) { int x, y, z; Graphics g = getGraphics(); if (red) g.setColor(Color.red); else g.setColor(penColor); if (i < number / 2) z = y0; else { i -= number / 2; z = y2; } x = x0 + (2 * i + 1) * deltaX; if (iNote == - 1) { y = z + 3 * deltaY / 2; g.fillArc(x, y, deltaX / 2, deltaY / 2, 0, 360); g.drawLine(x + deltaX / 2, y + deltaY, x + deltaX / 2, y - deltaY); return; } y = delta(iNote) * deltaY / 2 + z - deltaY; drawSharp(iNote, x, y, g); durationCase(iDuration, x, y, g); } public void setMusicAndDraw(int num, int[] not, int[] dur) { number = num; note = new int[number]; duration = new int[number]; for (int i = 0; i < number; i++) { note[i] = not[i]; duration[i] = dur[i]; } paintComponent(getGraphics()); } } class NoiseMusicFrame extends JFrame { double beta; int iHeight, iWidth, number; int[] duration, note; JButton jButton1 = new JButton(); JButton jButton2 = new JButton(); JPanel jPanel = new JPanel(); GridLayout gridLayout = new GridLayout(4, 1); Controls controls; Date date = new Date(); String[] instrument; InstrumentsTable instrumentsTable; MidiChannel[] midiChannels; Random random = new Random(date.getTime()); Receiver synthesizerReceiver; Synthesizer synthesizer; NoiseMusicPanel noiseMusicPanel; // step 3 - percentage size the window void setDesktopSize(JFrame frame, int wPerc, int hPerc) { Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); iWidth = screen.width * wPerc / 100; iHeight = screen.height * hPerc / 100; frame.setSize(iWidth, iHeight); } // step 4 - center the window void centerOnScreen(JFrame frame) { Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); Dimension window = frame.getSize(); int iCenterX = screen.width / 2; int iCenterY = screen.height / 2; frame.setLocation(iCenterX - window.width / 2, iCenterY - window.height / 2); } public NoiseMusicFrame(double b) { beta = b; number = 0; String title = "NoiseMusic by James Pate Williams, Jr. (c) 2002"; jButton1.setToolTipText("Generate white noise music"); jButton1.setText("Generate Notes"); jButton1.setVerticalAlignment(SwingConstants.BOTTOM); jButton1.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { jButton1_actionPerformed(e); } }); jButton2.setText("Play Notes"); jButton2.setVerticalAlignment(SwingConstants.BOTTOM); jButton2.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { jButton2_actionPerformed(e); } }); try { synthesizer = MidiSystem.getSynthesizer(); synthesizer.open(); midiChannels = synthesizer.getChannels(); for (int i = 0; i < midiChannels.length; i++) midiChannels[i].programChange(0); synthesizerReceiver = synthesizer.getReceiver(); } catch (Exception exception) { jButton2.setEnabled(false); } this.getContentPane().setLayout(gridLayout); setTitle(title); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent event) { synthesizer.close(); System.exit(0); } }); setDesktopSize(this, 100, 100); centerOnScreen(this); controls = new Controls(); controls.setMidiChannel(midiChannels[0]); Container contentPane = getContentPane(); jPanel.add(controls, BorderLayout.CENTER); jPanel.add(jButton1, BorderLayout.EAST); jPanel.add(jButton2, BorderLayout.WEST); noiseMusicPanel = new NoiseMusicPanel(iWidth, iHeight); instrumentsTable = new InstrumentsTable(); instrumentsTable.initTable(); instrument = instrumentsTable.getInstrument(); jButton2.setToolTipText(instrument[0]); instrumentsTable.setData(synthesizer); contentPane.add(noiseMusicPanel); contentPane.add(controls); contentPane.add(instrumentsTable); contentPane.add(jPanel); this.show(); } public int iRandom(int lo, int hi) { return random.nextInt(hi - lo + 1) + lo; } class Complex { public double re, im; public Complex(double r, double i) { re = r; im = i; } } void dft(double[] x, int N, Complex[] X) { double pi2oN = 2.0 * Math.PI / N; int k, n; for (k = 0; k < N; k++) { X[k] = new Complex(0.0, 0.0); for (n = 0; n < N; n++) { X[k].re += x[n] * Math.cos(pi2oN * k * n); X[k].im -= x[n] * Math.sin(pi2oN * k * n); } X[k].re /= N; X[k].im /= N; } } boolean inverseDFT(double[] x, int N, Complex[] X) { double imag, pi2oN = 2.0 * Math.PI / N; int k, n; for (n = 0; n < N; n++) { imag = x[n] = 0.0; for (k = 0; k < N; k++) { x[n] += X[k].re * Math.cos(pi2oN * k * n) - X[k].im * Math.sin(pi2oN * k * n); imag += X[k].re * Math.sin(pi2oN * k * n) + X[k].im * Math.cos(pi2oN * k * n); } if (Math.abs(imag) > 1.0e-5) return false; } return true; } double dRandom(double min, double max) { return random.nextDouble() * (max - min) + min; } void shapedNoise(double min, double max, double[] x, int N) { double amplitude, nMax, nMin, phase, power; int i; Complex[] X = new Complex[N]; for (i = 0; i < N; i++) x[i] = dRandom(- 1.0, + 1.0); dft(x, N, X); for (i = 1; i <= N / 2; i++) { power = X[i].re * X[i].re + X[i].im * X[i].im; phase = Math.atan2(X[i].im, X[i].re); power /= Math.pow((double) i, beta); amplitude = Math.sqrt(power); X[i].re = amplitude * Math.cos(phase); X[i].im = amplitude * Math.sin(phase); } for (i = 1; i <= N / 2; i++) { X[N - i].re = X[i].re; X[N - i].im = - X[i].im; } inverseDFT(x, N, X); nMax = nMin = x[0]; for (i = 1; i < N; i++) { if (x[i] > nMax) nMax = x[i]; if (x[i] < nMin) nMin = x[i]; } for (i = 0; i < N; i++) x[i] = (max - min) * (x[i] - nMin) / (nMax - nMin) + min; } void jButton1_actionPerformed(ActionEvent e) { double[] x; number = 48; x = new double[number]; duration = new int[number]; note = new int[number]; shapedNoise(0.0, 19.0, x, number); for (int i = 0; i < number; i++) { duration[i] = 2; note[i] = (int) (x[i] + 60.0); } noiseMusicPanel.setMusicAndDraw(number, note, duration); } void jButton2_actionPerformed(ActionEvent e) { int beats = controls.getBeats(); int volume = controls.getVelocity(); try { for (int i = 0; i < number; i++) { ShortMessage shortMessage = new ShortMessage(); if (note[i] != - 1) { shortMessage.setMessage(ShortMessage.NOTE_ON, 0, note[i], volume); synthesizerReceiver.send(shortMessage, - 1); } int time = (int) (60000.0 / beats); noiseMusicPanel.drawNote(true, i, note[i], duration[i]); Thread.sleep(time); shortMessage = new ShortMessage(); if (note[i] != - 1) { shortMessage.setMessage(ShortMessage.NOTE_OFF, 0, note[i], volume); synthesizerReceiver.send(shortMessage, - 1); } noiseMusicPanel.drawNote(false, i, note[i], duration[i]); } } catch (Exception exception) { System.exit(0); } } } class NoiseMusic { public static void main(String[] args) { if (args.length != 1) { System.err.println("usage: NoiseMusic beta"); System.err.println("where the noise is of the type 1 / pow(f, beta) 0 <= beta <= 2"); System.exit(1); } double beta = Double.parseDouble(args[0]); if (beta < 0.0 || beta > 2.0) { System.err.println("error: illegal value of beta not in range 0 <= beta <= 2"); System.exit(1); } new NoiseMusicFrame(beta); } }