




已阅读5页,还剩43页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
47讲义名称:UML嵌入式系统开发实例本讲义内容包括: 1. 录音程式(Recorder) - p.22. 单晶片嵌入式软体介面设计 - p.28- 以8051控制四位数七节LED灯为例本文引自 高焕堂所着的 “物件导向ANSI-C” 和 “物件导向Keil C51”两书UML嵌入式系统开发实例之一录音程式(Recorder)- 情 境:录音及播放(Record/Play)- 建 模:SysML/UML- 语 言:物件导向LW_OOPC- 资料库:Linter Embedded DBMS- 平 台:Win32/VC+基础录音概念和技术认识PCM规格 在你的电脑上,可以使用许多软体来进行录音。本章是假设你想自己写个录音程式,让你自己透过麦克风来录制你的声音,并且存入.wav型态的音档。由于.wav是标准的音档格式,你可使用许多种软体来播放之,包括Microsoft 的Windows Media Player等流行的播放软体。 在撰写录音程式方面,Windows提供了完整的API函数可供你去呼叫,就能用来录制.wav音档了。通常是以8、11、16、22KHz取样后再依据PCM(Pulse Code Modulation) 音轨来进行编码、数位化之后就成为.wav格式之音档了。由于音波本质上可以分解成为数个正旋的波型,其频率整数之倍数,所以PCM能依固定之周期而进行取样。例如,若采取 11.025 kHz, stereo, 8-bit 模式,并且使用双声道来录音的话,则厘清下述之数据关系,对于设计及撰写录音程式,会有很大帮助的。l 每次取样8bit = 1Bytel 每秒钟取样11025 (即11.025 * 1000)次l 录音声道数= 2l 可算出每秒钟将录制 (11025 * 1 * 2) Bytes的音讯资料l 若录制N秒,供需要(11025 * 2 * N) Bytes的记忆体空间来存放其中,这.wav格式之音档除了8Bit之取样模式之外,还可以选择16Bit取样模式。8Bit取样意味着每次取样8bit,所以音档的每笔资料长度是1Byte;若为16Bit音档的话,则每笔资料长度是2 Bytes。当取样频率一样时,每次取样较大可得到较佳的音质。但是所需要较大的储存空间。 .wav音档又分为单声道(channel)或双声道等,单声道录音时,.wav音档是由单一个资料所构成;使用双声道录音时,会同时接收两笔资料,一笔由左声道输出的,另一笔是由右声道输出,依序写入.wav音档里。设定录音格式 在你的VB.Net录音程式里,只需要将上述的参数指定(assign)给如下的format结构里,然后呼叫Win32 API,就可以了:Private format As WAVEFORMATEX . 11.025 kHz, stereo, 8-bit 且双声道 format.wFormatTag = Wave.WAVE_FORMAT_PCM format.nChannels = 2 format.nSamplesPerSec = 11025 format.wBitsPerSample = 8 format.nBlockAlign = format.nChannels * (format.wBitsPerSample / 8) format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign format.cbSize = 0 Windows依据format里的资讯而进行音讯之采样,其过程中会不断地把采集到的音讯资料存入缓冲区(buffer)里,而你的程式必须及时给予足够的缓冲区,或者即时从缓冲区取出资料。设定缓冲区格式 你的程式必须安排缓冲区,并决定其大小,其定义之格式如下:缓冲区格式之内容:Structure WAVEHDR lpData As IntPtr - 指向你所安排的录音缓冲区(例如Byte阵列) dwBufferLength As Integer - 缓冲区之长度值 dwBytesRecorded As Integer - 是给录音系统使用,说明已经录了几个Byte dwUser As IntPtr - 指向原来呼叫waveInxxx来录音之物件 dwFlags As Integer - 相关之Flag dwLoops As Integer - 回圈Counter lpNext As IntPtr - 指向下一个缓冲区定义(WAVEHDR) reserved As Integer - 保留做为其他用途End Structure 设定好缓冲区之后,你的程式就可以从缓冲区不断取出音讯资料。取得资料后,可以将之存入档案里。因之,你必须知道.wav档案的格式,才能准确地存好档案。 将音讯资料写入.wav音档 在.wav的音档里,起头44 Bytes必须记载着我们采取8Bit或16Bit,也必须记载我们选择几声道方式录音。这44bytes长的区域通称为.wav音档的档头(Header),继档头之后(即45 Byte起)到档尾才储存所录的音讯资料。如下表所示:(档头:固定占44个Bytes)Char(4)储存 RIFF 字串Int32储存FileSize 8整数值(表示从此到档尾之距离长度)Char(4)储存 WAVE 字串Char(4)储存 fmt 字串Int32储存16整数值(表示后续16Bytes记载音档之格式)音档格式区 Int16wFormatTag值(即音档规格, 0x0001表示PCM规格) Int16nChannels值(即声道数) Int32nSamplesPerSec值(即每秒取样几次- 频率) Int32nAvgBytesPerSec值(即每秒平均资料量) Int16nBlockAlign值(即 取样Bit数/8之整数值) Int16wBitsPerSample值(即每次取样之Bit数- 样本大小)Char(4)储存 data 字串Int32储存FileSize 44整数值(即实际音讯资料之长度) (档身:占 FileSize 44个Bytes)Char(FileSize 44)储存实际所录制之音讯资料使用Win32所提供之API 在录音方面,Win32 提供如下之常用API函数:1. waveOutGetNumDevs() - 侦测可用之音讯设备之个数2. waveOutGetDevCaps() - 侦测可用之音讯设备之能力3. waveInOpen() - 找到可用之录音设备,然后开启它 4. waveInPrepareHeader() - 给予缓冲区(Buffer)之格式5. waveInAddBuffer() - 实际添增一个缓冲区 6. waveInStart() - 开始录音 7. waveInUnprepareHeader() - 除去缓冲区(Buffer)之格式 8. waveInReset() - 立即停止录音9. waveInStop() - 待目前缓冲区满时,立即停止录音10. waveInClose() - 关闭录音设备 声音录制范例分析与设计绘制系统Use Case图 本范例里,因为操作需求简单,只是系统执行过程较复杂,所以跳过企业Use Case图,直接切入系统Use Case图。如下图所示:此图显示出使用者需求是简单的:只是想要录音10秒钟,然后存入.wav格式之档案。绘制类别图 此为典型之软硬体整合设计之系统,其包括三种不同类型的组件:l 硬体设备 - 例如麦克风、Hard Disk等。l 驱动软体(driver)或服务提供者(service provider)- 例如录音的MMSYSTEM(即winmm.lib)程式。 l 主控软体(或称为应用软体) - 例如声音录制VB.Net程式。 为了明确表达上述三者之间的密切关系,兹先绘制一个软硬整合设计之类别图如下:(系统类别图)接着,把焦点摆在软体(包括驱动程式和应用程式),并且将驱动程式视为应用程式与硬体设备之间的介面。就能绘制以软体为主的类别图如下: (新式类别图:软体是圣诞树,硬体组件是糖果) 传统上,我们常常把硬体视为较坚强主干,它支撑着许许多多的软体系统,软体就像树叶一般挂在树干或树枝上。而上图则采取比较新潮的观点,就是:把软体视为树干,而硬体就像树叶一般挂在软体上。由于两个观点都没有错,但是换个新观点总是有益无害的。绘制循序图 于此,藉由循序图来表达上述Use Case幕后的系统流程,如下图: (以软体为主的循序图) 把驱动程式视为介面,则硬体组件就像汽车的轮胎,驱动程式就像轮盘(就是车辆与轮胎之介面),应用程式就是车辆本身。这种新观点能带来极大的利益,就是:硬体组件很容易像轮胎一样迅速汰旧换新。 这种新观点几乎与传统软硬体观点是相反的,就如同数百年前,大多数人从地球看太阳,直觉地认为太阳绕地球而旋转。然而哥白尼则换个新角度,从太阳看地球,认为地球绕太阳而旋转。因为观点本身并无对错之分,所以两种观点都是对的。但是,当我们能同时兼具两种观点,将会为我们带来最大的利益。希望你也能像哥白尼一样的智慧。声音录制范例之实作- 使用LW_OOPC语言 Step-1: 先建立VC+专案,内容为:Step-2: 定义WavRec类别,担任录音的工作,录好之后,会存入c:SymSound.wav音档里。 /* wavrec.h */#ifndef WAVREC_H#define WAVREC_H#include lw_oopc.hCLASS(WavRec) /* char* m_buffer;int m_file_size;*/ void (*init)(void*);void (*prepare)(void*);void (*start)(void*);void (*close)(void*);#endif撰写WavRec.c程式码:/* WavRec.c */#include StdAfx.h #include stdio.h#include #include #include #include #include #include wavsave.h#include wavrec.hextern void* WavSaveNew();#define OFFSET_FORMATTAG20#define OFFSET_CHANNELS22#define OFFSET_SAMPLESPERSEC24#define OFFSET_AVGBYTESPERSEC28#define OFFSET_BLOCKALIGN32#define OFFSET_BITSPERSAMPLE34#define OFFSET_WAVEDATA44#define HEADER_SIZE OFFSET_WAVEDATAtypedef struct char R1; char I2; char F3; char F4; unsigned long WAVElen; struct char W1; char A2; char V3; char E4; char f5; char m6; char t7; char space; unsigned long fmtlen; struct unsigned short FormatTag; unsigned short Channels; unsigned long SamplesPerSec; unsigned long AvgBytesPerSec; unsigned short BlockAlign; unsigned short BitsPerSample; /* format specific for PCM */ fmt; char d8; char a9; char t10; char a11; unsigned long datalen; /* from here you insert your PCM data */ WAVE; RIFF;long total_len = 0;HWAVEIN m_hwIn;WAVEFORMATEX m_format;WAVEHDR m_wHdr; RIFF header;int hfile;int xfile;/-static void ProcessHeader(WAVEHDR * pvr)write(hfile, pvr-lpData, pvr-dwBytesRecorded); total_len += pvr-dwBytesRecorded;if(waveInAddBuffer(m_hwIn, pvr, sizeof(WAVEHDR) != 0) MessageBox(NULL, _T(waveInAddBuffer error!), _T(), MB_OK | MB_ICONINFORMATION);static void CALLBACK waveInProc(HWAVEIN hwi,UINT uMsg,DWORD dwInstance,DWORD dwParam1,DWORD dwParam2)WAVEHDR *pHdr=NULL;switch(uMsg)case WIM_CLOSE:break;case WIM_DATA:/VoiceRec *pvr=(VoiceRec*)dwInstance;ProcessHeader(WAVEHDR *)dwParam1);break;case WIM_OPEN:break;default:break;/-static void writeFileHeader() /header = new RIFF(); header.R1 = R; header.I2 = I; header.F3 = F; header.F4 = F; header.WAVElen = 36; /sizeof(header.WAVE); /* + datalen */ /既粜戈斗update header.WAVE.W1 = W; header.WAVE.A2 = A; header.WAVE.V3 = V; header.WAVE.E4 = E; header.WAVE.f5 = f; header.WAVE.m6 = m; header.WAVE.t7 = t; header.WAVE.space = ; header.WAVE.fmtlen = 16; /sizeof(header.WAVE.fmt); header.WAVE.fmt.FormatTag = WAVE_FORMAT_PCM; header.WAVE.d8 = d; header.WAVE.a9 = a; header.WAVE.t10 = t; header.WAVE.a11 = a; header.WAVE.datalen = 0; /* we dont know yet */既粜戈斗update header.WAVE.fmt.BitsPerSample = m_format.wBitsPerSample; header.WAVE.fmt.Channels = m_format.nChannels ; header.WAVE.fmt.SamplesPerSec = m_format.nSamplesPerSec; header.WAVE.fmt.AvgBytesPerSec =m_format.nAvgBytesPerSec; header.WAVE.fmt.BlockAlign =m_format.nBlockAlign ; /= hfile = open(c:SymSound.wav,O_CREAT | O_TRUNC | O_RDWR | O_BINARY, S_IWRITE); if(!hfile | hfile = -1) MessageBox(NULL,_T(can not open .wav!),_T(), MB_OK | MB_ICONINFORMATION); if(write(hfile, &header, sizeof(header) != sizeof(header) MessageBox(NULL,_T(write header Err!),_T(), MB_OK | MB_ICONINFORMATION);/-static void prepare(void* t) int kk; MMRESULT ret=0; m_format.wFormatTag = WAVE_FORMAT_PCM; m_format.nChannels = 2; /channels; 1=mono, 2=stereo m_format.nSamplesPerSec = 44100; / 11025; m_format.wBitsPerSample = 16; /bitsPerSample; 16 for high quality, 8 for telephone-grade m_format.nBlockAlign = m_format.nChannels * (m_format.wBitsPerSample / 8); m_format.cbSize = 0; /sizeof(WAVEFORMATEX); m_format.nAvgBytesPerSec = m_format.nSamplesPerSec * m_format.nChannels * (m_format.wBitsPerSample / 8); writeFileHeader();/- ret=waveInOpen(&m_hwIn,WAVE_MAPPER,&m_format,(DWORD_PTR)waveInProc,(DWORD_PTR)NULL,CALLBACK_FUNCTION); if(ret!=MMSYSERR_NOERROR)MessageBox(NULL,_T(waveInOpen err .),_T(), MB_OK | MB_ICONINFORMATION); return; /- PrepareBuffers UnPrepareBuffers Close Device - DWORD curr_time, base_time, draw_time; base_time = GetTickCount(); do curr_time = GetTickCount() - base_time; while (curr_time 2000 & error 3000) MessageBox(NULL,_T(Syntax error),_T(), MB_OK | MB_ICONINFORMATION); LINTER_CloseAPI(); /* free library resource */ exit(1); else printf(Return code = %ldn, ret_cod);static void load_from_file_to_db(void* t) WORD nConn; /* connection identifier */ WORD nCurs; /* cursor identifier */ char Query1 = drop table YooTable; char Query2 = create table YooTable (SONGID char(20), BLOBSEG1 Blob, BLOGSEG2 Blob, REMARK char(125); char Query3 = select SONGID, BLOBSEG1, REMARK from YooTable; char Query4 = insert into YooTable values (Queen,NULL, NULL, -); LONG lAnsLen; /* answer length */ char *cAnsBuf; /* answer buffer */ LONG lRet; /* return code */ LONG lApiErr = 0; LONG lLinErr = 0; LONG lSysErr = 0;long lError;short ty;void* vBuff;long BuffLength = 50;WavSave* cthis = (WavSave*)t; if (lRet = LINTER_Connect(SYSTEM, 0, MANAGER, 0, NULL, mAutocommit, &nConn) processing_error(lRet, nConn, 0, 0, ERROR Linter_Connect); if (lRet = LINTER_OpenCursor(nConn, &nCurs, NULL, 0, mAutocommit) processing_error(lRet, nConn, 0, 0, Error open cursor); if (lRet = LINTER_ExecuteDirect(nCurs, Query1, 0, NULL, NULL) processing_error(lRet, 0, nCurs, 0, Error ExecuteDirect); if (lRet = LINTER_ExecuteDirect(nCurs, Query2, 0, NULL, NULL) processing_error(lRet, 0, nCurs, 0, Error ExecuteDirect);/ MessageBox(NULL,_T(555),_T(), MB_OK | MB_ICONINFORMATION);/= FILE *pf = fopen(c:SymSound.wav, rb); if(!pf) return;fseek(pf, 0, SEEK_END); long file_size = ftell(pf);long block_size = 441000;long block, last; if(file_size = block_size) block = 0; last = file_size;else block = file_size / block_size; last = file_size - block * block_size; vBuff = new char block_size; fseek(pf, 0, SEEK_SET); /-for(int i=0; i 0 ) fread(vBuff, 1, last, pf); if (lRet = LINTER_ExecuteDirect(nCurs, Query4, 0, NULL, NULL) processing_error(lRet, 0, nCurs, 0, Error ExecuteDirect); if (lError= LINTER_AppendBlob(nCurs, 0 ,vBuff, last, NULL, NULL) processing_error(lError, 0, nCurs, 0, LINTER_PurgeBlob); LINTER_CloseAPI();fclose(pf); return;/-CTOR(WavSave) FUNCTION_SETTING(init, init) FUNCTION_SETTING(copy_from_file_to_db, load_from_file_to_db)END_CTOR Step-4: 定义WavPlay类别,负责从Linter DB读取歌曲内容,然后播放出来。/* WavPlay.h */#ifndef WAVPLAY_H#define WAVPLAY_H#include lw_oopc.hCLASS(WavPlay) char* m_buffer;int m_file_size; void (*init)(void*);void (*load_from_db)(void*);void (*play)(void*);#endif撰写WavPlay.c程式码:/* WavPlay.c */#include StdAfx.h #include stdio.h#include #include linapi.h#include wavplay.h#define OFFSET_FORMATTAG20#define OFFSET_CHANNELS22#define OFFSET_SAMPLESPERSEC24#define OFFSET_AVGBYTESPERSEC28#define OFFSET_BLOCKALIGN32#define OFFSET_BITSPERSAMPLE34#define OFFSET_WAVEDATA44#define HEADER_SIZE OFFSET_WAVEDATA/-static void CALLBACK VoicePlayProc(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)switch(uMsg)case WOM_OPEN:break;case WOM_DONE:WAVEHDR *whdr = (WAVEHDR*)dwParam1;if(whdr-dwUser)waveOutWrite(hwo, whdr, sizeof(WAVEHDR);elsewaveOutUnprepareHeader(hwo, whdr, sizeof(WAVEHDR);delete whdr;break;case WOM_CLOSE:break;/-static void init(void *t) WavPlay* cthis = (WavPlay*)t; static void processing_error(LONG ret_cod, WORD con_id, WORD cur_id, WORD stmt_id, char *message ) LONG lRet; LONG apierr = 0, error = 0, syserr = 0; if (ret_cod = LINAPI_ERROR) if (lRet = LINTER_Error(con_id, cur_id, stmt_id, &apierr, &error, &syserr, NULL, NULL) MessageBox(NULL,_T(diagnostic error),_T(), MB_OK | MB_ICONINFORMATION); else MessageBox(NULL,_T(API error),_T(), MB_OK | MB_ICONINFORMATION); if (apierr = eLinterError) & error 2000 & error 3000) MessageBox(NULL,_T(Syntax error),_T(), MB_OK | MB_ICONINFORMATION); LIN
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 标准工程承包合同模板2篇
- 应急救援协议(医疗救护)4篇
- 企业间财产租赁合同范本2篇
- 保全车间绩效考核合同6篇
- 新解读《GB-T 30873-2014耐火材料 抗热震性试验方法》
- 新解读《GB-T 31017-2014移动实验室 术语》
- 新解读《GB-T 31124-2014聚碳酸亚丙酯(PPC)》
- 美甲店套餐出售合同范本
- 售后保密合同范本
- 矿产企业合作合同范本
- 诊断学-常见症状的诊疗(临床疾病概要课件)
- 咨询类合同合同范例
- 九上道法【思维导图+重点句+考点问题+典型例题】
- 水土保持工程概(估)算编制规定
- 2024至2030年中国山西省轨道交通行业市场深度研究及投资战略规划报告
- 《第一课-学会管理情绪课件》高中心理健康教育北师大版高中二年级全一册1634
- 旅游新媒体营销
- 地质调查员三级(区域地质、矿产地质、矿山地质)复习参考试题库(含答案)
- 乳牙根管治疗的护理配合
- 经编车间安全操作规程模版
- 《小学三年级英语开学第一课》课件
评论
0/150
提交评论