找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4572|回复: 19
收起左侧

STC单片机音源制作进程(日记)

  [复制链接]
ID:283954 发表于 2021-9-25 22:57 | 显示全部楼层 |阅读模式
     昨天(24-09-2021)已完成了一款用STC8G制作的音源,整个制作过程繁杂,回头再看很多方法已经忘记了,为了能重复整个制作过程,我将分几日将原理和程序逐步梳理,写在论坛就不会再忘记了。

(1) 乐曲声音的来源:现在的音源都是用真乐器的录音来制作的,录音的工作就叫取样,原厂家会请一些器乐演奏好手来录音,做成样本,由于声音文件很大,一般都只采用几个音符的样本,用程序运算产生所有音符(一般有88个音符),做成音源售卖。

用编曲软件去演奏这些音源,就可以把所有音符录起来,这是一个MIDI文件,可以产生从C2到C9的音符:

SAMPLE-FULL.jpg


虽然一般乐器没有用到这么宽的音域,但为了统一方便处理,照录不误。乐器维持发声长短也不一,弹拨乐最短,吹管乐一个音也不会长多五六秒,就用8秒间隔来录:这是音频文件的截图:

FLUTE-1.jpg

从波形可以看出,这其实只是用几个样本运算所得的全部音符,这个音频文件还要经过处理才可以用来制作STC单片机音源。

。。待续

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:276663 发表于 2021-9-26 09:21 | 显示全部楼层
kdg,还没看懂你要干啥
回复

使用道具 举报

ID:283954 发表于 2021-9-26 17:08 | 显示全部楼层
用作音源的音频文件需要降噪处理,把背景杂声去除,用CE软件就能完成,接下来就是把全部85个音符剪辑,一个音符一个文件,顺序排列,这项工作可用人工完成,但工作量不小,尤其是文件的命名,如果错误就麻烦了,因此需要软件来帮忙。

经过降噪的音频,在静音的部分会有一连串零(00H)的字符,这本来可以作为辨识字符把每个音符剪切出来,但不能保证一定正确,因此还是用人工方法在每个音符开始的部分塞进容易辨识的字串,字串要如何塞进原来的音频文件呢?就必须用音频处理软件如CE或GOLDWAVE完成。

首先要制作一个音频文件,内容包含辨识字符,我采用了“CUTHERE!"这个字,用简单的BASIC语言就能完成:

CUT$="CUTHERE!"
OPEN "CUTHERE.WAV" FOR BINARY AS #1
PUT$ #1, CUT$
CLOSE #1

生成的“CUTHERE.WAV”文件并没有WAV文件需要的前辍字符,用CE或GOLDWAVE打开后,软件会询问,选择44.1K,16 BITS signed,Stereo的参数即可,然后保存,以后打开就不会再询问了。

如何使用呢?用GOLDWAVE打开CUTHERE.WAV文件,选择复制(COPY),


打开要处理的音频文件,把光标放在每个音符开始的前面,按“粘帖PASTE”,就把包含“CUTHERE!"字符的波形贴上了,从波形看就有一个突出的尖峰,用播放器播放就能听到POP声。把全部85个音符标记完毕工作就完成了。

NOTEMARK.jpg


标记位置的准确直接影响后来音源的结果,必须力求放在音频刚开始的位置,太靠前则延迟音符的出现,太靠后则音符演奏时会有POP声。

这工作完成后就可以写一个软件把每个音符剪切出来变成85个文件了。

。。待续



回复

使用道具 举报

ID:283954 发表于 2021-9-27 16:39 | 显示全部楼层
      昨天用GOLDWAVE把85个音符都做了标记,总共花费25分钟才做完,如果要把128种音色都做完的话,那就得花25分钟X128除60=53小时才能做完,真的是三天三夜不眠不吃不喝还得精神饱满才能做完,所以还得相出其他办法,否则是无法做出全部音色的。

      经过标记的音色文件,就可以用程序来做切割成85个音符,要写出一个能一次过切割文件的程序也不容易,因此就分几步走,第一步是读取文件后产生一个MAP的文件,注释每个音符在文件里的位置:

   mapfile.bas


   CLS
   VL=8
   FL$="FLUTE.WAV"

   OPEN FL$ FOR BINARY AS #1 'FIND THE WORD "DATA"
   PRINT "PROCESSING FILE ";FL$;" LEN=";LOF(1)

   FOR I&=0 TO 1000 'LOF(1)
   GET$ #1,4, RING$
   IF RING$="data" THEN
      PRINT "FOUND THE WORD data AT LOCATION:";LOC(1); " SO, IT IS A WAV FILE"
      EXIT FOR
   END IF
   K=LOC(1)
   K=K-3
   SEEK #1, K
   NEXT I&
   CLOSE #1

   VER$="CUTHERE!"

   OPEN FL$ FOR BINARY AS #1 'FIND VER$ MARK AS 000000000(38BYTES)
   OPEN "MAP.TXT" FOR OUTPUT AS #2
   PRINT "ORIGINAL FILE ";FL$;" LEN=";LOF(1)


   B&=LOF(1)/VL 'LOOP HOW MANY TIME

   N=9 'START FILE NAME AT NUMBER 9

   FOR I&=0 TO LOF(1)
   LOCATE 7, 1
   PRINT I&
   IF EOF(1) THEN
      EXIT FOR
   END IF

   GET$ #1,VL, RING$

   IF RING$=VER$ THEN
      N=N+1
      OL&=LOC(1)-OL&
      PRINT #2, N;LOC(1);OL&

      LOCATE 5, 1
      PRINT "FOUND VER$ AT";LOC(1);"SIZE=";OL&;" NUMBER=";N;" LOOP=";I&
      OL&=LOC(1)
      GET$ #1,64, USELESS$ 'MOVE FORWARD TO AVIOD DOUBLE
   END IF
   K&=LOC(1)
   K&=K&-7
   SEEK #1, K&
   NEXT I&
   CLOSE #1
   CLOSE #2
   END

运行后得到MAP.TXT的文件,内容如下:

10  2252344  2252344
11  3667072  1414728
12  5079052  1411980
13  6489384  1410332
14  7901104  1411720
15  9309872  1408768
16  10721256  1411384
17  12131796  1410540
18  13545088  1413292
19  14957832  1412744
20  16368244  1410412
21  17777268  1409024
22  19189964  1412696
23  20600396  1410432
24  22012532  1412136
25  23424380  1411848
26  24834712  1410332
27  26244712  1410000
28  27657152  1412440
29  29069004  1411852
30  30479592  1410588
31  31890980  1411388
32  33302956  1411976
33  34713624  1410668
34  36124548  1410924
35  37535808  1411260
36  38947912  1412104
37  40358964  1411052
38  41769040  1410076
39  43180428  1411388
40  44591816  1411388
41  46003204  1411388
42  47414384  1411180
43  48826824  1412440
44  50237620  1410796
45  51648080  1410460
46  53059468  1411388
47  54470184  1410716
48  55881908  1411724
49  57293884  1411976
50  58704808  1410924
51  60116068  1411260
52  61527120  1411052
53  62938508  1411388
54  64350020  1411512
55  65761152  1411132
56  67172668  1411516
57  68583208  1410540
58  69994260  1411052
59  71406492  1412232
60  72817672  1411180
61  74228548  1410876
62  75640064  1411516
63  77051244  1411180
64  78462836  1411592
65  79873684  1410848
66  81285404  1411720
67  82696664  1411260
68  84108228  1411564
69  85518688  1410460
70  86930412  1411724
71  88340744  1410332
72  89751872  1411128
73  91163772  1411900
74  92574904  1411132
75  93985904  1411000
76  95397804  1411900
77  96808728  1410924
78  98220244  1411516
79  99630784  1410540
80  101041324  1410540
81  102453224  1411900
82  103864612  1411388
83  105276204  1411592
84  106686920  1410716
85  108098644  1411724
86  109509568  1410924
87  110921468  1411900
88  112332468  1411000
89  113743728  1411260
90  115154856  1411128
91  116565832  1410976
92  117977092  1411260


文件中第一列是音符序列码,第二列是该音符在文件中开始的位置,第三列是每个标记之间的大小,大概是1.4M,这数字并不重要,主要是用来查看有没有漏标或多标,除了第一行的数字,其他的都应该接近1.4M这个数字,如有错误必须打开音色文件纠正才能继续。

。。待续



回复

使用道具 举报

ID:887734 发表于 2021-9-27 21:17 | 显示全部楼层
好东西,坐等更新。。。。。。
回复

使用道具 举报

ID:283954 发表于 2021-9-28 17:50 | 显示全部楼层
本帖最后由 dalaoshi 于 2021-9-29 01:22 编辑

    有了MAP.TXT 这个文件,就可以写一个软件把每个音符剪出来保存为一个音频文件,在这之前得先知道每个音符真正长度所占的字节是多少,这可以用GOLDWAVE将音色文件中的一个音符复制,保存为ONENOTE.WAV, 然后查看电脑目录,显示为734K,由于每个音符都是由CAKEWALK软件演奏的,长度一样,因此在软件中就填上1024次循环,每次读取734字节,共734K字节,保存为文件:

   CUTFILE.BAS

   DR$="C:\SOUND\"
   FL$="FLUTE.WAV"
   CLS

   OPEN DR$+FL$ FOR BINARY AS #1 'FIND data
   PRINT "ORIGINAL FILE ";DR$;FL$;" LEN=";LOF(1)

   FOR I&=0 TO 1000 'LOF(1)
   GET$ #1,4, RING$
   IF RING$="data" THEN
      PRINT "FOUND data AT";LOC(1);"SO IT IS A WAV FILE"
      EXIT FOR
   END IF
   K&=LOC(1)
   K&=K&-3
   SEEK #1, K&
   NEXT I&
   CLOSE #1

   OPEN DR$+FL$ FOR BINARY AS #1 'FIND DATA
   OPEN DR$+"MAP.TXT" FOR INPUT AS #2
   PRINT "ORIGINAL FILE ";DR$;FL$;" LEN="LOF(1)

   FOR I=1 TO 84
   IF EOF(2) THEN EXIT FOR
   INPUT #2, MAKE$
   SN$=LTRIM$(STR$(VAL(MAKE$))," ")  'FILE
   PRINT SN$;",";
   MAKE$=MID$(MAKE$,5,18)
   START&=VAL(MAKE$)  'START
   PRINT "LOCATION:";START&;
   MAKE$=MID$(MAKE$,10,10)
   LG=VAL(MAKE$)
   PRINT "BYTES:";LG
   OPEN DR$+SN$+".WAV" FOR BINARY AS #3
   CLOSE #3
   KILL DR$+SN$+".WAV"

   OPEN DR$+SN$+".WAV" FOR BINARY AS #3  'GET 800K
   SEEK #1, START&
   FOR V= 1 TO 1024
   GET$ #1, 734, HG$
   PUT$ #3, HG$
   NEXT V
   CLOSE #3
   NEXT I
   END

   剪切好的音符文件必须用GOLDWAVE打开一个试听,确保音符是完整的。

note29.jpg

。。待续

回复

使用道具 举报

ID:283954 发表于 2021-9-29 17:26 | 显示全部楼层
    接下来就是要把所有单音符的文件重新组合成一个文件, 并产生参数让单片机编程使用:

   JOINFILE.BAS

   CLS
   DR$="C:\SOUND\"

   OPEN DR$+"ALL.WAV" FOR BINARY AS #2
   CLOSE #2
   KILL DR$+"ALL.WAV"
   OPEN DR$+"ALL.WAV" FOR BINARY AS #2
   OPEN DR$+"LIST.TXT" FOR OUTPUT AS #3

   FOR F=10 TO 93
   FILE$=STR$(F)
   FILE$=DR$+MID$(FILE$, 2,2)+".WAV"
   PRINT FILE$
   GOSUB MAKEFILE
   NEXT F
   CLOSE #2

   OPEN DR$+"ALL.WAV" AS #2
   TOTAL$=STR$(LOF(2)/1024)+" KB"
   PRINT "TOTAL IN NEW FILE=";TOTAL$
   PRINT #3, "TOTAL IN NEW FILE=";TOTAL$
   PRINT "TOTAL SECTOR=";LOF(2)/512
   PRINT #3, "TOTAL SECTOR=";LOF(2)/512
   CLOSE #3
   CLOSE #2
   END


   MAKEFILE:
   OPEN FILE$ FOR BINARY AS #1
   IF LOF(1)=0 THEN
      CLOSE #1
      PRINT
      PRINT FILE$;" CONTAIN ZERO BYTES, PRESS ANY KEY TO CONTINUES: ";
      W$=INPUT$(1)
      PRINT
      GOTO MAKEFILEEXIT
   END IF
   PRINT "ORIGINAL FILE LEN=";LOF(1)
   Z=1000
   M=LOF(1)
   IF DISPLAY=0 THEN             'SHOW DETAIL AT FIRST FILE
      PRINT "VALID DATA M=";M
      H=M mod 512
      PRINT "EXTRA DATA H=";H
      K=512-H
      PRINT "NEED FEED DATA K=";K
      PRINT "TOTAL DATA WILL BE";M+K
      PRINT "EACH NOTE NEED:";(M+K)/512;" SECTORS "
      PRINT #3,"EACH NOTE NEED:";(M+K)/512;" SECTORS "
      PRINT
      PRINT "PRESS ANY KEY TO CONTINUE";
      W$=INPUT$(1) 'WAIT
      DISPLAY=1
    END IF
   P=LOF(1)/Z
   FOR I=0 TO P 'LOF(1)
   GET$ #1,Z,G$
   PUT$ #2, G$
   NEXT I
   FOR I=1 TO K
   PUT$ #2, CHR$(0)
   NEXT I
   CLOSE #1
   MAKEFILEEXIT:
   RETURN

      生成的 ALL.WAV 就是一个有结构的文件,每个音符所占用的扇区一样,将音符好码乘上扇区数就能直接到该扇区把音符的字节取出,用单片机的PWM或外接DAC就能播放出来。

ALL-NEW.jpg

参数:
EACH NOTE NEED: 1469  SECTORS
TOTAL IN NEW FILE= 60963.5 KB
TOTAL SECTOR= 121927


回复

使用道具 举报

ID:147710 发表于 2021-9-30 12:00 | 显示全部楼层
很多年前用电脑玩过MIDI,音色不错,文件又小,看到大佬的帖子,手痒痒,准备弄片SAM2695玩玩,看那封装,真有点犹豫,大佬的音源是放在SD卡里么
回复

使用道具 举报

ID:283954 发表于 2021-9-30 16:32 | 显示全部楼层
MIDI文件很小,只是记录音符和音符的时长,但要播放出好声音,要有好的音源,现在都用软音源,声音还不错,sam2695原本是打算给玩具用的,意外成功,但音色不佳,不能用来当演奏用,玩玩可以。这晶片太小,手工焊接很难成功,我做了10片只有7片有声音,打算验证线路正确后,让厂家小批量生产。

我把经过格式化的音源文件存入SD卡后,用单片机载入大容量RAM再播放出来。
回复

使用道具 举报

ID:887734 发表于 2021-10-1 10:45 | 显示全部楼层
2012年用stc11f02单片机做过midi 的播放程序,midi文件存储在EEROM 25P40里面,参考的是一本日文杂志上的文章,由于单片机资源有限只做了一个钢琴音色,2个通道,声音效果一般,不过midi音乐文件要简化到2个通道才能用。
附件的文件是效果音,以前的东西好多资料都没有了,看楼主都东西比我的要好太多了。

回复

使用道具 举报

ID:283954 发表于 2021-10-2 03:46 | 显示全部楼层
syjldz 发表于 2021-10-1 10:45
2012年用stc11f02单片机做过midi 的播放程序,midi文件存储在EEROM 25P40里面,参考的是一本日文杂志上的文 ...

市售的音源必须至少有16个声道,必须能同时发24个音以上,还要有128种乐器的声音。这不是一般的单片机能做到,而且必须能对几十种控制讯号做反应,对CPU的运算能力要求很高。所以你用STC单片机做的只能2声道,1种乐器。
市面通行的音源芯片只有三颗:SAM2695, VS1053B, CS9326,我都有做过,但声音都不满意,很多乐器的声音都不像,不能作为表演用,因此我必须从最底层做起,连音色文件都要自己制作才行。
回复

使用道具 举报

ID:887734 发表于 2021-10-2 06:29 | 显示全部楼层
附件里是2通道一种音色的声音效果,见笑了,stc11f02的性能确实有限。

01.rar

3.46 MB, 下载次数: 9, 下载积分: 黑币 -5

2通道示例音频

回复

使用道具 举报

ID:283954 发表于 2021-10-2 16:54 | 显示全部楼层
syjldz 发表于 2021-10-2 06:29
附件里是2通道一种音色的声音效果,见笑了,stc11f02的性能确实有限。

听起来还很不错,而且是两个声部,同时发两个音,那就是有multitasking的能力,估计再多几个声部MCU就来不及了,不过现在MCU速度快多了,可以再尝试,有四个声部就有实用价值了,因为一个和弦必须用四个音组成。

音源开发还有另一条路线图,就是采用网上易得的SOUNDFONT格式,文件后辍是.sf2,原理是长音符都采用重复播放部分的方式,所以文件很小,128种乐器就30M,而声音也不错了。你若能写个能解读.SF2的代码,就能造出完整的音源,而不必用我这个笨方法了。

这是用.SF2演奏的: hsymp3.zip (4.94 MB, 下载次数: 17)
回复

使用道具 举报

ID:887734 发表于 2021-10-2 22:31 | 显示全部楼层
用单片机玩解码midi音乐播放的人不多,要有音乐和单片机的多方位能力,楼主的东西很扎实,很好,学习了。
要是能年轻10岁我一定好好研究一下这个东西。我是60后,玩不动了,呵呵。。。

回复

使用道具 举报

ID:992668 发表于 2021-12-15 12:15 | 显示全部楼层
玩单片机也玩midi的人很少,方便加个
回复

使用道具 举报

ID:283954 发表于 2021-12-18 15:32 | 显示全部楼层
你好!我玩单片机是为了解决电子乐器无法用来组织交响乐队的难题,市面卖的电子琴功能很多,音质差,但容易销售,我称之为“市场导向型”,我要的电子琴是声音要好,演奏者能自然控制音量,弯音等,表达情感,我称为“艺术导向型”,这样的琴商家是不会生产的,因为卖不多,无法营运,所以只能自己做,这是我用市售的37键电子琴改装的琴,整个控制器拆掉,换成用STC15+STC12做的控制器:

key4.jpg

有了这个琴,就能让四个键盘手组成弦乐四重奏。

目前要解决的是音源,音源IC最便宜的是sam2695,¥15,做了7个,声音很差,玩玩可以,用来舞台演奏就对不起观众了,所以又得用STC8自己做了。

回复

使用道具 举报

ID:283954 发表于 2021-12-25 18:20 | 显示全部楼层
单片机音源已经DIY了30片,够用了,但音符转换时会出现POP声,为了解决这个问题,必须对音频的波形进行处理,这就必须作16BITS带符号的运算,网上找资料来学,始终搞不通,干脆主动出击,写个软件生成WAV文件,再用GOLDWAVE打开来看,这下就完全清楚了,制了个图放在网上,就不会忘记了。
LEARN-01.jpg


回复

使用道具 举报

ID:283954 发表于 2021-12-29 17:50 | 显示全部楼层
      制作单片机音源原本以为不必涉及负数运算,只需把VELOCITY的数字0-127输出到音量控制IC就可控制的音量大小,免去复杂的运算,但结果控制不那么顺滑,所以就想尝试把波形直接减幅,每组数据都要16位X8位的一次除数运算和一次乘数运算,每秒要进行44K次,不知道这单片机是否来得及,先用PB软件模拟一下运算过程,正数还容易理解,负数就头大了,原本以为,负数越大,幅度就越大,模拟的结果却完全相反,无所谓啦,用单片机只要加多几步也能实现,这是模拟程序和产生的波形图。


CLS

OPEN "LEARN2.WAV" FOR BINARY AS #1
CLOSE #1
KILL "LEARN2.WAV

OPEN "LEARN2.WAV" FOR BINARY AS #1
SS%=32767       '01111111 11111111 POSITIVE MAX
SS%=SS%/127     'EACH VELOCITY PART

FOR K%=0 TO 127
S%=SS%*K%
FOR I=1 TO 1
PUT$ #1, CHR$(S% MOD 256)+CHR$(S%\256)
NEXT I
NEXT K%

SS%=-32768      '11111111 11111111 NEGATIVE MAX
SS%=SS%+32767+1  
SS%=(SS%+32767)/127 'EACH VELOCITY PART

FOR K%=0 TO 127
J%=127-K%
S%=SS%*J%
FOR I=1 TO 1
PUT$ #1, CHR$(S% MOD 256)+CHR$(S%\256+128)
NEXT I
NEXT K%
CLOSE #1

PRINT "END"

LEARN-02.jpg

回复

使用道具 举报

ID:495990 发表于 2022-1-4 09:46 | 显示全部楼层
楼主很牛,这要有相当的音乐专业知识才能看得懂哦!
回复

使用道具 举报

ID:106060 发表于 2022-1-16 16:20 | 显示全部楼层
如果真的想做,51单片机可能真的无法满足你们的要求,有个DSP或者FPGA了解一下。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表