2017-02-11 34 views
0

так что это мой самый первый пост, и мне очень жаль, если моя грамматика плохая (английский не мой родной язык). Недавно я начал программировать в Java, и я заинтересован в обучении. Поэтому я начал несколько небольших проектов, чтобы помочь мне понять больше основных вещей и улучшить свое кодирование.Действия перестают работать на Java

Недавно я прочитал про keyListeners, keyBindings и все такое. Так я думал, что я закодировать очень основную программу (почти полное отсутствие GUI), который должен работать как простой фортепиано:

import javax.sound.sampled.AudioSystem; 
import javax.sound.sampled.Clip; 
import java.awt.*; 
import java.io.File; 
import javax.swing.*; 

import java.awt.event.*; 

public class pianl1 { 


    public static void main (String[] args){ 
     int i= 0; 

     File C7 = new File("res/39191__jobro__piano-ff-044.wav"); 
     File D7 = new File ("res/39194__jobro__piano-ff-046.wav"); 

     JLabel lab1 =new JLabel("Hallo"); 
     frame.add(lab1); 


     AbstractAction keyBindingReactorC7 = new AbstractAction(){ 
      @Override 
      public void actionPerformed(ActionEvent e){ 
       Playsound(C7); 
      } 
     }; 
     AbstractAction keyBindingReactorD7 = new AbstractAction() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       Playsound(D7); 
      } 

     JPanel panel= new JPanel(new FlowLayout()); 
     frame.getContentPane().add(panel); 
     frame.pack(); 

     panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("C"), 
       "cPressed"); 
     panel.getActionMap().put("cPressed", keyBindingReactorC7); 

     panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("D"), 
       "dPressed"); 
     panel.getActionMap().put("dPressed", keyBindingReactorD7); 


    public static void Playsound(File Sound){ 
     try{ 
      Clip clip = AudioSystem.getClip(); 
      clip.open(AudioSystem.getAudioInputStream(Sound)); 
      clip.start(); 

     }catch(Exception e){} 

    } 

} 

И это работает отлично. Если я нажимаю клавиши, он воспроизводит звук, и даже если я забиваю клавиши, звук почти не задерживается. Это именно то, чего я хотел.

Но есть небольшая ошибка.

Если я продолжаю нажимать одну клавишу, или одновременно нажимаю две клавиши (что работает, оно играет одновременно в одно и то же время), иногда бывает, что звука вообще не будет. Я не могу ничего сделать, чтобы заставить его работать снова, и все, что я могу сделать, это перезапустить всю программу. Это происходит случайно, и я не могу понять, почему. Я знаю, что что-то блокирует мои действия от непрерывной работы.

+0

Используйте clip.is active() или clip.is running(), если он ничего не делает! – Gacci

+0

@ Gacci Поскольку они созданы как локальные переменные, это не сработает - хорошая идея, если бы он мог использоваться как поле экземпляра вместо этого, но – MadProgrammer

+3

Не используйте пустой блок catch. Возможно, создается ошибка. – camickr

ответ

2

Ответ на ваш вопрос вращается вокруг того, чего вы в конечном итоге хотите достичь, если вы просто хотите остановить более одного воспроизведения звука, тогда вам нужно какое-то условие, которое вы можете контролировать, если вы хотите остановить «конкретный», звук от воспроизведения, тогда вам нужно поддерживать какой-то List флагов, которые вы можете проверить.

Итак, основываясь на вашем коде, давайте предположим, что вы создаете пианино, поэтому вам нужно, чтобы звуки перекрывались, в этом случае нам нужно каким-то образом определить, был ли воспроизведен какой-то конкретный звук.

Существует несколько способов достижения этого, но позволяет установить на Set, что позволяет поддерживать уникальные List элементов (без дубликатов).

Каждый раз, когда вызывается playSound, мы проверяем этот список и определяем, были ли звуки уже воспроизведены или нет, если это не так, мы добавляем звук в список и воспроизводим его, когда звук останавливается, мы удаляем он из списка

в основе ...

Я изменил ваш код немного, и я объясню это более подробно это позже, но, по сути, это «ядро» идеи. ..

private Set<File> playing = new HashSet<File>(25); 

public void playsound(File sound) { 
    try { 
     // Is the been played or not? 
     if (!playing.contains(sound)) { 
      // And the sound to prevent it from been played again 
      playing.add(sound); 
      // Set up a new clip 
      Clip clip = AudioSystem.getClip(); 
      // Monitor the clip's status, we want to know when it ends 
      clip.addLineListener(new LineListener() { 
       @Override 
       public void update(LineEvent event) { 
        // Clip has stopped 
        if (event.getType() == LineEvent.Type.STOP) { 
         // Release the resources 
         clip.close(); 
         // Remove the sound from our list 
         // so it can be played again 
         playing.remove(sound); 
        } 
       } 
      }); 
      // Play it again Sam 
      clip.open(AudioSystem.getAudioInputStream(sound)); 
      clip.start(); 
     } 
    } catch (Exception e) { 
     // Remove the sound if something goes wrong 
     playing.remove(sound); 
     e.printStackTrace(); 
    } 

} 

Обратный пример

Хорошо, так что я «обновленный» ваш маленький код, вот почему ...

  • Java имеет некоторые установленные правила кодирования, все разработчики поощрены следовать, они делают это легче для других людей, читать ваш код и для вас, чтобы прочитать их, посмотрите на Code Conventions for the Java TM Programming Language для более подробной информации. Сказав, я заставил все ваши переменные начинать с символов нижнего регистра.
  • Создана пользовательская панель. Хорошо, это только я, но это делает жизнь намного проще, поскольку вы можете более легко инкапсулировать логику, которую вы пытаетесь реализовать.Поскольку вы используете API Action, другим вариантом было бы создать класс SoundManager, который содержал бы логику управления и воспроизведения звуков и передавал ссылку на каждый Action, лично я, вероятно, в конечном итоге
  • Я использовал EventQueue.invokeLater, чтобы гарантировать, что пользовательский интерфейс создается в контексте события диспетчерские темы, восстанавливающую любой возможный риск нарушения однопоточного характера Swing, всегда хорошая идея;)

You похоже, с хорошим началом пробовать что-то, молодец, не отставайте!

import java.awt.EventQueue; 
import java.awt.event.ActionEvent; 
import java.io.File; 
import java.util.HashSet; 
import java.util.Set; 
import javax.sound.sampled.AudioSystem; 
import javax.sound.sampled.Clip; 
import javax.sound.sampled.LineEvent; 
import javax.sound.sampled.LineListener; 
import javax.swing.AbstractAction; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.KeyStroke; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class Test { 

    public static void main(String[] args) { 
     new Test(); 
    } 

    public Test() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
        ex.printStackTrace(); 
       } 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.add(new TestPane()); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class TestPane extends JPanel { 

     public TestPane() { 

      File c7 = new File("res/res39191__jobro__piano-ff-044.wav"); 
      File d7 = new File("res/39194__jobro__piano-ff-046.wav"); 

      add(new JLabel("Hello")); 

      AbstractAction keyBindingReactorC7 = new AbstractAction() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        playsound(c7); 
       } 
      }; 
      AbstractAction keyBindingReactorD7 = new AbstractAction() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        playsound(d7); 
       } 
      }; 
      getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("C"), 
                                  "cPressed"); 
      getActionMap().put("cPressed", keyBindingReactorC7); 

      getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("D"), 
                                  "dPressed"); 
      getActionMap().put("dPressed", keyBindingReactorD7); 
     } 

     private Set<File> playing = new HashSet<File>(25); 

     public void playsound(File sound) { 
      try { 
       if (!playing.contains(sound)) { 
        playing.add(sound); 
        Clip clip = AudioSystem.getClip(); 
        clip.addLineListener(new LineListener() { 
         @Override 
         public void update(LineEvent event) { 
          if (event.getType() == LineEvent.Type.STOP) { 
           clip.close(); 
           playing.remove(sound); 
          } 
         } 
        }); 
        clip.open(AudioSystem.getAudioInputStream(sound)); 
        clip.start(); 
       } 
      } catch (Exception e) { 
       playing.remove(sound); 
       e.printStackTrace(); 
      } 

     } 
    } 
} 

Хорошо, но как я могу сделать так, чтобы за один раз мог воспроизводиться только один звук?

Ах, хороший вопрос ...

В основном, мы используем один клип и проверить его состояние ...

private Clip clip; 

public void playsound(File sound) { 
    try { 
     if (clip == null) { 
      clip = AudioSystem.getClip(); 
      clip.addLineListener(new LineListener() { 
       @Override 
       public void update(LineEvent event) { 
        if (event.getType() == LineEvent.Type.STOP) { 
         clip.close(); 
        } 
       } 
      }); 
     } 
     // Is the clip active or running? 
     if (!clip.isActive() && !clip.isRunning()) { 
      if (clip.isOpen()) { 
       clip.close(); 
      } 
      clip.open(AudioSystem.getAudioInputStream(sound)); 
      clip.start(); 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

Теперь мой аудио опыт работы с Java довольно не существует, но некоторые вещи, которые я мог бы рассмотреть, пытаясь ...

  • Сделать AudioManager или SoundManager класс, который управляет звуками и предоставляет простой интерфейс для воспроизведения их (как playC, playD). Предварительно загрузите клипы для каждого звука. Это потребует некоторого дополнительного управления, потому что когда клип заканчивается, вам нужно будет «перезагрузить» его до начала. Это «должно» ускорить воспроизведение клипов, но это, вероятно, будет потреблять больше ресурсов, которые более важны для вас? Вы также можете создать какой-то кеш, где, если клип не воспроизводится в течение определенного периода времени, он закрывается и удаляется.
  • Keep воспроизведение звука до отпускания клавиши ... хороший вызов для вас;)
+0

(1+) Пример NIce. 'потому что, когда клип заканчивается, вам нужно будет« вернуть »его в начало.'- это может быть достигнуто с помощью' clip.setFramePosition (0) 'перед' clip.start() ' – camickr

+0

@camickr Yep, я тоже думал об этом, закрытие показалось более простым в то время: P, но если бы вы были повторное использование клипов (работа в направлении скорости), setFramePosition будет вызывающе быть способом! – MadProgrammer

+0

Спасибо! Это действительно полезно, и я ценю, что вы приложили столько усилий, чтобы помочь мне. –

0

В дополнение к большой помощи @MadProgrammer, я также заметил, что-то еще. Я работаю на Mac, но у меня также есть Windows-машина. Недавно я переключился на Mac, и я не заметил (до сих пор), что если вы удерживаете клавишу достаточно долго, OSX автоматически отобразит больше ключей (например, û, ć и все такое). Итак, я переключил все на свою Windows-машину и voilá, это работает. Конечно, есть некоторые незначительные ошибки, но в итоге я доволен результатом.