KeyboardPianoV1.6 MusicPlayer


详细步骤

例行说明

  • 本着最小代价/资源化原则,使用 java 自带的音频播放器(位于 javax.sound.sampled 包内),格式上仅限于 wav 音频(MP3 翻车不支持,且对 wav 频率&位 有范围限制)这里博主使用 44100 Hz, 16 bit 的格式
  • 所以与其说是选择了 wav,倒不如说是选择了播放类
    而整体呈现出来的效果就是 音效不行,音质全损 ╮( ̄﹏ ̄)╭
  • 当然博主也对其他格式也进行过简单测试,比较有感觉的是 MP3 格式,听起来更加悦耳,而不像 wav 那样低沉,也不知道是格式转换问题还是咋滴,表示一脸懵,望指点!
  • 不过在阅读官方文档的过程中,发现位于 javax.sound.sampled 之上的有个 javax.sound.midi 的包,同样也是做音频播放的,所不同的是后者调的是系统的声音,后期可能考虑更改,具体效果如何,有待验证

具体步骤

  • 造个音乐播放器 MusicPlayer,使用线程带动,方便并发
  • MyButton 每按一次,播放一个音频 new Thread(new MusicPlayer(getType(), wavPath)).start();也就是 V0.0 所说的按一个键,发一个声
  • 音频命名出错,纠正方式请见 Option1

代码分析

  • MusicPlayer
    1. 第一次把整个类全贴上来,代码上已经加上中文注释,合理来说应该可以看得懂
    2. 整体而言,通过音频数据流获取音频数据,再怼到播放器上让其播放,播放完再想办法把它关了
public class MusicPlayer extends Thread {
    /*
     * 对音量高低的调整
     */
	private static final float LEFT_VALUE = -3.0f;
	private static final float RIGHT_VALUE = +3.0f;
	
	private String musicPath; 
	private Clip clip;
	private AudioInputStream audioInputStream = null;
	private BufferedInputStream buffer = null;
	private char musicType;
	
	MusicPlayer(char musicType, String musicPath) {
		this.musicType = musicType;
		this.musicPath = musicPath;
	}

	@Override
	public void run() {

		if(musicPath == null) { //如果找不到这个音频就不播放了
			return;
		}
		
        /*
         * 通过 buffer 数据流把音频怼进来
         */
		try {
			buffer = new BufferedInputStream(new FileInputStream(musicPath));
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
		}
		
		/*
         * buffer 转换为音频数据流,使用 Clip 打开音频通道,为播放做好准备
         */
		try {
			audioInputStream = AudioSystem.getAudioInputStream(buffer);
			clip = AudioSystem.getClip();
			clip.open(audioInputStream);
		} catch (UnsupportedAudioFileException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (LineUnavailableException e) {
			e.printStackTrace();
		}  
		
		/*
         * 音量控制器
         */
		FloatControl gainControl = 
				(FloatControl)clip.getControl(FloatControl.Type.MASTER_GAIN);
		
		/*
         * 音量设置
         */
		if(musicType == KeyboardPiano.L) {
			gainControl.setValue(LEFT_VALUE); //set +- dB
		} else if(musicType == KeyboardPiano.R) {
			gainControl.setValue(RIGHT_VALUE);
		}
		
		/*
         * 音频播放
         */
		clip.start();
		
        /*
         * 播放完毕关闭线程 & 释放资源
         * 想是这样想啦,然而并没有什么卵用。。。
         */
		try {
			Thread.sleep(3000);
			if(!this.isInterrupted()) {
				this.interrupt();
			}
			this.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
	}
	
}

这里就不传视频了,就差不多 V0.0Demo 演示的效果

  • Attentionclip.start(); 后的代码块几乎无效,ClipDaemon Thread (守护线程),不关闭的话线程一直耗在那直到程序退出,但是,即使加上 clip.close() 关闭播放类也收效甚微(具体原因是 Clip的自身 BUG
    反正只要线程里的资源不释放,再怎么 interrupt, 再怎么 close 都没戏,不信可以试试
    而资源没有释放导致一个最严重的后果就是内存泄露(准确来说是堆内存泄露)
    什么意思?一首曲子弹下来,内存飙到 1000+ M,而且只增不减,谁受得了。。。

  • JConsole: Heap Memory Usage
    在这里插入图片描述

看不懂,没关系,任务管理器拿出来瞅瞅

  • Task Manager: Memory Usage
    在这里插入图片描述

音频实际上就是一串 byte 数据流,存储在 byte[]
经过后期内存分析,发现这块资源无论如何都释放不了,但最终还是得到了极大的改善,具体情况以后分析内存泄露时自然会解释清楚


Options

Option1

  • 音频命名错误,导致弹奏的时候不着调,博主已经通过 FileTmp.java 文件对音频交换命名
    读者只需把 wav/ 文件夹下载替换本地的即可,实际上并没有改变音频本身,只是更改名称而已

相关链接


后记

  • 至此,项目开发到这里已经有了基本的雏形了,后期的版本要么是代码调整,要么是 Debug, 而且到现在还处于第一阶段的开发,后面还跟着 V1.7 & V1.8 & V1.9 的系列版本,离完结撒花还有很长的路要走

莫哭,一起走;莫愁,路未尽,心尚留。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值