第一篇:基于Qt的音乐播放器课程设计报告
山西大学
课程设计报告
题 目:基于QT的音乐播放器
系 别: 软件学院 班 级: 1522班
姓 名:贾梦洁 学 号:
同组组员:
设计时间: 2017年12月22日----2017年12月30日
公司名称: 上海杰普软件科技有限公司
目 录
第一章 引言.......................................1 第二章 软件分析与设计.............................2 2.1软件需求分析........................................2 2.2开发环境............................................3 2.3软件概要设计........................................3
第三章 软件功能实现...............................4 3.1软件总体架构........................................5 3.2软件功能流程........................................5 3.3具体功能实现........................................6 第四章 软件测试..................................16 第五章 总结......................................17
第一章 引言
计算机技术的飞速发展大大提高了人们的工作效率,尤其是互联网技术更是很大程度上丰富和方便了人们的生活。近些年来,人们的生活水平也在不断提升,在物质丰富的条件下,人们开始在工作之余关注娱乐,期望在其它方面释放工作压力,同时培养自己的兴趣爱好,随之而来的是人们对多媒体应用的关注,许多电影播放平台、音乐播放软件等逐渐深入人们的生活,并慢慢地成为人们生活重要组成部分。
目前,互联网上已经拥有大量的音乐播放软件,这些软件是各个软件供应商的商品关键组成部分,当前其实现技术较复杂,在功能方面相当完备且强大,如何简单、高效、方便地设计实现一款小巧美观的音乐播放器软件成为人们关注的热点。基于该问题,本文设计并实现了基于Qt的音乐播放软件,该软件能够便捷、高效地为用户展示音乐播放界面,方便的进行歌曲播放和控制功能。本文的工作分为软件界面设计和软件功能实现两部分,其中,软件界面设计工作主要包括用户界面设计实现;各个功能模块实现工作主要包括后台程序编码设计模块化完成设计等内容。
该音乐播放软件以Qt开发平台中实现歌曲播放的相应功能为基本框架设计,通过C++语言编程实现各个功能函数,软件设计方面采用模块化的软件设计思想实现,具有友好的用户交互界面和高承载能力的运行稳定性。
第二章 软件分析与设计
2.1 软件需求分析
在设计实现音乐播放器软件的同时,可以对目前存在的不同类型的音乐播放器进行广泛深入的研究,查看软件可能需要的需求内容。因此,需要对具体问题进行具体分析,深入挖掘其需要实现的系统功能,以方便后面对软件构架的设计工作。需求分析的过程,是开发人员对音乐播放器工作过程的认识与熟悉的过程,也是对软件内部工作流程进行计算机建模的过程,最终目的是通过需求分析了解用户需求实现的功能,根据用户提出的需求设计好系统的概念模型,对用户提出的需求进行计算机方法的描述,并建立相应配套的需求分析文档,设计好系统的具体实现方案。
在设计实现基于Qt的音乐播放器的同时,考虑到音乐播放器的实际工作环境,可以确定的是该软件应当拥有以下几个方面的特性:
(1)基本功能
随着电脑终端的扩大化,PC机上各种软件也不计其数。为了使用户体验及软件质量都达到一定的完备性,我们需要保证一定的基础功能。基于人性化角度,开发设计基础功能,使用户可以流畅使用软件。在进行功能划分的过程当中,可以采用模块化的功能设计思想,对功能的划分尽可能的细致,做到不遗漏。例如,应当有播放模式的选择,音乐列表的选择,音量高低的调试等。(2)稳定性
基于QT的音乐播放器是一款娱乐软件,更需要保证软件的稳定性,以使用户体验达到最高。若播放器不稳定,则用户体验这一指标则会大幅下降。
(3)联通性
移动设备日益增长,微博、微信等交流平台在市场中也占据重要地位。为迎合这一现象,QT音乐播放器必须进行一定的互联网联通性。可以进行音乐分享、转发评论等。这样可以实现软件之间的交流结合,有利于软件的推广。同时也有利于通过大数据分析,得到听众最喜爱听的歌曲,符合大众口味。
2.2 开发环境
操作系统:Windows 10 开发平台:Qt 使用语言:C++
2.3 软件概要设计
在软件概要设计阶段,是基于整个系统需要实现的功能,对物业管理信息系统的整体架构进行科学合理的设计,使之有一定的规律可以遵循,不进行盲目的设计工作,这对于后期的程序编码和系统的来说意义重大。在对音乐播放器软件进行软件需求分析之后,针对需求 分析的结果,对系统进行了整体的架构设计。
设计实现的音乐播放器软件,从软件的架构来看,主要包括两个功能部分:软件的歌曲播放部分和图标最小化功能实现部分。其中,歌曲播放部分主要实现该软件的主要功能,即选择歌曲和播放歌曲;另一部分则是最小化后软件的实现,主要包括显示、登录、设置、检查更新、退出。以上是对该音乐播放器软件的整体工作架构进行的设计,该步骤是后续进一步进行系统功能实现的基础。
第三章 软件功能实现
在设计实现基于Qt的音乐播放器软件的同时,充分考虑了Qt的语言特性和开发环境,发挥了其在用户界面应用程序开发当中的优势,对音乐播放器软件进行了开发。根据前文对该音乐播放器软件的 需求分析,以及对软件的设计分析结果,结合实际使用当中可能使用到的软件功能,并采用了软件工程中模块化的开发思想,完成了该音乐播放器软件的开发,下面分别对软件中重要的功能模块的实现方法及实现效果进行详细的介绍和分析。
3.1 总体架构
通过在需求阶段对系统的总体功能的分析,我们得到了这个音乐播放器软件的总体功能结构,它应包括四大基本功能模块。
(1)选择歌曲文件模块:用户可以方便的查询环境当中存在的歌曲列表信息,并找到满意歌曲的位置和具体的歌曲内容。
(2)歌曲播放模块:用户根据所选择的具体歌曲让该软件对歌曲进行播放,并且可以实时查看歌曲的播放状态。
(3)播放状态控制模块:用户可以查看成自己在歌曲播放过程中进度情况,并可以随时更改歌曲的播放进度信息。
(4)第二界面模块:用户可以进入第二个更为简洁的界面进行播放、暂停、切换等操作。
3.2 软件功能流程
整个软件所设计的工作流程如下:
(1)开始。进入Qt界面开始运行软件。
(2)播放歌曲。该部分是音乐播放器软件最主要的功能部分,播放歌曲的功能实现需要相对复杂的函数调用来实现,在软件开发的过程 当中有具体的实现代码。
(3)播放设置。该部分的实现是进一步提高用户的使用体验,方便用户根据其自身的需求对所播放的歌曲进行进度控制,可以暂停歌曲的播放,也可以继续歌曲的播放功能,同时也可以进行音量的调控,以及对歌曲播放的顺序进行调整,比如顺序播放、单曲循环等。(4)第二界面。点击shrink按钮可跳转至第二界面,进行播放切换歌曲等操作,也可以进行最小化。
(5)结束。点击关闭软件,结束软件运行。
3.3 具体功能实现
本人完成了本次音乐播放器中的歌曲导入模块以及播放歌曲的初步工作,具体的实现过程如下。
3.3.1歌曲导入(1).h文件
歌曲导入部分的代码函数名称以及相应的函数声明完成在settingwiget.h的头文件下,先对命名空间进行前向声明,对类内的对象和方法进行声明,具体代码如下:
#ifndef SETTINGWIGET_H #define SETTINGWIGET_H
#include
namespace Ui { class settingwiget;}
class settingwiget : public QWidget { Q_OBJECT
public: explicit settingwiget(QWidget *parent = 0);~settingwiget();
void initSystemSetting(void);
bool writeInit(QString path, QString user_key, QString user_value);bool readInit(QString path, QString user_key, QString &user_value);
private slots: void on_pb_save_clicked();
void on_pb_cancle_clicked();
void on_tb_lyricsPath_clicked();
void on_tb_songsPath_clicked();
void on_pb_save_destroyed();
private: Ui::settingwiget *ui;};
#endif // SETTINGWIGET_H
(2).cpp文件
配置文件写入和读取的方法完成在settingwiget.cpp文件内,代码如下:
settingwiget::settingwiget(QWidget *parent): QWidget(parent), ui(new Ui::settingwiget){ ui->setupUi(this);
SongsFile::m_songPath.clear();LyricsFile::m_lyricPath.clear();}
settingwiget::~settingwiget(){ delete ui;}
bool settingwiget::writeInit(QString path, QString user_key, QString user_value){ if(path.isEmpty()|| user_key.isEmpty()){ return false;} else { //创建配置文件操作对象
QSettings *config = new QSettings(path, QSettings::IniFormat);
//将信息写入配置文件
config->beginGroup(“config”);config->setValue(user_key, user_value);config->endGroup();
return true;} }
bool settingwiget::readInit(QString path, QString user_key, QString &user_value){ user_value = QString(“");if(path.isEmpty()|| user_key.isEmpty()){ return false;} else { //创建配置文件操作对象
QSettings *config = new QSettings(path, QSettings::IniFormat);
//读取用户配置信息
user_value = config->value(QString(”config/“)+ user_key).toString();
return true;} }
界面设计中按钮的具体功能也对应在settingwiget.cpp文件内,代码如下:
void settingwiget::on_tb_songsPath_clicked(){ SongsFile::m_songPath = QFileDialog::getExistingDirectory();ui->le_songsPath->setText(SongsFile::m_songPath);}
void settingwiget::on_tb_lyricsPath_clicked(){ LyricsFile::m_lyricPath = QFileDialog::getExistingDirectory();ui->le_lyricsPath->setText(LyricsFile::m_lyricPath);}
void settingwiget::on_pb_save_clicked(){ writeInit(QString(”../user.ini“), ”SONGPATH“, SongsFile::m_songPath);writeInit(QString(”../user.ini“), ”LYRICPATH“, LyricsFile::m_lyricPath);
initSystemSetting();this->hide();}
void settingwiget::on_pb_cancle_clicked(){ this->hide();}
void settingwiget::initSystemSetting(void){ readInit(QString(”../user.ini“), ”SONGPATH“, SongsFile::m_songPath);readInit(QString(”../user.ini“), ”LYRICPATH“, LyricsFile::m_lyricPath);
ui->le_songsPath->setText(SongsFile::m_songPath);ui->le_lyricsPath->setText(LyricsFile::m_lyricPath);}
void settingwiget::on_pb_save_destroyed(){}
其中,cpp文件内的头文件为:
#include ”settingwiget.h“ #include ”ui_settingwiget.h“
#include
3.3.2歌曲播放的部分功能(1).h文件
musicplayer.h的头文件下,采用枚举类型对播放模式进行声明,写入信号和槽方便传值,对歌曲播放逻辑、歌曲列表获取逻辑、歌曲歌词获取逻辑的对象、方法进行声明,具体代码如下:
#ifndef MUSICPLAYER_H #define MUSICPLAYER_H
#include
#include
#include ”songsfile.h“ #include ”lyricsfile.h“
#define TIME_MS_DURATION 1000 #define INIT_SYSTEM_VOLUME 50
enum PlaybackMode //播放模式 { CURRENT_ITEM_ONCE = 0, //单曲播放 CURRENT_ITEM_IN_LOOP = 1, //单曲循环 SEQUENTIAL = 2, //顺序播放 LOOP = 3, //列表循环 RANDOM = 4 //随机播放
};
class MusicPlayer : public QObject { Q_OBJECT
signals: void signalPositionChanged(QString updateTime);void signalDurationChanged(qint64 duration);
public slots: void slotPositionChanged(qint64 position);void slotDurationChanged(qint64 duration);
public: explicit MusicPlayer(QObject *parent = 0);
const qint64 getTotalPlayerTime(void)const;void setTotalPlayerTime(const qint64 time);
const qint64 getCurrentPlayerTime(void)const;void setCurrentPlayerTime(const qint64 time);
/// 歌曲播放逻辑
QMediaPlayer ¤tMediaPlayer(void);
/// 歌曲列表获取逻辑
QMediaPlaylist &musicPlayList(void);QStringList &songsNameList(void);
/// 歌曲歌词获取逻辑 void getCurrentSongLyric(void);QList
private: /// 歌曲播放逻辑
qint64 m_totalPlayerTime;qint64 m_currentPlayerTime;QMediaPlayer m_player;
/// 歌曲列表获取逻辑
SongsFile *m_songsFile;QMediaPlaylist m_musicPlayList;QStringList m_songsNameList;
/// 歌曲歌词获取逻辑
QList
#endif // MUSICPLAYER_H
(2).cpp文件
musicplayer.cpp的头文件如下:
#include ”musicplayer.h“
#include
同时在cpp文件内写入了信号与槽传值连接的方法,代码如下:
MusicPlayer::MusicPlayer(QObject *parent): QObject(parent){ m_songsFile = new SongsFile(this);
m_songsFile->initSongsListAndSongsNameList(m_musicPlayList, m_songsNameList);
m_player.setPlaylist(&m_musicPlayList);m_player.setVolume(INIT_SYSTEM_VOLUME);connect(&m_player, SIGNAL(durationChanged(qint64)), this, SLOT(slotDurationChanged(qint64)));connect(&m_player, SIGNAL(positionChanged(qint64)), this, SLOT(slotPositionChanged(qint64)));}
得到siganl后相应执行的槽函数(position),具体代码如下:
void MusicPlayer::slotPositionChanged(qint64 position){ m_currentPlayerTime = position / TIME_MS_DURATION;//歌曲进度条显示
QTime currentTime((m_currentPlayerTime/3600)%60,(m_currentPlayerTime/60)%60, m_currentPlayerTime%60,(m_currentPlayerTime*1000)%1000);QTime totalTime((m_totalPlayerTime/3600)%60,(m_totalPlayerTime/60)%60, m_totalPlayerTime%60,(m_totalPlayerTime*1000)%1000);
QString updateTime = currentTime.toString(”mm:ss“)+ ”/“+ totalTime.toString(”mm:ss");
emit signalPositionChanged(updateTime);}
void MusicPlayer::slotDurationChanged(qint64 duration){ m_totalPlayerTime = duration / TIME_MS_DURATION;//TIME_MS_DURATION 1000 emit signalDurationChanged(m_totalPlayerTime);}
以及对播放时间、播放列表等的声明,代码如下:
const qint64 MusicPlayer::getTotalPlayerTime(void)const { return m_totalPlayerTime / TIME_MS_DURATION;//INIT_SYSTEM_VOLUME 50 } void MusicPlayer::setTotalPlayerTime(const qint64 time){ m_totalPlayerTime = time;}
const qint64 MusicPlayer::getCurrentPlayerTime(void)const { return m_currentPlayerTime;} void MusicPlayer::setCurrentPlayerTime(const qint64 time){ m_currentPlayerTime = time;}
QMediaPlayer &MusicPlayer::currentMediaPlayer(void){ return m_player;}
QMediaPlaylist &MusicPlayer::musicPlayList(void){ return m_musicPlayList;}
QStringList &MusicPlayer::songsNameList(void){ return m_songsNameList;}
void MusicPlayer::getCurrentSongLyric(void){ LyricsFile lyricsFile;m_lyricIndexList.clear();m_lyricContentList.clear();lyricsFile.getCurrentSongLyric(m_lyricIndexList, m_lyricContentList);}
QList
QStringList &MusicPlayer::lyricContentList(void)//歌词内容列表 { return m_lyricContentList;}
第四章 软件测试
软件实现截图如下:(1)主界面
(2)第二界面(3)最小化
第五章 总结
本次所设计的基于Qt的音乐播放器软件,在Windows系统环境下可以成功的运行,对于预期的功能目标已经基本实现,其中包括歌曲的选择,歌曲打开,歌曲播放,歌曲暂停,显示歌曲播放的进度条等功能。该软件的开发是在Qt Creator的开发环境下完成的程序编写工作,该开发平台简单方便,操作快捷,可以直接在Windows系统平台下安装运行,完成代码的编写后,只需要直接点击编译和运行即可使音乐播放器开始工作,按用户的选择进行歌曲播放等功能,具有一定的实用性。
通过本次毕业设计,我终于明白了“看一万行代码,不如动手写一行代码”这一句真理,对于工科类的学生来说,除了加强对对书本里的理论知识的学习之外,更重要的是培养自己实践动手的能力。这次毕业设计,让我以后面对困难时变得更有耐心,对我来说,这一精力都是在以后的生活和学习中的很宝贵的财富,极大的影响我以后的成长和发展道路。
开发时间限制,我们小组实现了系统的基本功能,软件可以实现基本功能,但是界面尚不够美观,系统也不够完善,下一步,我们会 继续改进系统。本次设计以及系统的实现让我们认识到了以前很多没有注意到的细节问题,让我学到了不少的新知识。
第二篇:基于java的音乐播放器课程设计报告
Java课程设计报告
题目:java音乐播放器
姓
名 学
号 院
系 班
级 专
业 任课教师
1.设计内容及要求
能够实现简单的音乐播放器功能,如:打开本地文件,播放,暂停,停止,背景播放,单曲循环等等,界面充实,交互友好,可以添加多首歌曲目录
一个简单的基于java语言的音乐播放器,菜单栏:文件,播放控制和播放列表,文件菜单包含打开、循环和退出三个菜单项;播放控制菜单包含播放、暂停和停止三个菜单项,播放列表菜单则是当向里面添加歌曲之后才能够查看到里面所包含的歌曲目录。当播放歌曲时,可以调节音量大小或者设置是否静音;可以查看当前播放音乐的相关属性,如:歌曲名,歌手,发布时间,所属专辑等等。
2.需求分析
1、时间跟踪条:根据歌曲播放的进度,控制条自动进行追踪,用户可以
随时了解歌曲的播放进度
2、音量控制键:可以点击该控键进行音量大小的调节以及是否静音的设
置
3、属性查询键:通过该控键,用户可以查看当前播放音乐的相属性,获
取关于该歌曲的用户所需的相关信息。
4、菜单栏:
①文件:
打开:用户通过该菜单项打开本地音乐文件,听任何用户想
听的歌曲
循环:通过循环设置,用户可以重复的播放一首喜欢的歌曲
退出:退出音乐播放器,及退出该程序
②播放控制:
播放:选择歌曲之后,通过点击播放菜单项启动播放器播
放音乐
暂停:暂停当前正在播放的音乐
停止:停止当前正在播放的音乐
③播放列表:当用户通过文件打开本地音乐文件后,及相当于在
播放列表里面添加了歌曲,及形成相应的歌曲播放目录
3.总体设计
结合需求分析来看,整个设计包含了简单的菜单栏,根据用户需求设置了三个简单的实现基本操作的菜单,分别是:文件,播放控制,播放列表;根据具体的操作每个菜单还包含了相应的菜单项,文件:打开,循环,退出;播放控制:播放,暂停,停止;播放列表则没有菜单项,该菜单就是用来显示或者查看相应的歌曲目录的。
该音乐播放器设置了两个窗口,运行程序时打开的初始化欢迎界面,用户可以根据自己的需求进行菜单栏里面的基本操作和相应的设置,当用户添加或者打开音乐播放文件的时候,程序将会显示出第二个音乐文件播放窗口,与此同时,第一个初始化窗口将会自动隐藏,在音乐播放窗口里面用户可以进行相关的音乐播放的控制操作。
当用户进入音乐播放窗口时,该窗口有几个快捷控制的控键:时间追踪轴:可以实现播放的前进、后退功能,根据用户需求调节音乐的播放进度等;音量控制:设置静音,打开扬声器或者调节音量大小;播放列表:查看当前播放音乐的相关属性。4.主要功能设计流程
5.系统实现及测试:
(一)JMF(java媒体框架)简介
JMF 即Java媒体框架。其核心框架支持不同媒体,如音频输出和视频输出,包括时间的时钟同步。它是一个标准的扩展框架,允许用户制作纯音频流和视频流。
JMF实际上是Java的一个类包。它包括了一个开放的媒体架构,可使开发人员灵活采用各种媒体回放、捕获组件,或采用他们自己的定制的内插组件。
JMF软件是Java Media系列软件的一部分。采用各种Java Media API,软件开发商人员就能容易、快速地为他们已有的各种应用程序和客户端,Java小程序增添丰富的媒体功能,如流式视频、3D图像和影像处理等。就是 说,各种Java Media API发挥了Java平台的固有优势,将“编写一次,到处运行”的能力扩展到了图像、影像和数字媒体等各种应用领域,从而大大缩减了开发时间和降低了开发 成本。
在开发JMF 应用程序之前要完全理解JMF 的体系架构、接口和类。就拿我们的家用摄像机系统作个例子。首先用摄像机拍摄内容,拍摄下来的内容录制在DV带中。DV带可以放在放像机里播放、放像机提供视频信号给电视机,提供音频信号给音箱,这样我们就可以在电视机上看到画面,从音箱里听到声音。JMF API 提供的也是同样的模型。
JMF 提供的模型可大致分为七类
* 数据源(Data source)
* 截取设备(Capture Device,包括视频和音频截取设备)
* 播放器(Player)
* 处理器(Processor)
* 数据池(DataSink)
* 数据格式(Format)
* 管理器(Manager)
如果只是想观看捕获的内容,只需要使用捕获数据源创建播放器Player即可。如果想把捕获的数据发送到网络或者保存起来,就需要创建处理器Processor。
基本步骤是首先获取视频、音频捕获设备的信息,然后再根据取得的设备信息确定设备的位置。找到设备的位置以后,调用ManageCreatePlayer方法创建Player,当Player开始播放的时候,就开始了捕获的过程。
有多种方法获得捕获设备信息,可以通过查询指定的格式,也可以查询特定的设备名字。Player准备好播放数据,当Player发出这个事件时,就可以获取播放器的可视面板和控制面板了。具体步骤如下:
1.先把所有的捕获设备调出来
2.创建Player,当Play开始的时候,就开始了音频捕获的过程
3.以MediaLocator为参数,创建Player 4.为PLAYER添加监听器,以便监听RealizeComplete事件
(二)代码实现
(1)添加库、包等相关文件 import javax.media.ControllerEvent;import javax.media.ControllerListener;import javax.media.EndOfMediaEvent;import javax.media.PrefetchCompleteEvent;import javax.media.RealizeCompleteEvent;import javax.media.*;import javax.swing.*;import java.awt.*;
import java.awt.event.*;
(2)初始化窗口 ①界面
②代码实现
public void setupMenu(){
Menu f = new Menu(“文件”);
MenuItem mi = new MenuItem(“打开”);
CheckboxMenuItem cbmi = new CheckboxMenuItem(“循环”, false);MenuItem ee = new MenuItem(“退出”);f.add(mi);f.add(cbmi);f.add(ee);
mi.addActionListener(this);cbmi.addActionListener(this);ee.addActionListener(this);f.addSeparator();f.addSeparator();f.addSeparator();
Menu l = new Menu(“播放列表”);Menu c = new Menu(“播放控制”);
MenuItem move = new MenuItem(“播放”);MenuItem pause = new MenuItem(“暂停”);MenuItem stop = new MenuItem(“停止”);move.addActionListener(this);pause.addActionListener(this);stop.addActionListener(this);c.add(move);c.add(pause);c.add(stop);
c.addSeparator();c.addSeparator();c.addSeparator();
MenuBar mb = new MenuBar();mb.add(f);mb.add(c);mb.add(l);
setMenuBar(mb);}
(3)音乐播放窗口机基本功能的实现 ①界面
②代码实现
public void actionPerformed(ActionEvent e){
String cufile, selectfile, currentDirectory;if(e.getActionCommand().equals(“退出”)){
dispose();
return;}
if(e.getActionCommand().equals(“播放”)){ if(player!= null)
player.start();return;
} if(e.getActionCommand().equals(“暂停”))
{
if(player!= null)
player.stop();return;}
if(e.getActionCommand().equals(“停止”)){
if(player!= null){
player.stop();
player.setMediaTime(new Time(0));} return;}
if(e.getActionCommand().equals(“打开”)){
FileDialog fd = new FileDialog(this, “打开媒体文件”, FileDialog.LOAD);fd.setVisible(true);
if(fd.getFile()== null)
return;
selectfile = fd.getFile();
currentDirectory = fd.getDirectory();
cufile = currentDirectory + selectfile;
MenuItem mi = new MenuItem(selectfile);mi.setActionCommand(cufile);MenuBar mb = getMenuBar();Menu m = mb.getMenu(2);mi.addActionListener(this);m.add(mi);} else {
cufile = e.getActionCommand();selectfile = cufile;}
if(player!= null)
player.close();try {
player = Manager.createPlayer(new MediaLocator(“file:” + cufile));}catch(Exception e2)
{
System.out.println(e2);return;}
if(player == null){
System.out.println(“无法创建播放器”);return;}
first = false;
setTitle(selectfile);
player.addControllerListener(this);player.prefetch();}
public void itemStateChanged(ItemEvent arg0){ }
public static void main(String[] args){
new MediaPlayer(“播放器”);}
public void controllerUpdate(ControllerEvent e){
Container tainer = getContentPane();if(e instanceof ControllerClosedEvent){
if(vc!= null){
remove(vc);vc = null;}
if(cc!= null){
remove(cc);cc = null;} }
if(e instanceof EndOfMediaEvent){
player.setMediaTime(new Time(0));if(loop)
player.start();return;}
if(e instanceof PrefetchCompleteEvent){
player.start();return;}
if(e instanceof RealizeCompleteEvent){
vc = player.getVisualComponent();if(vc!= null)
tainer.add(vc, BorderLayout.CENTER);
cc = player.getControlPanelComponent();cc.setBackground(Color.blue);if(cc!= null)
{ tainer.add(cc, BorderLayout.SOUTH);if(vc!= null){
pack();return;}
Else {
setSize(300, 75);setVisible(true);return;} } }
}
6.总结与说明
在做写程序实现功能的过程中,界面和基本功能的设计需要较强的逻辑思维,一不小心就容易出错,在具体的功能设计和实现的过程中要尽可能用最简单的语句实现基本的播放器功能。我觉得可以设计更多的菜单及菜单项目从而实现更多的功能,如:删除,保存等,还可以实现更多的背景效果或者更多可选择的皮肤,还可以对按钮添加音效效果,这样感觉整个音乐播放器更具有灵活性,媒体感更强烈一些,界面会更加丰富和生动一些。
通过自己做课程设计,自己设计界面,功能和设计功能的代码实现,将理论知识运用到实际操作中,加深了对理论知识的理解和记忆,在做程序设计的过程中,对很多代码的多次操作和重复使用,使得对很多基本的代码和相关的操作能够牢固的记忆。
第三篇:基于java的音乐播放器课程设计报告
Java课程设计报告
题目:java音乐播放器
姓
名 学
号 院
系 班
级 专
业 任课教师
1.设计内容及要求
能够实现简单的音乐播放器功能,如:打开本地文件,播放,暂停,停止,背景播放,单曲循环等等,界面充实,交互友好,可以添加多首歌曲目录
一个简单的基于java语言的音乐播放器,菜单栏:文件,播放控制和播放列表,文件菜单包含打开、循环和退出三个菜单项;播放控制菜单包含播放、暂停和停止三个菜单项,播放列表菜单则是当向里面添加歌曲之后才能够查看到里面所包含的歌曲目录。当播放歌曲时,可以调节音量大小或者设置是否静音;可以查看当前播放音乐的相关属性,如:歌曲名,歌手,发布时间,所属专辑等等。
2.需求分析
1、时间跟踪条:根据歌曲播放的进度,控制条自动进行追踪,用户可以
随时了解歌曲的播放进度
2、音量控制键:可以点击该控键进行音量大小的调节以及是否静音的设
置
3、属性查询键:通过该控键,用户可以查看当前播放音乐的相属性,获
取关于该歌曲的用户所需的相关信息。
4、菜单栏:
①文件:
打开:用户通过该菜单项打开本地音乐文件,听任何用户想
听的歌曲
循环:通过循环设置,用户可以重复的播放一首喜欢的歌曲
退出:退出音乐播放器,及退出该程序
②播放控制:
播放:选择歌曲之后,通过点击播放菜单项启动播放器播
放音乐
暂停:暂停当前正在播放的音乐
停止:停止当前正在播放的音乐
③播放列表:当用户通过文件打开本地音乐文件后,及相当于在
播放列表里面添加了歌曲,及形成相应的歌曲播放目录
3.总体设计
结合需求分析来看,整个设计包含了简单的菜单栏,根据用户需求设置了三个简单的实现基本操作的菜单,分别是:文件,播放控制,播放列表;根据具体的操作每个菜单还包含了相应的菜单项,文件:打开,循环,退出;播放控制:播放,暂停,停止;播放列表则没有菜单项,该菜单就是用来显示或者查看相应的歌曲目录的。
该音乐播放器设置了两个窗口,运行程序时打开的初始化欢迎界面,用户可以根据自己的需求进行菜单栏里面的基本操作和相应的设置,当用户添加或者打开音乐播放文件的时候,程序将会显示出第二个音乐文件播放窗口,与此同时,第一个初始化窗口将会自动隐藏,在音乐播放窗口里面用户可以进行相关的音乐播放的控制操作。
当用户进入音乐播放窗口时,该窗口有几个快捷控制的控键:时间追踪轴:可以实现播放的前进、后退功能,根据用户需求调节音乐的播放进度等;音量控制:设置静音,打开扬声器或者调节音量大小;播放列表:查看当前播放音乐的相关属性。4.主要功能设计流程
5.系统实现及测试:
(一)JMF(java媒体框架)简介
JMF 即Java媒体框架。其核心框架支持不同媒体,如音频输出和视频输出,包括时间的时钟同步。它是一个标准的扩展框架,允许用户制作纯音频流和视频流。
JMF实际上是Java的一个类包。它包括了一个开放的媒体架构,可使开发人员灵活采用各种媒体回放、捕获组件,或采用他们自己的定制的内插组件。
JMF软件是Java Media系列软件的一部分。采用各种Java Media API,软件开发商人员就能容易、快速地为他们已有的各种应用程序和客户端,Java小程序增添丰富的媒体功能,如流式视频、3D图像和影像处理等。就是 说,各种Java Media API发挥了Java平台的固有优势,将“编写一次,到处运行”的能力扩展到了图像、影像和数字媒体等各种应用领域,从而大大缩减了开发时间和降低了开发 成本。
在开发JMF 应用程序之前要完全理解JMF 的体系架构、接口和类。就拿我们的家用摄像机系统作个例子。首先用摄像机拍摄内容,拍摄下来的内容录制在DV带中。DV带可以放在放像机里播放、放像机提供视频信号给电视机,提供音频信号给音箱,这样我们就可以在电视机上看到画面,从音箱里听到声音。JMF API 提供的也是同样的模型。
JMF 提供的模型可大致分为七类
* 数据源(Data source)
* 截取设备(Capture Device,包括视频和音频截取设备)
* 播放器(Player)
* 处理器(Processor)
* 数据池(DataSink)
* 数据格式(Format)
* 管理器(Manager)
如果只是想观看捕获的内容,只需要使用捕获数据源创建播放器Player即可。如果想把捕获的数据发送到网络或者保存起来,就需要创建处理器Processor。
基本步骤是首先获取视频、音频捕获设备的信息,然后再根据取得的设备信息确定设备的位置。找到设备的位置以后,调用ManageCreatePlayer方法创建Player,当Player开始播放的时候,就开始了捕获的过程。
有多种方法获得捕获设备信息,可以通过查询指定的格式,也可以查询特定的设备名字。Player准备好播放数据,当Player发出这个事件时,就可以获取播放器的可视面板和控制面板了。具体步骤如下:
1.先把所有的捕获设备调出来
2.创建Player,当Play开始的时候,就开始了音频捕获的过程
3.以MediaLocator为参数,创建Player 4.为PLAYER添加监听器,以便监听RealizeComplete事件
(二)代码实现
(1)添加库、包等相关文件 import javax.media.ControllerEvent;import javax.media.ControllerListener;import javax.media.EndOfMediaEvent;import javax.media.PrefetchCompleteEvent;import javax.media.RealizeCompleteEvent;import javax.media.*;import javax.swing.*;import java.awt.*;
import java.awt.event.*;
(2)初始化窗口
1代码实现
private void init(){
// TODO Auto-generated method stub
this.setLayout(new BorderLayout());
JPanel lrcPanel = new JPanel();
JPanel controP= new JPanel();
jta = new JTextArea(22,35);
jta.setBackground(Color.black);
jta.setLineWrap(true);
jta.setWrapStyleWord(true);
jta.setEditable(false);
lrcPanel.add(new JScrollPane(jta));
lrcPanel.setBackground(Color.black);
lrcPanel.setVisible(true);
JButton Jstart= new JButton(“");Jstart.setIcon(new ImageIcon(”start.png“));
Jstart.addActionListener(new ActionListener(){
@Override public void actionPerformed(ActionEvent arg0){
// TODO Auto-generated method stub
start();} });JButton Jpause=new JButton();Jpause.setIcon(new ImageIcon(”停止.png“));Jpause.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){
stop();
} });JButton Jnext =new JButton();Jnext.setIcon(new ImageIcon(”next.png“));Jnext.addActionListener(new ActionListener(){
@Override public void actionPerformed(ActionEvent e){
// TODO Auto-generated method stub
next();} });JButton Jprior =new JButton();Jprior.setIcon(new ImageIcon(”back.png“));Jprior.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){
back();} });controP.setLayout(new FlowLayout());controP.add(Jprior);controP.add(Jstart);controP.add(Jpause);
} controP.add(Jnext);
this.add(lrcPanel,BorderLayout.CENTER);this.add(controP,BorderLayout.SOUTH);
(3)音乐播放窗口机基本功能的实现 ①界面
②代码实现
// 播放方法
public void start(){
if(isplaying==false){
try {
player =
Manager.createPlayer(new File(mp3List.get
(mp3NO)).toURI().toURL());
jta.setText(null);
} catch(NoPlayerException e){
// TODO 自动生成 catch BufferedReader(new FileReader(lcf));
String s;
块
e.printStackTrace();
System.out.println(”不能播放此文件!“);
return;
} catch(IOException e){
// TODO 自动生成 catch 块
e.printStackTrace();
return;
}
if(player == null){
System.out.println(”播放文件为空!“);
return;
}
player.addControllerListener(this);
// 提取媒体内容
player.prefetch();
isplaying=true;//正在播放一首歌
setLrc();
} }
private void setLrc(){
// TODO Auto-generated method stub
File lrcfile = new File(lrcpath);
if(!lrcfile.exists()){
lrcfile.mkdir();
}
String lrcFName = getlrcFName();
BufferedReader bReader;
File lcf= new File(lrcpath+lrcFName+”.lrc“);
System.out.println(lcf.getName());
try {
bReader = new while((s=bReader.readLine())!= null){
jta.append(” “+s);
jta.append(”n“);
}
} catch(Exception e){
// TODO Auto-generated catch block
jta.setText(”没有歌词“);
System.out.println(”没有歌词文件!“);
}
}
private String getlrcFName(){//解析歌曲名;
// TODO Auto-generated method stub
String musicPath = mp3List.get(mp3NO);
String s =musicPath.substring(11);
System.out.println(s);
String []str = s.split(”.“);
String lrcFName=str[0];
System.out.println(lrcFName);
return lrcFName;}
public void stop(){
player.stop();
isplaying=false;}
public void next(){
if(isplaying==true)
stop();
if(mp3NO mp3NO++; start(); } else{ jta.setText(”没有下一首了 // 当提取媒体的内容结束 if(e instanceof PrefetchCompleteEvent){ System.out.println(“内容结束”); player.start(); return; }(<_>“); } } public void back(){ if(isplaying) stop(); if(mp3NO>0){ mp3NO--; start(); } else jta.setText(”已经是第一首歌了(<_>)“);} public void controllerUpdate(ControllerEvent e){ // 当媒体播放结束时,循环播放 if(e instanceof EndOfMediaEvent){ isplaying=false; mp3NO++; System.out.println(mp3NO); if(mp3NO < mp3List.size()){ this.start(); } return; } // 当实例化后 if(e instanceof RealizeCompleteEvent){ System.out.println(”实例化“); // pack();//执行pack()操作 return; } } public void setMp3List(){ File file = new File(musicpath); if(!file.exists()){ file.mkdir(); } File[] mcFiles; mcFiles = file.listFiles(); if(mcFiles!=null){ for(File f : mcFiles){ System.out.println(f.getPath()); mp3List.add(f.getPath()); } }else System.out.println(”MyMusic中没有歌曲文件"); } 6.总结与说明 在做写程序实现功能的过程中,界面和基本功能的设计需要较强的逻辑思维,一不小心就容易出错,在具体的功能设计和实现的过程中要尽可能用最简单的语句实现基本的播放器功能。我觉得可以设计更多的菜单及菜单项目从而实现更多的功能,如:删除,保存等,还可以实现更多的背景效果或者更多可选择的皮肤,还可以对按钮添加音效效果,这样感觉整个音乐播放器更具有灵活性,媒体感更强烈一些,界面会更加丰富和生动一些。 通过自己做课程设计,自己设计界面,功能和设计功能的代码实现,将理论知识运用到实际操作中,加深了对理论知识的理解和记忆,在做程序设计的过程中,对很多代码的多次操作和重复使用,使得对很多基本的代码和相关的操作能够牢固的记忆。 一. 课程设计目的 1.通过D/A装换器产生模拟信号,使PC机作为简易音乐播放器。2.了解利用数模转换器产生音乐的基本方法。 二.课程设计任务 设计并实现一个键控音乐播放器。要求: (1)自己选用合适的芯片,不少于两种。 (2)自行设计电路并使用汇编语言编写程序完成键控音乐播放器功能。 (3)该播放器有若干首歌曲可以选择,开始时输出说明,要用户选择要播放的歌曲,然后根据用户按键进行播放、退出或出错提示。 三、总体设计方案 1、总体设计方案一 所有音乐都是由各个不同频率的音阶和其延续时间的长短来实现的。不同的音乐是由各个音阶按某种排列各自播放一定时间形成的,将各音乐音阶和其延续时间存在数据段中,然后根据不同按键值选择不同的音阶和时间表,再使用计数器产生该音阶频率。而我们学过的有计数器可以产生各种频率,所以我们主要采用计数器8253产生各音符,用8255并行接口来控制扬声器的开关,达到播放音乐的功能。 2、总体设计方案二 可以使用0832(数模转换器)来产生频率,原理图: 更连续,效果更好点。 提出这个方案是因为我想产生模拟信号,来驱动扬声器,这样产生的声音更加圆润感觉我们想把一个周期的波形分成32份,然后每份给8253一个值让他转换成模拟信号,不同的频率可以用8253计数器控制,比如要产生261Hz的频率,使用1MHz的话,周期就为1/261=3.83ms,分成32份,每份间隔时间就是3.83ms/32=0.12ms,换句话说就是送计数器0的初值为1M/261/32=120次。 3、各个音符的对应频率表: 音符 频率/HZ 半周期/us 音符 频率/HZ 半周期/us 低1DO 262 1908 #4FA# 740 0676 #1DO# 277 1805 中5SO 784 0638 低2RE 294 1700 #5SO# 831 0602 #2RE# 311 1608 中6LA 880 0568 低3M 330 1516 #6LA# 932 0536 低4FA 349 1433 中7SI 988 0506 #4FA# 370 1350 高1DO 1046 0478 低5SO 392 1276 #DO# 1109 0451 #5SO# 415 1205 高2RE 1175 0426 低6LA 440 1136 #2RE# 1245 0402 #6LA# 466 1072 高3M 1318 0372 低7SI 494 1012 高4FA 1397 0358 中1DO 523 0956 #4FA# 1480 0338 #1DO# 554 0903 高5SO 1568 0319 中2RE 578 0842 #5S0# 1661 0292 #2RE# 622 0804 高6LA 1760 0284 中3M 659 0759 #6LA# 1865 0268 中4FA 698 0716 高7SI 1976 0253 四.部分电路设计及功能解说 1、频率发生电路 使用8253产生音符频率。8253采用方式3,产生方波信号,根据输入计数初值的不同产生不同频率的方波信号来驱动扬声器。 2、扬声器开关控制电路 使用8255并行接口芯片来控制扬声器的开和关,PC0始终接低电平,PA0和8253的OUT0接在与门上,这样只有PA0=1时扬声器才有可能开通,否则不发声。关闭的方法是,从PC口读入数据再从PA口输出;而开扬声器时只要在输出PA口数据前对数据进行一个取反操作就可以了。 设某音符频率为fHz,而CLK脉冲是1MHz,则计数初值N=1M/f。8253的控制端口为28BH,控制字为36H。五.硬件接线图 六.软件设计流程图 1、总流程图 开始输出说明读取按键是‘1’?N是‘2’?Y播放曲1Y播放曲2N是‘3’?Y播放曲3N是‘0’?Y结束Y选择无效程序总流程图 2、音乐播放子程序流程图 开始保护现场曲N各音符频率设置曲N各音符时间设置读取频率F频率是-1 ?Y恢复现场N读取时间T结束返回计算机计数次数送计数器,产生该频率F信号启动喇叭延时T关闭喇叭音符间延时播音流程图 七.程序段功能汇总 1、MAIN程序 MAIN程序是总程序,输出说明,等待用户按键并读取键值。根据不同的按键选择调用播音子程序播放不同的歌曲。 2、PLAY子程序 PLAY子程序是播音子程序,SI指向音节表中的频率,BP指向音节表中的时间。从SI的指向的音节表中取一个频率,只要不是-1,即有效就再读取时间,然后计算计数初值送入计数器,产生各种频率。开启扬声器,根据所取的时间调用若干次延时子程序。这段时间扬声器就发出该频率的声音,延时结束,就关闭扬声器,调用音节之间的小延时程序。最后修改SI和BP,指向下一个频率,重复上面的工作。 3、DELAY子程序和DELAY_OFF子程序 两个都是子程序,采用空操作循环多次的方法,只是第二个延时时间较短,大概为5ms。八.程序清单 SSEG SEGMENT PARA STACK 'stack' dw 100h dup(0);Resize the stack by changing the number '100' SSEG ENDS DSEG SEGMENT ;TO DO: Add your program's data here INFO1 DB 0DH,0AH,'--------------------------',0DH,0AH,'THERE ARE 3 SONGS:',0DH,0AH,0DH,0AH,'$' INFO2 DB '1.HAPPY BIRTHDAY',0DH,0AH,'$' INFO3 DB '2.SHEEP',0DH,0AH,'$' INFO4 DB '3.RIVER',0DH,0AH,'$' INFO5 DB '0.EXIT',0DH,0AH,'$' INFO6 DB 'YOU HAVE CHOSEN :$' INFO7 DB 'THANK YOU FOR YOUR USE',0DH,0AH,'$' INFO8 DB '---------------------------',0DH,0AH,'PRESS THE KEY TO SELECT SONG!',0DH,0AH,'$' INFO9 DB 0DH,0AH,'-------------------',0DH,0AH,'|INVALID SELECTION|',0DH,0AH,'-------------------',0DH,0AH,'$' FREG1 DW 2 dup(262),294,262,349,262,262,294,262,392,249,262,262,523,440,349 ;曲1的频率 DW 330,294,466,266,440,349,392,349,-1 TIME1 DW 1,1,2,2,2,4,1,1,2,2,2,4,1,1,2,2,2,2,4,1,1,2,2,2,4 ;曲1的时间 FREG2 DW 330,294,262,294,3 DUP(330) ;曲2的频率 DW 3 DUP(294),330,392,392 DW 330,294,262,294,4 DUP(330)DW 294,294,330,294,262,-1 TIME2 DW 6 DUP(1),2 ;曲2的时间 DW 2 DUP(1,1,2)DW 12 DUP(1),4 FREG3 DW 330,392,330,294,330,392,330,294,330,330,392,330,294,262,294,330,392,294 ;曲3的频率 DW 262,262,220,196,220,262,294,332,262,-1 TIME3 DW 3 DUP(2),1,1,2,1,1,4 ;曲3的时间 DW 2 DUP(2,2,1,1),4 DW 3 DUP(2,1,1,1),4 DSEG ENDS CSEG SEGMENT assume cs:CSEG, ds:DSEG, es:DSEG, ss:SSEG INIT PROC;Initialize procedure mov ax, dseg mov ds, ax mov es, ax;TO DO: Add your initialize code here(as your requirement)ret ;return to the MAIN procedure INIT ENDP MAIN PROC ;Here is your program entry point call INIT;call the INIT procedure to initialize the program ;**TO DO: Add your main code here** RE: MOV DX,28BH ;关闭扬声器 MOV AL,89H OUT DX,AL MOV DX,28AH IN AL,DX MOV DX,288H OUT DX,AL LEA DX,INFO1 MOV AH,09H INT 21H LEA DX,INFO2 INT 21H LEA DX,INFO3 INT 21H LEA DX,INFO4 INT 21H LEA DX,INFO5 INT 21H LEA DX,INFO8 INT 21H MOV AH,01H INT 21H CMP AL,'1' JE MUSIC1 CMP AL,'2' JE MUSIC2 CMP AL,'3' JE MUSIC3 CMP AL,'0' JE EXIT LEA DX,INFO9 MOV AH,09H INT 21H JMP RE ;输出说明信息 ;读取按键 ;根据不同的按键播放不同的曲子 ;无效选择,输出错误提示 MUSIC1: MOV SI,OFFSET FREG1 ;指向曲1的表 MOV BP,OFFSET TIME1 CALL PLAY JMP RE MUSIC2: MOV SI,OFFSET FREG2 ;指向曲2的表 MOV BP,OFFSET TIME2 CALL PLAY JMP RE MUSIC3: MOV SI,OFFSET FREG3 ;指向曲3的表 MOV BP,OFFSET TIME3 CALL PLAY JMP RE EXIT: MOV DX,28BH ;关闭扬声器 MOV DX,28AH IN AL,DX MOV DX,288H OUT DX,AL LEA DX,INFO7 ;输出欢迎使用信息,增加界面友好度 MOV AH,09H INT 21H mov ax, 4c00h;The end of the program, return to the system MOV AL,89H OUT DX,AL int 21h MAIN ENDP ;TO DO: Add other procedures(PROC)here(as your requirement) ;THE PROGRAMME OF PLAYING THE MUSIC PLAY PROC ;PLAY子程序,功能上面介绍过 L1: MOV BX,DS:[SI] ;取频率 CMP BX,-1 ;看是否有效 JE L0 ;无效就退出 MOV CX,DS:[BP] ;读取时间 MOV DL,CL ;保存时间 ADD DL,30H MOV AH,02H INT 21H MOV DX,0FH ;计算计数初值,1M的十六进制为0F4240H MOV AX,4240H DIV BX MOV BX,AX MOV DX,283H ;设置计数器工作方式 MOV AL,36H OUT DX,AL MOV DX,280H ;输入计数初值 MOV AX,BX OUT DX,AL MOV AL,AH OUT DX,AL MOV DX,28BH MOV AL,89H OUT DX,AL MOV DX,28AH IN AL,DX NOT AL MOV DX,288H OUT DX,AL ROD:CALL DELAY LOOP ROD MOV DX,28BH MOV AL,89H OUT DX,AL MOV DX,28AH IN AL,DX MOV DX,288H OUT DX,AL CALL DELAY_OFF ADD SI,2 ADD BP,2 JMP L1 L0: RET PLAY ENDP DELAY PROC PUSH AX PUSH BX PUSH CX PUSH DX MOV BX,09FH LL1:MOV CX,0FFFFH ;开扬声器 ;延时 ;关扬声器 ;延时子程序 ;循环这么多次 ;音节间延时 LOP: LOOP LOP DEC BX JNZ LL1 POP DX POP CX POP BX POP AX RET DELAY ENDP DELAY_OFF PROC PUSH AX PUSH BX PUSH CX PUSH DX MOV BX,0FH LL2:MOV CX,0CFFFH LOP2: LOOP LOP2 DEC BX JNZ LL2 POP DX POP CX POP BX POP AX RET DELAY_OFF ENDP CSEG ENDS;TO DO: Add other segments here(as your requirement) END MAIN 九.试验结果和分析 1、试验结果: 程序初始运行界面 如果按错了键,会出现如下界面 如果选择正确,将出现如下界面: 2、分析 这是按照方案一做的结果,按1~3分别播放“生日快乐”等歌,但由于本组人对音乐都是外行,各音阶频率的排序和延时时间搭配不好,导致音乐严重走调,但基本能听出不是噪音。 按照方案二做的电路和程序,无论怎么样都不出声,后来我们直接送数据到0832产生三角波信号(程序在我们的一次作业中写的)。还是无法让扬声器发出声音,因此按这个方案失败了。 十.课程设计总结和体会 1.实验过程中碰到了很多的难题和障碍,我认识到平时基础知识的重要性,只有能够熟练的掌握才能在实验过程中得心应手,否则一步错则整个试验都会陷入困境,因而,严谨的态度是试验成功的重要保障! 2.通过这次课程设计,我们对各个芯片有了进一步的了解,对各个芯片的功能有了更深刻的认识和体会,平时上课的理论知识只是停留在理论的层面,只有通过了这样的试验才能更好的体会到,做到了理论和实际的相结合,使理论知识真正运用到了实践中去。在课程设计过程中,同组人员之间相互合作,共同研究使我更加坚信了团体的力量。在团体的共同协作和努力下,任何的难题都可以被解决! 3.我们大家在实验的时候都团结合作,遇到问题时候一起探讨,增强了我们的合作精神。 十一.参考文献 1、《〈微机原理与接口技术〉学生实验指导书》 扬州大学 罗加奇 2、《微机原理及应用》 机械工业出版社 胡钢 主编 《微机原理与接口技术》课程设计 关智杰 一、课程设计的任务和目的 课程设计题目:音乐播放器 课程设计的实现目的:本课程设计主要是通过汇编语言用软件编程的方法实现简单的音乐播放功能。通过在《微机原理与接口技术》课程上所学的汇编知识和8253/8254芯片相关知识,来完成本课程设计;用汇编程序完成键控音乐播放器的,用8253/8254定时器来产生声音。该播放器有若干首歌曲可以选择,开始时输出说明,要用户选择要播放的歌曲,然后根据用户按键进行播放、退出或出错提示。通过课程设计环节来加强对所学知识的理解和应用。 二、课程设计相关知识 2.1 定时/计数器8253/58254 在微机及控制系统中,经常要用到定时信号。如系统的日历时钟,动态存储器刷新。对外部执行机构控制时也需要定时中断、定时检测、定时查询等。定时的方法主要是两种: 软件定时:利用指令的执行时间设计循环程序,使CPU 执行延迟子程序的时间就是定时时间。缺点:执行延迟时,CPU 一直被占用,降低了CPU 的效率。 硬件定时:用计数器/定时器作为主要硬件,在软件简单指令的控制下产生精确的时间延迟。突出优点为计数时不占用CPU 时间,如利用定时器/计数器产生中断信号,可建立多作业环境,提高了CPU 效率。 作为定时器可用8253或者8254,二者功能基本相同,知识工作的最高频率不一样。本实验就采用了8254,其主要功能为: (1)每片上有3 个独立的16 位的减计数器通道。 (2)对于每个计数器,都可以单独作为定时器或计数器使用,并且都可以按照二进制或十进制来计数。 (3)每个通道都有6 种工作方式,都可以通过程序设置或改变。(4)每个计数器的速率可高达10MHz。 主要部分有:数据总线缓冲器、读/写控制逻辑、控制字寄存器、计数通道0#、1#、2#: 内部结构如下图: 《微机原理与接口技术》课程设计 关智杰 8254内部结构 2.2 8254外部引脚 8254芯片是具有24个引脚的双列直插式集成电路芯片,其引脚分布如图所示。8254芯片的24个引脚分为两组,一组面向CPU,另一组面向外部设备,各个引脚及其所传送信号的情况,介绍如下: 8254的引脚 (1)D7~D0:双向、三态数据线引脚,与系统的数据线连接,传送控制、数据及状态信息。 (2)RD:来自于CPU的读控制信号输入引脚,低电平有效。(3)WR:来自于CPU的写控制信号输入引脚,低电平有效。(4)CS:芯片选择信号输入引脚,低电平有效。 (5)A1、A0:地址信号输入引脚,用以选择8254芯片的通道及控制字寄存器。(6).VCC及GND:+5V电源及接地引脚。 (7)CLKi: i=0,1,2,第i个通道的计数脉冲输入引脚,8254规定,加在CLK引脚的输入时钟信号的频率不得高于2.6MHZ,即时钟周期不能小于380ns。 《微机原理与接口技术》课程设计 关智杰 (8)GATEi: i=0,1,2,第i个通道的门控信号输入引脚,门控信号的作用与通道的工作方式有关。 (9)OUTi:i=0,1,2,第i个通道的定时/计数到信号输出引脚,输出信号的形式由通道的工作方式确定,此输出信号可用于触发其它电路工作,或作为向CPU发出的中断请求信号。 2.3 8254端口地址 8254控制字 说明 :(1)8254每个通道对输入CLK按二进制或二十进制从预置值开始减1计数,减到0时从OUT输出一个信号。 (2)8254编程时先写控制字,再写时间常数。 2.4 8254工作方式 《微机原理与接口技术》课程设计 关智杰 (1)方式0:计数结束产生中断方式 当写入控制字后,OUT变为低电平,当写入初值后立即开始计数,当计数结束时,变成高电平。 (2)方式1:可编程单次脉冲方式 当初值装入后且GATE由低变高时,OUT变为低电平,计数结束变为高电平。(3)方式2:频率发生器方式 当初值装入时,OUT变为高;计数结束,OUT变为低。该方式下如果计数未结束,但GATE为低时,立即停止计数,强制OUT变高,当GATE再变高时,便启动一次新的计数周期。 (4)方式3:方波发生器 当装入初值后,在GATE上升沿启动计数,OUT 输出高电平; 当计数完成一半时,OUT输出低电平。方式3与方式2的工作方式类似,也是在初始化完成后能重复循环计数,只是输出的波形不同。 (5)方式4:软件出发选通方式 进入工作方式4,OUTi输出高电平。装入计数值n后,如果GATE为高电平,则立即开始减“1”计数,直到计数值减到“0”为止,OUTi输出宽度为一个CLKi周期的负脉冲。由软件装入的计数值只有一次有效,如果要继续操作,必须重新置入计数初值n。如果在操作的过程中,GATE变为无效,则停止减“1”计数,到GATE再次有效时,重新从初值开始减“1”计数。 (6)方式5:硬件触发方式计数 进入工作方式5,OUTi输出高电平,硬件触发信号由GATE端引入。因此,开始时GATE应输入为0,装入计数初值n后,减“1”计数并不工作,一定要等到硬件触发信号由GATE端引入一个正阶跃信号,减“1”计数才会开始,待计数值计到“0”,OUTi将输出负脉冲,其宽度固定为一个CLKi周期,表示定时时间到或计数次数到。 三、程序设计思路 所有音乐都是由各个不同频率的音阶和其延续时间的长短来实现的。不同的音乐是由各个音阶按某种排列各自播放一定时间形成的,将各音乐音阶和其延续时间存在数据段中,然后根据不同按键值选择不同的音阶和时间表,再使用计数器产生该音阶频率。 CPU通过对定时器的通道2(端口地址为42)进行编程,使其I/O寄存器接收一个控制声音频率的16位计数值,端口61H的最低控制通道2门控的开断。以产生特殊的音响。当定时器接收的计数值为533H时,能产生896Hz的声音,因此产生其他频率的计数值就可算出来: 《微机原理与接口技术》课程设计 关智杰 533Hz×896÷频率=1234DC÷频率 在送出频率计数值之前,还要给方式寄存器送一个方式值,该数决定对哪一个通道编程,采用什么模式,送入通道的计数值是一字节还是两字节,是二进制码还是BCD码。其位组合的格式如下: 当通道2用于发声时,采用的是模式3,在模式3下,输出线为“1”和为“0”的时间各占计数时间的一半,因而产生一系列间隔均匀的脉冲。 产生指定频率声音的程序段如下: MOV AL,0B6H OUT 43H,AL ;43H为8254的控制字端口 MOV DX,12H MOV AX,34DCH DIV DI ;(DI)=频率 OUT 42H,AL ;42H为8254的通道2端口 MOV AL,AH MOV 42H,AL 从定时器输出的方波信号,经功率放大和滤波后驱动扬声器。送到扬声器的信号还受到了从并行接口芯片8255(端口地址为61H)来的双重控制,端口61H的最低位控制通道2的门控开断,以产生特殊的音频信号,端口61H的PA1位和定时器的输出信号同时作为与门的输入,PA0和PA1位可由程序决定为0还是为1。显然只有PA0和PA1都是1时,才能使扬声器发出声音。控制音长的时间可以简单地通过反复执行指令来得到。我们知道执行2801次LOOP指令约需要10MS的时间。因此用10MS的倍数值来控制扬声器开关的时间间隔,就可控制发声的音长了。实现程序如下: IN AL,61H MOV AH,AL OR AL,3 OUT 61H,AL;开扬声器 L: MOV CX,2801 DY:LOOP DY DEC BX JNZ L MOV AL,AH OUT 61H,AL;关扬声器 《微机原理与接口技术》课程设计 关智杰 四、功能流程图及子程序说明 1、总流程图 MAIN程序:MAIN程序是总程序,输出说明,等待用户按键并读取键值。根据不同的按键选择调用播音子程序播放不同的歌曲。 开始输出说明读取按键是‘1’?N是‘2’?Y播放曲1Y播放曲2N是‘3’?Y播放曲3N是‘0’?Y结束Y选择无效程序总流程图 2、音乐播放子程序流程图 PLAY子程序:PLAY子程序是播音子程序,SI指向音节表中的频率,BP指向音节表中的时间。从SI的指向的音节表中取一个频率,只要不是-1,即有效就再读取时间,然后计算计数初值送入计数器,产生各种频率。开启扬声器,根据所取的时间调用若干次延时子程序。这段时间扬声器就发出该频率的声音,延时结束,就关闭扬声器,调用音节之间的小延时程序。最后修改SI和BP,指向下一个频率,重复上面的工作 DELAY子程序和DELAY_OFF子程序:两个都是子程序,采用空操作循环多次的方法,只是第二个延时时间较短,大概为5ms。 《微机原理与接口技术》课程设计 关智杰 开始保护现场曲N各音符频率设置曲N各音符时间设置读取频率F频率是-1 ?Y恢复现场N读取时间T结束返回计算机计数次数送计数器,产生该频率F信号启动喇叭延时T关闭喇叭音符间延时播音流程图 五、试验结果截屏: 初始界面: 如果按错了键,会出现如下界面: 《微机原理与接口技术》课程设计 关智杰 如果选择正确,将出现如下界面: 六、参考文献 【1】李长青.微机原理与接口技术.徐州:中国矿业大学出版社,2006 【2】沈美明.汇编语言程序设计实验教程.北京:清华大学出版社,2002年 【3】周明德.微机原理与接口技术.北京:人民邮电出版社,2002年 七、总结 在本次设计中,可以说是一次成功的经验。在我们学完了《微型计算机原理与接口技术》这门课的基础上来做这个设计,通过设计后,使我们对这门课的理论知识的理解有很大程度上的加强。微机原理这门课程本身是一门实验性和工程性很强的专业技术课,因此不仅要重视理论教学,更应注意实践技能的培养和训练。课程设计是这门课程的一个重要环节,通过课程设计,巩固、加深和拓宽了学习的理解,本课程设计的重点目标是使用汇编语言,而不过多涉及硬件方面的太多知识。 《微机原理与接口技术》课程设计 关智杰 在编程方面我通过本次课程设计学到了很多。一开始面对很长的程序往往有畏难情绪,感觉无法下手,没办法只能硬着头皮啃下去,多看几个和音乐播放有关的汇编程序,然后我就能慢慢看懂了并理解了别的作者的设计思路。然后再根据自己的思路,对照本人在图书馆借的汇编语言指导书慢慢编写符合自己思路的程序。一次写出来的程序肯定不会是正确的,还需要进一步调试它。检查程序过程中,在充分思考的基础上多次实验是检查改正程序的良方。编写程序的过程中,体会最深的是子程序的调用和程序的条理问题,一个程序就算功能实现了,但是也要使主程序和子程序的条理分明,易读性高,才能算一个比较好的程序。调试程序中,学习了DEBUG 的使用,DEBUG对检查程序的错误作用很大。同时,也要灵活使用各种调试方法,来缩小寻找错误的范围。 书到用时方恨少。在课程设计过程中,我才体会到这句话的深意。课堂上学的8254的知识和汇编语言都太少,还不足以完成本次课设,为此我经常跑图书馆借了各种各样的工具书。有的书用处较大,有的书仅能用到一小块知识,就是这样,一步步在知识的海洋里我寻觅着自己需要的东西,确实克服了不少困难,解决了不少问题。或许坎坷才能更好的使人成长。在这次的课程设计中,我的收获是不但做出了一个符合要求的音乐播放器,而且为自己积累了一些宝贵的经验。同时我也对音乐方面的频率知识有了一些认识,我想如果不是本次课程设计中用到这方面知识,我这辈子可能没有机会去接触这方面的知识了。这,或许也是我比别的同学多出的一点收获吧! 六、附录 1、源程序代码: SSEG SEGMENT PARA STACK 'stack' dw 100h dup(0);Resize the stack by changing the number '100' SSEG ENDS DSEG SEGMENT INFO1 DB 0DH,0AH,'--------------------------',0DH,0AH,'THERE ARE 3 SONGS:',0DH,0AH,0DH,0AH,'$' INFO2 DB '1.HAPPY BIRTHDAY',0DH,0AH,'$' INFO3 DB '2.SHEEP',0DH,0AH,'$' INFO4 DB '3.RIVER',0DH,0AH,'$' INFO5 DB '0.EXIT',0DH,0AH,'$' INFO6 DB 'YOU HAVE CHOSEN :$' INFO7 DB 'THANK YOU FOR YOUR USE',0DH,0AH,'$' INFO8 DB '---------------------------',0DH,0AH,'PRESS THE KEY TO SELECT SONG!',0DH,0AH,'$' INFO9 DB 0DH,0AH,'-------------------',0DH,0AH,'|INVALID 《微机原理与接口技术》课程设计 关智杰 SELECTION|',0DH,0AH,'-------------------',0DH,0AH,'$' FREG1 DW 2 dup(262),294,262,349,262,262,294,262,392,249,262,262,523,440,349 ;曲1的频率 DW 330,294,466,266,440,349,392,349,-1 TIME1 DW 1,1,2,2,2,4,1,1,2,2,2,4,1,1,2,2,2,2,4,1,1,2,2,2,4 ;曲1的时间 FREG2 DW 330,294,262,294,3 DUP(330) ;曲2的频率 DW 3 DUP(294),330,392,392 DW 330,294,262,294,4 DUP(330)DW 294,294,330,294,262,-1 TIME2 DW 6 DUP(1),2 ;曲2的时间 DW 2 DUP(1,1,2)DW 12 DUP(1),4 FREG3 DW 330,392,330,294,330,392,330,294,330,330,392,330,294,262,294,330,392,294;曲3的频率 DW 262,262,220,196,220,262,294,332,262,-1 TIME3 DW 3 DUP(2),1,1,2,1,1,4 ;曲3的时间 DW 2 DUP(2,2,1,1),4 DW 3 DUP(2,1,1,1),4 DSEG ENDS CSEG SEGMENT assume cs:CSEG, ds:DSEG, es:DSEG, ss:SSEG INIT PROC ;初始化程序 mov ax, dseg mov ds, ax mov es, ax INIT ENDP MAIN PROC ;程序入口 call INIT RE: MOV DX,28BH ;关闭扬声器 MOV AL,89H OUT DX,AL MOV DX,28AH IN AL,DX MOV DX,288H OUT DX,AL LEA DX,INFO1 ;输出说明信息 MOV AH,09H INT 21H LEA DX,INFO2 INT 21H LEA DX,INFO3 INT 21H 《微机原理与接口技术》课程设计 关智杰 LEA DX,INFO4 INT 21H LEA DX,INFO5 INT 21H LEA DX,INFO8 INT 21H MOV AH,01H ;读取按键 INT 21H CMP AL,'1' ;根据不同的按键播放不同的曲子 JE MUSIC1 CMP AL,'2' JE MUSIC2 CMP AL,'3' JE MUSIC3 CMP AL,'0' JE EXIT LEA DX,INFO9 MOV AH,09H INT 21H JMP RE MUSIC1: MOV SI,OFFSET FREG1 MOV BP,OFFSET TIME1 CALL PLAY JMP RE MUSIC2: MOV SI,OFFSET FREG2 MOV BP,OFFSET TIME2 CALL PLAY JMP RE MUSIC3: MOV SI,OFFSET FREG3 MOV BP,OFFSET TIME3 CALL PLAY JMP RE EXIT: MOV DX,28BH MOV AL,89H OUT DX,AL MOV DX,28AH IN AL,DX ;无效选择,输出错误提示 ;指向曲1的表;指向曲2的表;指向曲3的表;关闭扬声器 《微机原理与接口技术》课程设计 关智杰 MOV DX,288H OUT DX,AL LEA DX,INFO7 ;输出欢迎使用信息,增加界面友好度 MOV AH,09H INT 21H mov ax, 4c00h;The end of the program, return to the system int 21h MAIN ENDP PLAY PROC L1: MOV BX,DS:[SI] CMP BX,-1 JE L0 MOV CX,DS:[BP] MOV DL,CL ADD DL,30H MOV AH,02H INT 21H MOV DX,0FH MOV AX,4240H DIV BX MOV BX,AX MOV DX,283H MOV AL,36H OUT DX,AL MOV DX,280H MOV AX,BX OUT DX,AL MOV AL,AH OUT DX,AL MOV DX,28BH MOV AL,89H OUT DX,AL MOV DX,28AH IN AL,DX NOT AL MOV DX,288H OUT DX,AL ROD:CALL DELAY LOOP ROD MOV DX,28BH MOV AL,89H ;PLAY子程序,功能上面介绍过 ;取频率 ;看是否有效 ;无效就退出 ;读取时间 ;保存时间 ;计算计数初值,1M的十六进制为0F4240H ;设置计数器工作方式 ;输入计数初值 ;开扬声器 ;延时 ;关扬声器 《微机原理与接口技术》课程设计 关智杰 OUT DX,AL MOV DX,28AH IN AL,DX MOV DX,288H OUT DX,AL CALL DELAY_OFF ;音节间延时 ADD SI,2 ADD BP,2 JMP L1 L0: RET PLAY ENDP DELAY PROC PUSH AX PUSH BX PUSH CX PUSH DX MOV BX,09FH LL1:MOV CX,0FFFFH LOP: LOOP LOP DEC BX JNZ LL1 POP DX POP CX POP BX POP AX RET DELAY ENDP DELAY_OFF PROC PUSH AX PUSH BX PUSH CX PUSH DX MOV BX,0FH LL2:MOV CX,0CFFFH LOP2: LOOP LOP2 DEC BX JNZ LL2 POP DX POP CX POP BX POP AX RET ;延时子程序 ;循环这么多次 《微机原理与接口技术》课程设计 关智杰 DELAY_OFF ENDP CSEG ENDS END MAIN 2、各个音符的对应频率表: 音符 频率/HZ 半周期/us 音符 频率/HZ 半周期/us 低1DO 262 1908 #4FA# 740 0676 #1DO# 277 1805 中5SO 784 0638 低2RE 294 1700 #5SO# 831 0602 #2RE# 311 1608 中6LA 880 0568 低3M 330 1516 #6LA# 932 0536 低4FA 349 1433 中7SI 988 0506 #4FA# 370 1350 高1DO 1046 0478 低5SO 392 1276 #DO# 1109 0451 #5SO# 415 1205 高2RE 1175 0426 低6LA 440 1136 #2RE# 1245 0402 #6LA# 466 1072 高3M 1318 0372 低7SI 494 1012 高4FA 1397 0358 中1DO 523 0956 #4FA# 1480 0338 #1DO# 554 0903 高5SO 1568 0319 中2RE 578 0842 #5S0# 1661 0292 #2RE# 622 0804 高6LA 1760 0284 中3M 659 0759 #6LA# 1865 0268 中4FA 698 0716 高7SI 1976 0253第四篇:微机原理课程设计——音乐播放器
第五篇:微机原理课程设计音乐播放器