- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试制作一个Java应用程序来模拟某人在键盘上打字。击键声音以可变间隔循环播放(Java随机选择击键声音并播放)(以模拟真人打字)。
一开始它工作正常,但在第 95 次迭代之后,它停止播放声音(同时仍在循环)不到 4 秒,然后再次播放声音。在第 160 次迭代之后,它几乎每秒播放一次声音(而不是每隔三到六秒)。
一段时间后,它会停止播放声音很长一段时间,然后永远停止。
这是 AudioPlayer.java
类的源代码:
package entity;
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
public class AudioPlayer implements Runnable {
private String audioFilePath;
public void setAudioFilePath(String audioFilePath) {
this.audioFilePath = audioFilePath;
}
@Override
public void run() {
File audioFile = new File(audioFilePath);
try {
AudioInputStream audioStream = AudioSystem.getAudioInputStream(audioFile);
AudioFormat format = audioStream.getFormat();
DataLine.Info info = new DataLine.Info(Clip.class, format);
Clip audioClip = (Clip) AudioSystem.getLine(info);
audioClip.open(audioStream);
audioClip.start();
boolean playCompleted = false;
while (!playCompleted) {
try {
Thread.sleep(500);
playCompleted = true;
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
}
audioClip.close();
} catch (UnsupportedAudioFileException ex) {
System.out.println("The specified audio file is not supported.");
ex.printStackTrace();
} catch (LineUnavailableException ex) {
System.out.println("Audio line for playing back is unavailable.");
ex.printStackTrace();
} catch (IOException ex) {
System.out.println("Error playing the audio file.");
ex.printStackTrace();
}
}
}
这是用于测试击键模拟器的 Main.java
类:
package sandbox;
import java.util.Random;
import entity.AudioPlayer;
public class Main {
public static void main(String[] args) {
Random rnd = new Random();
AudioPlayer audio;
for(int i = 0; i < 10000; i++) {
int delay = rnd.nextInt(200)+75;
try {
Thread.sleep(delay);
}
catch (InterruptedException ie) {}
int index = rnd.nextInt(3)+1;
audio = new AudioPlayer();
audio.setAudioFilePath("resources/keystroke-0"+index+".wav");
Thread thread = new Thread(audio);
thread.start();
System.out.println("iteration "+i);
}
}
}
我在资源目录中使用了多个不同击键声音的短(小于 200 毫秒)波形文件(总共 3 个)。
编辑
我阅读了您的回答和评论。我想也许我误解了他们,因为建议的解决方案不起作用,或者也许我应该明确自己到底想要什么。另外,我需要注意的是,我不经常使用线程(并且不知道互斥锁是什么)。
所以我首先解释一下我到底想要程序做什么。它应该能够模拟击键,所以我使用了线程,因为它允许两个击键声音重叠,就像真人打字时一样。基本上,我使用的声音剪辑是按键声音,按键声音由两种声音组成:按下按键的声音。松开按键的声音。
如果程序在某个时刻允许两个击键重叠,听起来就好像有人按下一个键,然后按下另一个键,然后释放第一个键。这就是真正的打字听起来的样子!
现在我使用建议的解决方案遇到的问题是:直接调用AudioPlayer的run()方法时,
public static void main(String[] args)
{
// Definitions here
while (running) {
Date previous = new Date();
Date delay = new Date(previous.getTime()+rnd.nextInt(300)+75);
// Setting the audio here
audio.run();
Date now = new Date();
if (now.before(delay)) {
try {
Thread.sleep(delay.getTime()-now.getTime());
} catch (InterruptedException e) {
}
}
System.out.println("iteration: "+(++i));
}
}
声音按顺序播放(一个接一个),播放速率取决于 AudioPlayer 的 sleep 持续时间(或者如果 main() 方法中的延迟高于 AudioPlayer 的 sleep 持续时间,则取决于延迟),这不好,因为它听起来不像普通打字员(更像是刚开始打字并且在打字时仍在寻找每个键的人)。
调用AudioPlayer线程的join()方法时,
public static void main(String[] args)
{
//Variable definitions here
while (running) {
int delay = rnd.nextInt(200)+75;
try
{
Thread.sleep(delay);
}
catch (InterruptedException ie)
{
}
//Setting the AudioPlayer and creating its Thread here
thread.start();
try
{
thread.join();
}
catch(InterruptedException ie)
{
}
System.out.println("iteration "+(++i));
}
}
声音也按顺序播放,播放速率取决于 AudioPlayer 的 sleep 持续时间(或者如果 main() 方法中的延迟高于 AudioPlayer 的 sleep 持续时间,则取决于延迟),这再次,由于与之前相同的原因而没有好处。
所以,回答一下评论者的问题。是的!还有其他一些之前没有表达过的问题,这些问题首先需要线程。
我找到了一个“解决”我的问题的解决方法(但我不认为这是一个正确的解决方案,因为我在某种程度上作弊):我所做的是将 AudioPlayer 的 sleep 持续时间增加到在程序停止(24 小时)之前不太可能达到,而且据我所知,即使在一个多小时后,它也不会使用太多资源。
您可以查看我想要什么、运行建议的解决方案时得到什么以及使用 this youtube videos 上的解决方法得到什么(不幸的是 StackOverflow 没有视频上传功能。所以我不得不把它放在 YouTube 上)。
编辑音效可下载here .
最佳答案
这个单线程解决方案怎么样,它是您自己的更干净的版本,但重新使用缓冲区中已打开的剪辑?对我来说,即使没有同时播放两种声音,打字听起来也很自然。您可以通过更改 Application
类中相应的静态常量来调整打字速度。
package de.scrum_master.stackoverflow.q61159885;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine.Info;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import static javax.sound.sampled.AudioSystem.getAudioInputStream;
import static javax.sound.sampled.AudioSystem.getLine;
public class AudioPlayer implements Closeable {
private final Map<String, Clip> bufferedClips = new HashMap<>();
public void play(String audioFilePath) throws IOException, UnsupportedAudioFileException, LineUnavailableException {
Clip clip = bufferedClips.get(audioFilePath);
if (clip == null) {
AudioFormat audioFormat = getAudioInputStream(new File(audioFilePath)).getFormat();
Info lineInfo = new Info(Clip.class, audioFormat);
clip = (Clip) getLine(lineInfo);
bufferedClips.put(audioFilePath, clip);
clip.open(getAudioInputStream(new File(audioFilePath)));
}
clip.setMicrosecondPosition(0);
clip.start();
}
@Override
public void close() {
bufferedClips.values().forEach(Clip::close);
}
}
package de.scrum_master.stackoverflow.q61159885;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import java.io.IOException;
import java.util.Random;
public class Application {
private static final Random RANDOM = new Random();
private static final int ITERATIONS = 10000;
private static final int MINIMUM_WAIT = 75;
private static final int MAX_RANDOM_WAIT = 200;
public static void main(String[] args) throws UnsupportedAudioFileException, IOException, LineUnavailableException {
try (AudioPlayer audioPlayer = new AudioPlayer()) {
for (int i = 0; i < ITERATIONS; i++) {
sleep(MINIMUM_WAIT + RANDOM.nextInt(MAX_RANDOM_WAIT));
audioPlayer.play(randomAudioFile());
}
}
}
private static void sleep(int delay) {
try {
Thread.sleep(delay);
} catch (InterruptedException ignored) {}
}
private static String randomAudioFile() {
return "resources/keystroke-0" + (RANDOM.nextInt(3) + 1) + ".wav";
}
}
您可能已经注意到,AudioPlayer
是Closeable
,即您可以在调用应用程序中使用“尝试使用资源”。这样可以确保在程序结束时所有剪辑都会自动关闭。
重播同一剪辑的关键当然是在开始之前clip.setMicrosecondPosition(0)
。
更新:如果你想模拟多人,只需像这样修改主类即可。顺便说一句,我对音频编程一无所知,也不知道是否有办法更好地处理混音器和重叠声音。这只是一个概念证明,以便为您提供一个想法。每人有一个线程,但每个人以串行方式键入,而不是同时键入两个键。但多人可以重叠,因为每个人都有一个 AudioPlayer
并拥有自己的一组缓冲剪辑。
package de.scrum_master.stackoverflow.q61159885;
import java.util.Random;
public class Application {
private static final Random RANDOM = new Random();
private static final int PERSONS = 2;
private static final int ITERATIONS = 10000;
private static final int MINIMUM_WAIT = 150;
private static final int MAX_RANDOM_WAIT = 200;
public static void main(String[] args) {
for (int p = 0; p < PERSONS; p++)
new Thread(() -> {
try (AudioPlayer audioPlayer = new AudioPlayer()) {
for (int i = 0; i < ITERATIONS; i++) {
sleep(MINIMUM_WAIT + RANDOM.nextInt(MAX_RANDOM_WAIT));
audioPlayer.play(randomAudioFile());
}
} catch (Exception ignored) {}
}).start();
}
private static void sleep(int delay) {
try {
Thread.sleep(delay);
} catch (InterruptedException ignored) {}
}
private static String randomAudioFile() {
return "resources/keystroke-0" + (RANDOM.nextInt(3) + 1) + ".wav";
}
}
关于java - 为什么我的 Java 应用程序不在每次循环时播放声音?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61159885/
我正在通过 labrepl 工作,我看到了一些遵循此模式的代码: ;; Pattern (apply #(apply f %&) coll) ;; Concrete example user=> (a
我从未向应用商店提交过应用,但我会在不久的将来提交。 到目前为止,我对为 iPhone 而非 iPad 进行设计感到很自在。 我了解,通过将通用PAID 应用放到应用商店,客户只需支付一次就可以同时使
我有一个应用程序,它使用不同的 Facebook 应用程序(2 个不同的 AppID)在 Facebook 上发布并显示它是“通过 iPhone”/“通过 iPad”。 当 Facebook 应用程序
我有一个要求,我们必须通过将网站源文件保存在本地 iOS 应用程序中来在 iOS 应用程序 Webview 中运行网站。 Angular 需要服务器来运行应用程序,但由于我们将文件保存在本地,我们无法
所以我有一个单页客户端应用程序。 正常流程: 应用程序 -> OAuth2 服务器 -> 应用程序 我们有自己的 OAuth2 服务器,因此人们可以登录应用程序并获取与用户实体关联的 access_t
假设我有一个安装在用户设备上的 Android 应用程序 A,我的应用程序有一个 AppWidget,我们可以让其他 Android 开发人员在其中以每次安装成本为基础发布他们的应用程序推广广告。因此
Secrets of the JavaScript Ninja中有一个例子它提供了以下代码来绕过 JavaScript 的 Math.min() 函数,该函数需要一个可变长度列表。 Example:
当我分别将数组和对象传递给 function.apply() 时,我得到 NaN 的 o/p,但是当我传递对象和数组时,我得到一个数字。为什么会发生这种情况? 由于数组也被视为对象,为什么我无法使用它
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界. 这篇CFSDN的博客文章ASP转换格林威治时间函数DateDiff()应用由作者收集整理,如果你
我正在将列表传递给 map并且想要返回一个带有合并名称的 data.frame 对象。 例如: library(tidyverse) library(broom) mtcars %>% spl
我有一个非常基本的问题,但我不知道如何实现它:我有一个返回数据框,其中每个工具的返回值是按行排列的: tmp<-as.data.frame(t(data.frame(a=rnorm(250,0,1)
我正在使用我的 FB 应用创建群组并邀请用户加入我的应用群组,第一次一切正常。当我尝试创建另一个组时,出现以下错误: {"(OAuthException - #4009) (#4009) 在有更多用户
我们正在开发一款类似于“会说话的本”应用程序的 child 应用程序。它包含大量用于交互式动画的 JPEG 图像序列。 问题是动画在 iPad Air 上播放正常,但在 iPad 2 上播放缓慢或滞后
我关注 clojure 一段时间了,它的一些功能非常令人兴奋(持久数据结构、函数式方法、不可变状态)。然而,由于我仍在学习,我想了解如何在实际场景中应用,证明其好处,然后演化并应用于更复杂的问题。即,
我开发了一个仅使用挪威语的应用程序。该应用程序不使用本地化,因为它应该仅以一种语言(挪威语)显示。但是,我已在 Info.plist 文件中将“本地化 native 开发区域”设置为“no”。我还使用
读完 Anthony's response 后上a style-related parser question ,我试图说服自己编写单体解析器仍然可以相当紧凑。 所以而不是 reference ::
multicore 库中是否有类似 sapply 的东西?还是我必须 unlist(mclapply(..)) 才能实现这一点? 如果它不存在:推理是什么? 提前致谢,如果这是一个愚蠢的问题,我们深表
我喜欢在窗口中弹出结果,以便更容易查看和查找(例如,它们不会随着控制台继续滚动而丢失)。一种方法是使用 sink() 和 file.show()。例如: y <- rnorm(100); x <- r
我有一个如下所示的 spring mvc Controller @RequestMapping(value="/new", method=RequestMethod.POST) public Stri
我正在阅读 StructureMap关于依赖注入(inject),首先有两部分初始化映射,具体类类型的接口(interface),另一部分只是实例化(请求实例)。 第一部分需要配置和设置,这是在 Bo
我是一名优秀的程序员,十分优秀!