package com.eatenalive3.midiplayer; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.io.File; import java.io.UnsupportedEncodingException; import java.net.URISyntaxException; import javax.sound.midi.MidiSystem; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSlider; import javax.swing.JTextArea; import javax.swing.KeyStroke; import javax.swing.ScrollPaneConstants; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.UIManager.LookAndFeelInfo; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.border.EtchedBorder; import javax.swing.border.TitledBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.plaf.basic.BasicSliderUI; public class MidiPlayer { private static boolean mouseDown = false; public static RenderSong rs = new RenderSong(); private JFrame frame; private JTextArea room; private File currentMid; public static JSlider trackPosition; private static JButton play; private JSlider tempo; private JSlider transpose; private JCheckBox backwards; private JCheckBox sustain; private JCheckBox invertRound; private JCheckBox invert; private JCheckBox multipleNotes; public static JTextArea console; public static BotSocket currentSocket = null; private String currentRoom = null; public static Play currentSong = null; public static void main(String args[]) { try { for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { if ("Nimbus".equals(info.getName())) { UIManager.setLookAndFeel(info.getClassName()); break; } } } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) { e.printStackTrace(); } try { Play.synthesizer = MidiSystem.getSynthesizer(); Play.synthesizer.open(); Play.synthesizer.getChannels()[0].programChange(Play.synthesizer.getAvailableInstruments()[0].getPatch().getProgram()); Play.piano = Play.synthesizer.getChannels()[0]; } catch (Exception e) {} MidiPlayer gui = new MidiPlayer(); gui.setUpGUI(); console.setText("MidiPlayer BETA v2023.10.10 (jacolantern edition) started. Coded by Boss :P"); log("Remember to connect to a room first!"); } public void setUpGUI() { frame = new JFrame("MultiplayerPiano Midi Player BETA"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(670, 700); frame.setLocationRelativeTo(null); JPanel pane = new JPanel(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); frame.add(pane); new FileDrop(pane, new FileDrop.Listener() { public void filesDropped(File[] files) { for (File file : files) { try { MidiSystem.getSequence(file); currentMid = file; resetPlay(); log("Successfully loaded " + file.getName()); return; } catch (Exception e) { } } log("Could not load any midis from the dropped files."); } }); JButton choose = new JButton("Choose File (or drag&drop)"); choose.addActionListener(new Choose()); final JButton connect = new JButton("Connect"); connect.addActionListener(new Connect()); final String defaultText = "Room name or URL"; room = new JTextArea(defaultText, 1, 30); room.setMinimumSize(new Dimension(1, 25)); room.setPreferredSize(new Dimension(1, 30)); room.setFocusable(false); room.addKeyListener(new KeyListener() { @Override public void keyPressed(KeyEvent arg0) { if (arg0.getKeyCode() == KeyEvent.VK_ENTER) { connect.getActionListeners()[0].actionPerformed(null); } } @Override public void keyReleased(KeyEvent arg0) { // TODO Auto-generated method stub } @Override public void keyTyped(KeyEvent arg0) { // TODO Auto-generated method stub } }); room.addMouseListener(new MouseListener() { @Override public void mouseClicked(MouseEvent arg0) { } @Override public void mouseEntered(MouseEvent arg0) { } @Override public void mouseExited(MouseEvent arg0) { } @Override public void mousePressed(MouseEvent arg0) { if (room.getText().equals(defaultText)) { room.setText(""); } } @Override public void mouseReleased(MouseEvent arg0) { } }); room.getInputMap().put(KeyStroke.getKeyStroke("ENTER"), "none"); // blocks enter from having an effect but still works with keyListener JPanel roomPanel = new JPanel(new GridBagLayout()); c.gridy = 0; c.gridx = 0; c.gridwidth = 1; c.fill = GridBagConstraints.BOTH; roomPanel.add(new JLabel("Room Name: "), c); JPanel roomPan = new JPanel(); roomPan.add(room); c.fill = GridBagConstraints.HORIZONTAL; c.gridx = 1; roomPanel.add(roomPan, c); c.gridwidth = 1; c.gridx = 0; c.gridy = 1 + 1; c.weightx = .1; c.fill = GridBagConstraints.HORIZONTAL; pane.add(roomPanel, c); c.gridy = 0; JPanel topSlider = new JPanel(new BorderLayout()); transpose = new JSlider() { { MouseListener[] listeners = getMouseListeners(); for (MouseListener l : listeners) removeMouseListener(l); // remove UI-installed TrackListener final BasicSliderUI ui = (BasicSliderUI) getUI(); BasicSliderUI.TrackListener tl = ui.new TrackListener() { // this is where we jump to absolute value of click @Override public void mouseClicked(MouseEvent e) { Point p = e.getPoint(); int value = ui.valueForXPosition(p.x); setValue(value); } // disable check that will invoke scrollDueToClickInTrack @Override public boolean shouldScroll(int dir) { return false; } }; addMouseListener(tl); } }; transpose.setMinimum(-12); transpose.setMaximum(12); transpose.setMajorTickSpacing(12); transpose.setMinorTickSpacing(1); transpose.setPaintLabels(true); transpose.setPaintTicks(true); transpose.setValue(0); transpose.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent arg0) { if (currentSong != null) currentSong.transpose = transpose.getValue(); Play.pix = new int[RenderSong.HEIGHT]; } }); topSlider.add(transpose, BorderLayout.SOUTH); topSlider.setBorder(new TitledBorder(new EtchedBorder(), "Transpose")); c.gridwidth = 3; pane.add(topSlider, c); c.gridy = 2; c.fill = GridBagConstraints.CENTER; c.gridx = 1; c.gridwidth = 1; c.weightx = .9; pane.add(connect, c); // pane.add(javax.swing.Box.createGlue(), c); JPanel selectButtons = new JPanel(); play = new JButton("Play"); play.addActionListener(new Playing()); selectButtons.add(choose); backwards = new JCheckBox("Backwards"); backwards.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { Play.backwards = backwards.isSelected(); Play.pix = new int[RenderSong.HEIGHT]; } }); selectButtons.add(backwards); invert = new JCheckBox("Invert"); invert.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { Play.invert = invert.isSelected(); Play.pix = new int[RenderSong.HEIGHT]; } }); selectButtons.add(invert); sustain = new JCheckBox("Sustain"); sustain.setSelected(true); sustain.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { Play.sustain = !sustain.isSelected(); } }); selectButtons.add(sustain); invertRound = new JCheckBox("Invert: Round Down"); invertRound.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { Play.roundUpOrDown = invertRound.isSelected() ? -1 : 1; Play.pix = new int[RenderSong.HEIGHT]; } }); selectButtons.add(invertRound); final JCheckBox lessLag = new JCheckBox("Less lag"); lessLag.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { Play.lagBufferTime = lessLag.isSelected() ? 1000 : 100; } }); selectButtons.add(lessLag); c.gridx = 0; c.gridy = 1 + 2; c.weightx = 0; c.weighty = 0; c.gridwidth = 3; pane.add(selectButtons, c); c.gridy = 1 + 4; c.gridwidth = 3; c.weightx = 1; c.fill = GridBagConstraints.BOTH; JPanel tempoBar = new JPanel(); tempo = new JSlider() { { MouseListener[] listeners = getMouseListeners(); for (MouseListener l : listeners) removeMouseListener(l); // remove UI-installed TrackListener final BasicSliderUI ui = (BasicSliderUI) getUI(); BasicSliderUI.TrackListener tl = ui.new TrackListener() { // this is where we jump to absolute value of click @Override public void mouseClicked(MouseEvent e) { Point p = e.getPoint(); int value = ui.valueForXPosition(p.x); setValue(value); } // disable check that will invoke scrollDueToClickInTrack @Override public boolean shouldScroll(int dir) { return false; } }; addMouseListener(tl); } }; tempo.setMinimum(0); tempo.setMaximum(300); tempo.setValue(100); tempo.setMajorTickSpacing(100); tempo.setMinorTickSpacing(5); tempo.setPaintTicks(true); tempo.setSnapToTicks(true); tempo.setPaintLabels(true); tempo.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent arg0) { if (currentSong != null) currentSong.setTempo(tempo.getValue() / 100.0); } }); tempoBar.setLayout(new BorderLayout()); tempoBar.add(tempo); tempoBar.setBorder(new TitledBorder(new EtchedBorder(), "Tempo")); pane.add(tempoBar, c); c.gridy++; c.gridwidth = 3; c.weightx = 1; c.fill = GridBagConstraints.BOTH; JPanel multiPanel = new JPanel(); final JSlider multi = new JSlider() { { MouseListener[] listeners = getMouseListeners(); for (MouseListener l : listeners) removeMouseListener(l); // remove UI-installed TrackListener final BasicSliderUI ui = (BasicSliderUI) getUI(); BasicSliderUI.TrackListener tl = ui.new TrackListener() { // this is where we jump to absolute value of click @Override public void mouseClicked(MouseEvent e) { Point p = e.getPoint(); int value = ui.valueForXPosition(p.x); setValue(value); } // disable check that will invoke scrollDueToClickInTrack @Override public boolean shouldScroll(int dir) { return false; } }; addMouseListener(tl); } }; multi.setMinimum(1); multi.setMaximum(5); multi.setValue(0); multi.setMajorTickSpacing(1); multi.setPaintTicks(true); multi.setSnapToTicks(true); multi.setPaintLabels(true); multi.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent arg0) { Play.multipleNotes = multi.getValue() - 1; } }); multiPanel.setLayout(new BorderLayout()); multiPanel.add(multi); multiPanel.setBorder(new TitledBorder(new EtchedBorder(), "Multi-note")); pane.add(multiPanel, c); JPanel trackBar = new JPanel(); trackBar.setLayout(new BorderLayout()); c.gridy = 1 + 3; trackPosition = new JSlider() { { MouseListener[] listeners = getMouseListeners(); for (MouseListener l : listeners) removeMouseListener(l); // remove UI-installed TrackListener final BasicSliderUI ui = (BasicSliderUI) getUI(); BasicSliderUI.TrackListener tl = ui.new TrackListener() { // this is where we jump to absolute value of click @Override public void mouseClicked(MouseEvent e) { Point p = e.getPoint(); int value = ui.valueForXPosition(p.x); setValue(value); } // disable check that will invoke scrollDueToClickInTrack @Override public boolean shouldScroll(int dir) { return false; } }; addMouseListener(tl); } }; trackPosition.setMaximum(100); trackPosition.setMinimum(0); trackPosition.setValue(0); trackPosition.setMajorTickSpacing(50); trackPosition.setMinorTickSpacing(10); trackPosition.setPaintTicks(true); trackPosition.addMouseListener(new MouseListener() { @Override public void mouseClicked(MouseEvent arg0) { } @Override public void mouseEntered(MouseEvent arg0) { // TODO Auto-generated method stub } @Override public void mouseExited(MouseEvent arg0) { // TODO Auto-generated method stub } @Override public void mousePressed(MouseEvent arg0) { mouseDown = true; } @Override public void mouseReleased(MouseEvent arg0) { mouseDown = false; if (currentSong != null) currentSong.setPosition(trackPosition.getValue() / 100.0); Play.pix = new int[RenderSong.HEIGHT]; } }); trackBar.add(trackPosition, BorderLayout.NORTH); trackBar.setBorder(new EtchedBorder(EtchedBorder.RAISED)); JPanel buttons = new JPanel(); buttons.setLayout(new GridBagLayout()); GridBagConstraints cc = new GridBagConstraints(); JButton stop = new JButton("Stop"); stop.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { if (currentSong != null) { currentSong.stop(); trackPosition.setValue(0); play.setText("Play"); } } }); buttons.add(stop, cc); buttons.add(play, cc); trackBar.add(buttons); pane.add(trackBar, c); JPanel bottom = new JPanel(); bottom.setBorder(new TitledBorder(new EtchedBorder(), "Display")); console = new JTextArea(1, 0); console.setEditable(false); JScrollPane scroll = new JScrollPane(console); scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); scroll.setAutoscrolls(true); bottom.setLayout(new BorderLayout()); bottom.add(rs); c.weighty = 1; c.weightx = 1; c.fill = GridBagConstraints.BOTH; c.gridx = 0; c.gridwidth = 3; c.gridy = 7; // c.anchor = GridBagConstraints.SOUTH; pane.add(bottom, c); c.weighty = 0.3; JPanel consoleBottom = new JPanel(); consoleBottom.setBorder(new TitledBorder(new EtchedBorder(), "Console")); consoleBottom.setLayout(new BorderLayout()); consoleBottom.add(scroll); c.gridy++; pane.add(consoleBottom, c); frame.setVisible(true); SwingUtilities.invokeLater(new Runnable() { public void run() { room.setFocusable(true); } }); } public void getMidiFile() { JFileChooser chooser; if (currentMid == null) chooser = new JFileChooser(); else chooser = new JFileChooser(currentMid); FileNameExtensionFilter filter = new FileNameExtensionFilter("MIDI files", "mid", "midi"); chooser.setFileFilter(filter); int returnVal = chooser.showOpenDialog(frame); if (returnVal == JFileChooser.APPROVE_OPTION) { log("Loaded " + chooser.getSelectedFile().getName()); currentMid = chooser.getSelectedFile(); return; } log("Did not load any file. (approve option not pressed)"); } class Choose implements ActionListener { @Override public void actionPerformed(ActionEvent arg0) { getMidiFile(); } } class Playing implements ActionListener { @Override public void actionPerformed(ActionEvent arg0) { if (currentMid != null && currentRoom != null) { if (play.getText().equals("Play")) { play.setText("Pause"); try { new Thread(new Runnable() { public void run() { try { if (currentSong != null) currentSong.stop(); if (currentSong == null || !currentSong.mid.equals(currentMid)) currentSong = new Play(currentMid, null); currentSong.play(tempo.getValue() / 100.0, trackPosition.getValue() / 100.0, transpose.getValue()); // com.eatenalive3.midiplayer.Play.playSong(currentMid, 1, null, 0); } catch (Exception e) { log("Did not play mid. You are not connected to a room."); e.printStackTrace(); } finally { play.setText("Play"); } } }).start(); } catch (Exception e) { e.printStackTrace(); } } else { play.setText("Play"); if (currentSong == null) { log("No song loaded."); } else { currentSong.stop(); } } } else { if (currentMid == null) { log("Did not play mid:"); log("No midi file loaded!"); } else { log("Not connected to a room, so playing locally."); if (play.getText().equals("Play")) { play.setText("Pause"); try { new Thread(new Runnable() { public void run() { try { if (currentSong != null) currentSong.stop(); if (currentSong == null || !currentSong.mid.equals(currentMid)) currentSong = new Play(currentMid, null); currentSong.playLocally(tempo.getValue() / 100.0, trackPosition.getValue() / 100.0, transpose.getValue()); } catch (Exception e) { log("Did not play mid. You are not connected to a room."); e.printStackTrace(); } finally { play.setText("Play"); } } }).start(); } catch (Exception e) { e.printStackTrace(); } } else { play.setText("Play"); if (currentSong == null) { log("No song loaded."); } else { currentSong.stop(); } } } } } } class Connect implements ActionListener { @Override public void actionPerformed(ActionEvent arg0) { String text = room.getText(); String mpp = "www.multiplayerpiano.com/"; if (text.contains(mpp)) { text = text.substring(text.indexOf(mpp) + mpp.length()); } try { text = java.net.URLDecoder.decode(text, "UTF-8"); } catch (UnsupportedEncodingException e1) { e1.printStackTrace(); log(e1.toString()); } if (!text.equals(currentRoom)) { if (currentSocket != null) { currentSocket.send("[{\"m\":\"ch\",\"_id\":\"" + text + "\"}]"); } else { try { currentSocket = new BotSocket(text); } catch (URISyntaxException e) { e.printStackTrace(); log(e.toString()); } } currentRoom = text; log("Connected to " + text); } else { log("You are already connected to " + text); } } } public static void log(String s) { console.setText(console.getText() + "\n" + s); } public static void setSlider(double pos) { MidiPlayer.rs.update(Play.pix); MidiPlayer.rs.repaint(); if (!mouseDown && pos < 100) { trackPosition.setValue((int) pos); } } public static void resetPlay() { Play.pix = new int[RenderSong.HEIGHT]; if (currentSong != null) currentSong.stop(); play.setText("Play"); trackPosition.setValue(0); } }