<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>张新豪 个人资料学习笔记与美学作品展示</title>
	<atom:link href="http://www.zhangxinhao.com/feed" rel="self" type="application/rss+xml" />
	<link>http://www.zhangxinhao.com</link>
	<description></description>
	<lastBuildDate>Mon, 21 Jul 2025 08:36:45 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>Apple CGI</generator>
	<item>
		<title>【入门到精通】AI作图最好用的工具 Comfy UI</title>
		<link>http://www.zhangxinhao.com/blog/5377</link>
		<pubDate>Fri, 24 Mar 2023 12:15:02 +0000</pubDate>
		<dc:creator><![CDATA[Honour Z]]></dc:creator>
				<category><![CDATA[TECH]]></category>

		<guid isPermaLink="false">http://www.zhangxinhao.com/?p=5377</guid>
		<description><![CDATA[通过节点图设计AI生成平面作品 目录 软件介绍 安装 &#8211;&#124; 1.下载软件 2.下载模型 3.启动软... <a href="http://www.zhangxinhao.com/blog/5377" class="excerpt-read-more">Read More</a>]]></description>
				<content:encoded><![CDATA[<p style="text-align: center;">通过节点图设计AI生成平面作品</p>
<p>目录</p>
<p>软件介绍</p>
<p>安装</p>
<p>&#8211;| 1.下载软件 2.下载模型 3.启动软件 4.更新升级</p>
<p>基本操作</p>
<p>&#8211;| 1.生成一张图 2.词法规则 3.节点操作 4.AI作图原理 5.保存工程</p>
<p>高级功能</p>
<p>&#8211;| 1.使用Lora 2.使用ControlNet 3.使用Upscale 4.SetArea 5.用不同模型同时绘制多张图</p>
<p>附录</p>
<p>&nbsp;</p>
<hr />
<h1 style="text-align: center;">软件介绍</h1>
<hr />
<p style="text-align: center;">节点图是现代3D软件 如Unity、Unreal、Blender中常见的美术设计工具</p>
<p style="text-align: center;">ComfyUI 通过节点图控制AI生成平面作品</p>
<p style="text-align: center;">比起 WebUI 它的可控性和自由度更高 更适合商业化的设计场景 更适合设计师 而WebUI比较适合开发者</p>
<p><img class="aligncenter size-full wp-image-5403" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/4-2.png" alt="" width="1416" height="794" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/4-2.png 1416w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/4-2-768x431.png 768w" sizes="(max-width: 1416px) 100vw, 1416px" /></p>
<p>&nbsp;</p>
<hr />
<h1 style="text-align: center;">安装</h1>
<hr />
<p>&nbsp;</p>
<h4 style="text-align: center;">1.下载软件</h4>
<p style="text-align: center;">来到软件的Github页 <a href="https://github.com/comfyanonymous/ComfyUI" target="_blank" rel="noopener">GitHub &#8211; comfyanonymous/ComfyUI</a></p>
<p style="text-align: center;">点击 “Direct link to download”</p>
<p style="text-align: center;">下载后解压</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-5400" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/1-3.png" alt="" width="890" height="309" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/1-3.png 890w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/1-3-768x267.png 768w" sizes="(max-width: 890px) 100vw, 890px" /></p>
<p>&nbsp;</p>
<h4 style="text-align: center;">2.下载模型</h4>
<p style="text-align: center;">来到模型网站 <a href="https://civitai.com/" target="_blank" rel="noopener">Civitai.com</a> 挑选中意的模型存档（模型左上角是CHECKPOINT）</p>
<p><img class="aligncenter size-full wp-image-5409" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/7.png" alt="" width="828" height="774" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/7.png 828w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/7-768x718.png 768w" sizes="(max-width: 828px) 100vw, 828px" /></p>
<p style="text-align: center;">点进去后下载模型本体(图中CP)</p>
<p style="text-align: center;">如果提示包含独立的VAE模型（如下图）还要下载它包含的VAE模型（点蓝色的VAE）</p>
<p><img class="aligncenter size-full wp-image-5411" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/81.png" alt="" width="1146" height="699" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/81.png 1146w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/81-768x468.png 768w" sizes="(max-width: 1146px) 100vw, 1146px" /></p>
<p style="text-align: center;">下载后放置到 软件解压的目录中.\ComfyUI_windows_portable\ComfyUI\models 里对应的文件夹里</p>
<p style="text-align: center;">（如 Checkpoint放在checkpoints文件夹里 vae放在vae文件夹里）</p>
<p><img class="aligncenter size-full wp-image-5418" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/B4.png" alt="" width="263" height="325" /></p>
<p>&nbsp;</p>
<h4 style="text-align: center;">3.启动软件</h4>
<p style="text-align: center;">软件解压的目录中:</p>
<p style="text-align: center;"><strong>run_cpu.bat</strong> 为启动CPU算图的版本（很慢）</p>
<p style="text-align: center;"><strong>run_nvidia_gpu.bat</strong> 为启动GPU算图的版本 只支持NVIDIA卡</p>
<p style="text-align: center;">（其他显卡根据Github上的提示手动配置）</p>
<p><img class="aligncenter size-full wp-image-5405" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/6.png" alt="" width="245" height="195" /></p>
<p style="text-align: center;">打开后可能会出现下图中防火墙拦截的情况</p>
<p style="text-align: center;">按照图示允许即可</p>
<p><img class="aligncenter size-full wp-image-5401" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/2-2.png" alt="" width="528" height="497" /> <img class="aligncenter size-full wp-image-5402" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/3-2.png" alt="" width="523" height="491" /></p>
<p style="text-align: center;">软件启动成功后会弹出命令行窗口 并自动打开浏览器</p>
<p style="text-align: center;">（如果没有自动打开浏览器 并且有报错信息 比如找不到xxx的话</p>
<p style="text-align: center;">修改一下解压后文件夹存放的路径即可 路径尽可能简单 最好全英文 不要有特殊字符 不要太深）</p>
<p><img class="aligncenter size-full wp-image-5404" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/5.png" alt="" width="977" height="252" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/5.png 977w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/5-768x198.png 768w" sizes="(max-width: 977px) 100vw, 977px" /></p>
<p style="text-align: center;">如果浏览器内容是空白的 需要更换Edge或Chrome浏览器访问 http://www.zhangxinhao.com:8188</p>
<p><img class="aligncenter size-full wp-image-5415" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/b1.png" alt="" width="1480" height="559" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/b1.png 1480w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/b1-768x290.png 768w" sizes="(max-width: 1480px) 100vw, 1480px" /></p>
<p>&nbsp;</p>
<h4 style="text-align: center;">4.更新升级</h4>
<p style="text-align: center;">解压后文件夹内的 update 内的 bat 用来更新软件及其依赖</p>
<p><img class="aligncenter size-full wp-image-5421" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/up.png" alt="" width="491" height="173" /></p>
<p>&nbsp;</p>
<pre></pre>
<hr />
<h1 style="text-align: center;">基本操作</h1>
<hr />
<p>&nbsp;</p>
<h4 style="text-align: center;">1.生成一张图</h4>
<p style="text-align: center;">在CheckpointLoaderSimple节点上选择刚才下载好的模型</p>
<p><img class="aligncenter size-full wp-image-5440" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/geb0.png" alt="" width="547" height="758" /></p>
<p style="text-align: center;">分别在连到 positive 和 negative 的 CLIPTextEncode 里填入 正向提示语 和 负向提示语</p>
<p><img class="aligncenter size-full wp-image-5437" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/gen.png" alt="" width="1499" height="665" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/gen.png 1499w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/gen-768x341.png 768w" sizes="(max-width: 1499px) 100vw, 1499px" /></p>
<p style="text-align: center;">点击右边的 Queue Prompt 就开始算图了 默认是512*512的尺寸</p>
<p><img class="aligncenter size-full wp-image-5441" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/gen1.png" alt="" width="1403" height="689" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/gen1.png 1403w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/gen1-768x377.png 768w" sizes="(max-width: 1403px) 100vw, 1403px" /></p>
<p>&nbsp;</p>
<h4 style="text-align: center;">2.词法规则</h4>
<h6 style="text-align: center;">2.1 正向与负向</h6>
<p style="text-align: center;">提示语(prompt)有两种 正向的(positive) 和 负向的(negative)</p>
<p style="text-align: center;">正向提示语描述希望出现在图像里的元素，负向提示语表明不希望出现在图里的东西</p>
<p>&nbsp;</p>
<h6 style="text-align: center;">2.2 内容类型</h6>
<p style="text-align: center;">提示语 可以是一句话 如 “Standing On Narrow City Streets Crossword”</p>
<p style="text-align: center;">也可以是以逗号分隔的词 “masterpiece, pretty girl, long hair”</p>
<p>&nbsp;</p>
<h6 style="text-align: center;">2.3 权重</h6>
<p style="text-align: center;">权重影响该特征在图中占的比例 或者说 突显的程度</p>
<p style="text-align: center;">越靠前的提示语权重越大</p>
<p style="text-align: center;">也可以通加括号调整权重</p>
<p style="text-align: center;">小括号表示将权重调至当前 <strong>1.1 </strong>倍 可以迭代 如 ((cute))</p>
<p style="text-align: center;">大括号为 <strong>1.05 </strong>倍，中括号为 <strong>0.9 </strong>倍</p>
<p style="text-align: center;">也可以直接指定倍率 如 (cute:1.2)</p>
<p>&nbsp;</p>
<h6 style="text-align: center;">2.4 指定步长</h6>
<p style="text-align: center;">[girl:10] 从10步开始画女孩</p>
<p style="text-align: center;">[girl::20] 到20步停止停止画女孩</p>
<p style="text-align: center;">[[girl::20]:10] 从10步到20步画女孩</p>
<p>&nbsp;</p>
<h6 style="text-align: center;">2.5 融合</h6>
<p style="text-align: center;"><strong>xx AND yy</strong> 同时具有特性xx和yy (大写AND)</p>
<p style="text-align: center;"><strong>xx:1.05 AND yy:0.9</strong> 同时具有特性xx和yy 比例为xx1.05 yy0.9</p>
<p style="text-align: center;"><strong>[xx|yy]</strong> 融合特性xx和yy</p>
<p style="text-align: center;"><strong>[xx:yy:0.6]</strong> 以 前60%后40%的比例 融合特性xx和yy</p>
<p style="text-align: center;"><strong>[xx:yy:10]</strong> 以 前10步xx后面步yy 融合xx和yy</p>
<p>&nbsp;</p>
<h6 style="text-align: center;">2.6 自定义提示词</h6>
<p style="text-align: center;">Civitai 的资源中自定义提示词的左上角是Textual Inversion</p>
<p><img class="aligncenter size-full wp-image-5464" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/1-4.png" alt="" width="491" height="405" /></p>
<p style="text-align: center;">下载下来 记住它的 Trigger words 触发词</p>
<p><img class="aligncenter size-full wp-image-5465" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/2-3.png" alt="" width="329" height="471" /></p>
<p style="text-align: center;">下载后放到软件目录.\ComfyUI_windows_portable\ComfyUI\models 中的 embeddings 文件夹里</p>
<p><img class="aligncenter size-full wp-image-5418" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/B4.png" alt="" width="263" height="325" /></p>
<p style="text-align: center;">使用的时候直接填入Trigger word 触发词 就行了</p>
<p><img class="aligncenter size-full wp-image-5466" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/3-3.png" alt="" width="872" height="458" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/3-3.png 872w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/3-3-768x403.png 768w" sizes="(max-width: 872px) 100vw, 872px" /></p>
<p>&nbsp;</p>
<h6 style="text-align: center;">2.7 学习其他人的提示词</h6>
<p style="text-align: center;">Civitai 里大部分模型资源页的下方 都有网友分享的效果图</p>
<p><img class="aligncenter size-full wp-image-5410" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/9.png" alt="" width="1025" height="824" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/9.png 1025w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/9-768x617.png 768w" sizes="(max-width: 1025px) 100vw, 1025px" /></p>
<p style="text-align: center;">点开效果图 可以看到这张图用了什么提示语</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-5408" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/a.png" alt="" width="984" height="848" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/a.png 984w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/a-768x662.png 768w" sizes="(max-width: 984px) 100vw, 984px" /></p>
<p style="text-align: center;">尺寸、采样方式与步长等参数也会影响作图结果</p>
<p>&nbsp;</p>
<h4 style="text-align: center;">3.节点操作</h4>
<p style="text-align: center;">在节点上拖动可以拖动节点</p>
<p style="text-align: center;">在空白处拖动则会移动视图</p>
<p style="text-align: center;">鼠标滚轴放大缩小视图</p>
<p style="text-align: center;">在空白处双击 搜索并新建节点</p>
<p><img class="aligncenter size-full wp-image-5475" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/x1.png" alt="" width="434" height="383" /></p>
<p style="text-align: center;">在空白处右键 为 菜单</p>
<p><img class="aligncenter size-full wp-image-5476" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/x2.png" alt="" width="424" height="259" /></p>
<p style="text-align: center;">在节点上右键调出节点的菜单</p>
<p>&nbsp;</p>
<p style="text-align: center;">每个节点都是 左边输入 右边输出</p>
<p><img class="aligncenter size-full wp-image-5467" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/9-1.png" alt="" width="421" height="403" /></p>
<p style="text-align: center;">鼠标从 一个节点的输出 拖拽出来 连接到另一个节点的输入</p>
<p style="text-align: center;">拖拽期间 可以连接的地方会亮起来 如图</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-5477" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/x3.png" alt="" width="738" height="558" /></p>
<p style="text-align: center;">按 F11 切换全屏</p>
<p>&nbsp;</p>
<h4 style="text-align: center;">4.AI作图原理</h4>
<p style="text-align: center;">整个算法由三部分组成 文本翻译器 算图器 和 图片翻译器</p>
<p style="text-align: center;">首先 文本翻译器(CLIPTextEncode) 把提示语翻译成 AI 听得懂的语言</p>
<p style="text-align: center;">然后 算图器(KSampler)根据翻译过来的提示语 以 AI 自己的语言算图</p>
<p style="text-align: center;">最后 图片翻译器(VAEDecoder) 把AI语言里的图像翻译成人类能看懂的图片</p>
<p><img class="aligncenter size-full wp-image-5472" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/6-1.png" alt="" width="1465" height="705" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/6-1.png 1465w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/6-1-768x370.png 768w" sizes="(max-width: 1465px) 100vw, 1465px" /></p>
<p style="text-align: center;">三个部分 每一个部分都需要一个模型</p>
<p style="text-align: center;">所以 一个 Checkpoint 包含三个模型</p>
<p style="text-align: center;">MODEL 是算图器的模型 CLIP 是文本翻译器的模型 VAE 是图片翻译器的模型</p>
<p><img class="aligncenter size-full wp-image-5473" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/7-1.png" alt="" width="416" height="202" /></p>
<p style="text-align: center;">文本翻译器节点需要输入一个 CLIP 模型</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-5474" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/8.png" alt="" width="289" height="166" /></p>
<p style="text-align: center;">算图器 KSampler 节点需要输入一个算图器的模型(model) 以及两个文本提示语翻译后的结果(positive)(negative)</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-5467" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/9-1.png" alt="" width="421" height="403" /></p>
<p style="text-align: center;">它还需要输入一个画布(latent _image) 这里用 EmptyLatentImage 节点生成的随机噪音就好</p>
<p style="text-align: center;">(画布可以包含先验信息)</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-5469" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/b.png" alt="" width="273" height="188" /></p>
<p style="text-align: center;">图片翻译器 节点 需要输入算图的结果(samples) 与一个图片翻译器的模型(vae)<br />
<img class="aligncenter size-full wp-image-5468" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/a-1.png" alt="" width="292" height="487" /></p>
<p>&nbsp;</p>
<h4 style="text-align: center;">5.保存工程</h4>
<p style="text-align: center;">在右边的菜单中 可以 保存 和 加载工程 也可以通过 Load Default 加载初始工程</p>
<p><img class="aligncenter size-full wp-image-5416" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/b2.png" alt="" width="167" height="242" /></p>
<p style="text-align: center;"> 除此以外 ComfyUI 还会把工程存在导出的 PNG 文件的的元数据里</p>
<p style="text-align: center;">把PNG拖入节点视图 就可以直接加载生成这张图的原工程</p>
<p><img class="aligncenter size-full wp-image-5417" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/b3.png" alt="" width="1132" height="592" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/b3.png 1132w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/b3-768x402.png 768w" sizes="(max-width: 1132px) 100vw, 1132px" /></p>
<p>&nbsp;</p>
<hr />
<h1 style="text-align: center;">高级功能</h1>
<hr />
<p>&nbsp;</p>
<h4 style="text-align: center;">1.使用Lora模型</h4>
<p style="text-align: center;">Lora模型 是一种在已有模型上进行微调的模型</p>
<p><img class="aligncenter size-full wp-image-5412" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/82.png" alt="" width="1038" height="754" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/82.png 1038w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/82-768x558.png 768w" sizes="(max-width: 1038px) 100vw, 1038px" /></p>
<p style="text-align: center;">Civitai 上选好模型 下载下来 同样要记住触发词 Trigger word<img class="aligncenter size-full wp-image-5413" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/83.png" alt="" width="1029" height="692" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/83.png 1029w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/83-768x516.png 768w" sizes="(max-width: 1029px) 100vw, 1029px" /></p>
<p style="text-align: center;">下载后放到软件目录.\ComfyUI_windows_portable\ComfyUI\models 中的 loras 目录里</p>
<p><img class="aligncenter size-full wp-image-5418" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/B4.png" alt="" width="263" height="325" /></p>
<p style="text-align: center;">右键菜单 点 Add Node 然后 loaders 里新增一个 LoraLoader 节点</p>
<p><img class="aligncenter size-full wp-image-5483" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/1-5.png" alt="" width="366" height="214" /></p>
<p style="text-align: center;">选择刚下载的 Lora 模型后 把这个节点接在 CheckpointLoaderSimple 和其他节点之间 然后填入该Lora模型的触发词 就可以了</p>
<p><img class="aligncenter size-full wp-image-5485" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/3-4.png" alt="" width="1570" height="617" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/3-4.png 1570w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/3-4-768x302.png 768w" sizes="(max-width: 1570px) 100vw, 1570px" /></p>
<p style="text-align: center;">你可以直接在 LoraLoader 节点上调模型的权重 而不用通过&lt;xx:0.9&gt; 的提示词调整</p>
<p>&nbsp;</p>
<h4 style="text-align: center;">2.使用ControlNet模型</h4>
<p style="text-align: center;">ControlNet 让我们可以用 图片的方式 与 AI 沟通</p>
<p style="text-align: center;">来到 Civitai 下载对应的模型 搜索controlnet</p>
<p><img class="aligncenter size-full wp-image-5423" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/c1.png" alt="" width="937" height="846" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/c1.png 937w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/c1-768x693.png 768w" sizes="(max-width: 937px) 100vw, 937px" /></p>
<h6 style="text-align: center;">2.1 姿势</h6>
<p style="text-align: center;">模型页翻到 “版本” 的位置 选择 OpenPose 这个版本 下载</p>
<p><img class="aligncenter size-full wp-image-5425" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/c3.png" alt="" width="1242" height="648" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/c3.png 1242w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/c3-768x401.png 768w" sizes="(max-width: 1242px) 100vw, 1242px" /></p>
<p style="text-align: center;">下载后放到软件目录.\ComfyUI_windows_portable\ComfyUI\models 中的 controlnet目录里</p>
<p><img class="aligncenter size-full wp-image-5418" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/B4.png" alt="" width="263" height="325" /></p>
<p style="text-align: center;">右键菜单 conditioning 里新建 ControlNetApply 节点</p>
<p><img class="aligncenter size-full wp-image-5487" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/4-3.png" alt="" width="346" height="162" /></p>
<p style="text-align: center;">把它接在文本节点和 KSampler 节点之间</p>
<p><img class="aligncenter size-full wp-image-5493" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/42.png" alt="" width="1097" height="310" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/42.png 1097w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/42-768x217.png 768w" sizes="(max-width: 1097px) 100vw, 1097px" /></p>
<p style="text-align: center;">然而这个节点还需要其他两个输入 分别是 ControlNet模型 和 提示图</p>
<p style="text-align: center;">右键菜单 loaders 里 新建 ControlNetLoader节点</p>
<p><img class="aligncenter size-full wp-image-5488" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/5-1.png" alt="" width="348" height="212" /></p>
<p style="text-align: center;">配置 openpose 模型</p>
<p><img class="aligncenter size-full wp-image-5489" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/6-2.png" alt="" width="808" height="379" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/6-2.png 808w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/6-2-768x360.png 768w" sizes="(max-width: 808px) 100vw, 808px" /></p>
<p style="text-align: center;">右键菜单 image 里 新建 LoadImage 节点</p>
<p><img class="aligncenter size-full wp-image-5490" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/7-2.png" alt="" width="312" height="155" /></p>
<p style="text-align: center;">配置一张 提示图 就可以开始算图了 效果如下</p>
<p><img class="aligncenter size-full wp-image-5491" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/8-1.png" alt="" width="1281" height="815" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/8-1.png 1281w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/8-1-768x489.png 768w" sizes="(max-width: 1281px) 100vw, 1281px" /></p>
<p style="text-align: center;">你可以通过这个在线工具生成姿势图 <a href="https://zhuyu1997.github.io/open-pose-editor/?lng=zh" target="_blank" rel="noopener">open pose editor</a> 空白处左键旋转 右键拖动 滚轴缩放 点生成图后点图下载 点骨骼扭动</p>
<p>&nbsp;</p>
<h6 style="text-align: center;">2.2 线稿</h6>
<p style="text-align: center;">线稿也是一样的 先下载模型 放到对应的目录里</p>
<p><img class="aligncenter size-full wp-image-5424" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/c2.png" alt="" width="1249" height="646" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/c2.png 1249w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/c2-768x397.png 768w" sizes="(max-width: 1249px) 100vw, 1249px" /></p>
<p style="text-align: center;">节点上配置一下</p>
<p><img class="aligncenter size-full wp-image-5492" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/9-2.png" alt="" width="651" height="145" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/9-2.png 651w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/9-2-650x145.png 650w" sizes="(max-width: 651px) 100vw, 651px" /></p>
<p style="text-align: center;">就可以根据线稿或者涂鸦算图了</p>
<p><img class="aligncenter size-full wp-image-5486" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/a-2.png" alt="" width="1269" height="810" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/a-2.png 1269w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/a-2-768x490.png 768w" sizes="(max-width: 1269px) 100vw, 1269px" /></p>
<p>&nbsp;</p>
<h4 style="text-align: center;">3.使用Upscale模型</h4>
<p style="text-align: center;">算图的尺寸会对内容元素数量有影响 所以有时需要小尺寸上算完再放大</p>
<p style="text-align: center;">先下载用来放大的模型 <a href="https://github.com/JingyunLiang/SwinIR/releases/tag/v0.0" target="_blank" rel="noopener">JingyunLiang/SwinIR · GitHub</a> 放到 upscale_models 里</p>
<p><img class="aligncenter size-full wp-image-5418" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/B4.png" alt="" width="263" height="325" /></p>
<p style="text-align: center;">右键 image 里 upscaling 里新建 ImageUpscaleWithModel 节点</p>
<p><img class="aligncenter size-full wp-image-5504" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/72.png" alt="" width="464" height="176" /></p>
<p style="text-align: center;">把它连在 VAEDecode 和 SaveImage 节点之间</p>
<p><img class="aligncenter size-full wp-image-5505" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/AA.png" alt="" width="780" height="175" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/AA.png 780w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/AA-768x172.png 768w" sizes="(max-width: 780px) 100vw, 780px" /></p>
<p style="text-align: center;">右键菜单 loaders 里面新建 UpscaleModelLoader 节点</p>
<p><img class="aligncenter size-full wp-image-5501" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/5-2.png" alt="" width="354" height="227" /></p>
<p style="text-align: center;">配置下载好的模型</p>
<p><img class="aligncenter size-full wp-image-5502" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/6-3.png" alt="" width="726" height="142" /></p>
<p style="text-align: center;">如图连接</p>
<p><img class="aligncenter size-full wp-image-5503" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/9-3.png" alt="" width="1136" height="447" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/9-3.png 1136w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/9-3-768x302.png 768w" sizes="(max-width: 1136px) 100vw, 1136px" /></p>
<p style="text-align: center;">可以看到已经从 512 放大到了 2048</p>
<p><img class="aligncenter size-full wp-image-5500" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/a-3.png" alt="" width="414" height="650" /></p>
<p style="text-align: center;">也可以放大自定义图片 如下图配置</p>
<p><img class="aligncenter size-full wp-image-5506" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/AAA.png" alt="" width="1185" height="560" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/AAA.png 1185w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/AAA-768x363.png 768w" sizes="(max-width: 1185px) 100vw, 1185px" /></p>
<p>&nbsp;</p>
<h4 style="text-align: center;">4.SetArea</h4>
<p style="text-align: center;">我们可以设定不同特征在图像中作用于不同的区域</p>
<p style="text-align: center;">右键菜单 conditioning 里新建 ConditioningSetArea 节点</p>
<p><img class="aligncenter size-full wp-image-5494" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/1-6.png" alt="" width="347" height="189" /></p>
<p style="text-align: center;">把它连在文本节点和 KSampler 节点之间</p>
<p style="text-align: center;">设定作用区域 这里xy是距离左边和顶部的距离</p>
<p><img class="aligncenter size-full wp-image-5498" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/12-1.png" alt="" width="1033" height="313" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/12-1.png 1033w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/12-1-768x233.png 768w" sizes="(max-width: 1033px) 100vw, 1033px" /></p>
<p style="text-align: center;">克隆 文本节点 和 ConditioningSetArea 节点 我们让左边和右边的描述不一样</p>
<p><img class="aligncenter size-full wp-image-5495" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/2-5.png" alt="" width="432" height="259" /></p>
<p style="text-align: center;">右键菜单 conditioning 里新建一个 ConditioningCombine 节点</p>
<p><img class="aligncenter size-full wp-image-5496" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/3-5.png" alt="" width="342" height="164" /></p>
<p style="text-align: center;"> 如图连接 填上不同的词 效果如下</p>
<p><img class="aligncenter size-full wp-image-5497" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/4-4.png" alt="" width="1445" height="651" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/4-4.png 1445w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/4-4-768x346.png 768w" sizes="(max-width: 1445px) 100vw, 1445px" /></p>
<p>&nbsp;</p>
<h4 style="text-align: center;">5.用不同模型同时绘制多张图</h4>
<p style="text-align: center;">可以用同一组提示语应用于不同模型同时算图 如图</p>
<p><img class="aligncenter size-full wp-image-5507" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/bb.png" alt="" width="1596" height="794" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/bb.png 1596w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/bb-768x382.png 768w" sizes="(max-width: 1596px) 100vw, 1596px" /></p>
<p>&nbsp;</p>
<hr />
<h1 style="text-align: center;">附录</h1>
<hr />
<p>&nbsp;</p>
<p style="text-align: center;">CFG Scale 与 Step 对结果的影响</p>
<h6 style="text-align: center;">SDE</h6>
<p><img class="aligncenter size-full wp-image-5445" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/sde.jpg" alt="" width="1280" height="921" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/sde.jpg 1280w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/sde-768x553.jpg 768w" sizes="(max-width: 1280px) 100vw, 1280px" /></p>
<p>&nbsp;</p>
<h6 style="text-align: center;">Euler A</h6>
<p><img class="aligncenter size-full wp-image-5446" src="http://www.zhangxinhao.com/wp-content/uploads/2023/03/eulera.jpg" alt="" width="1210" height="1280" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/03/eulera.jpg 1210w, http://www.zhangxinhao.com/wp-content/uploads/2023/03/eulera-768x812.jpg 768w" sizes="(max-width: 1210px) 100vw, 1210px" /></p>
<p>&nbsp;</p>
<p style="text-align: center;">以上</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			</item>
		<item>
		<title>【制作技术】混音中的“音乐感”与“硬件感”</title>
		<link>http://www.zhangxinhao.com/blog/5266</link>
		<pubDate>Sat, 04 Feb 2023 16:00:08 +0000</pubDate>
		<dc:creator><![CDATA[Honour Z]]></dc:creator>
				<category><![CDATA[TECH]]></category>

		<guid isPermaLink="false">http://www.zhangxinhao.com/?p=5266</guid>
		<description><![CDATA[最近在反思以往的混音中发现了一个问题 &#160; 就是 音响没有很好的承载音乐感，或者说音响没有情感，尤其是... <a href="http://www.zhangxinhao.com/blog/5266" class="excerpt-read-more">Read More</a>]]></description>
				<content:encoded><![CDATA[<p>最近在反思以往的混音中发现了一个问题</p>
<p>&nbsp;</p>
<p style="text-align: center;">就是 音响没有很好的承载音乐感，或者说音响没有情感，尤其是在手机这类小设备的扬声器上很明显</p>
<p style="text-align: center;">为改善这个情况，我对“音乐感”做了一些研究，在这分享一点看法</p>
<p>&nbsp;</p>
<h2 style="text-align: center;">1.“音乐感”与“硬件感”的关系</h2>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-5326" src="http://www.zhangxinhao.com/wp-content/uploads/2023/02/eq.png" alt="" width="1870" height="610" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/02/eq.png 1870w, http://www.zhangxinhao.com/wp-content/uploads/2023/02/eq-768x251.png 768w" sizes="(max-width: 1870px) 100vw, 1870px" /></p>
<p style="text-align: center;">音乐感来自 在<strong>正确频率位置</strong>的<strong>乐音</strong></p>
<p style="text-align: center;">一般来说，通过音量(EQ)减少噪音对乐音的掩蔽就可以强化音乐感</p>
<p style="text-align: center;">但是，有时候，你需要的频段里根本就没有乐音</p>
<p>&nbsp;</p>
<p style="text-align: center;">这种情况，可以通过硬件的电气特性制造出某些频率位置的自然泛音</p>
<p style="text-align: center;"><em>(PS：并不是所有硬件都会带来音乐感，有一些话放会让人声变亮，但不产生音乐感。)</em></p>
<p>&nbsp;</p>
<h2 style="text-align: center;">2.硬件如何塑造“音乐感”</h2>
<p>&nbsp;</p>
<p style="text-align: center;">我通过多次实验发现，用来<strong>承载音乐感的频段</strong>的<strong>动态</strong>需要听上去像是一个<strong>共振的音尾</strong></p>
<p style="text-align: center;">所以说需要的不仅是谐波，还需要有一个正确动态</p>
<p style="text-align: center;">而硬件里刚好就有一些元件可以塑造这种谐波与调制，这里以二极管为例</p>
<p>&nbsp;</p>
<p><img class="size-full wp-image-5271 aligncenter" src="http://www.zhangxinhao.com/wp-content/uploads/2023/02/1k.png" alt="" width="1656" height="1132" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/02/1k.png 1656w, http://www.zhangxinhao.com/wp-content/uploads/2023/02/1k-768x525.png 768w" sizes="(max-width: 1656px) 100vw, 1656px" /></p>
<p>&nbsp;</p>
<p style="text-align: center;">上图是某调音台中负责染色「温暖感」的电路</p>
<p style="text-align: center;">图的下方 左边是输入信号，右边是输出信号（声音在电路里以电压形式存在）</p>
<p>&nbsp;</p>
<p><img class="aligncenter size-full wp-image-5273" src="http://www.zhangxinhao.com/wp-content/uploads/2023/02/100k.png" alt="" width="1662" height="1140" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/02/100k.png 1662w, http://www.zhangxinhao.com/wp-content/uploads/2023/02/100k-768x527.png 768w" sizes="(max-width: 1662px) 100vw, 1662px" /></p>
<p>&nbsp;</p>
<p style="text-align: center;">这个电路中制造硬件感的地方是左半部分的二极管（右半部分是放大）</p>
<p style="text-align: center;">如果增加其串联的电阻减少二极管流出的电流时，输出信号的形状就会接近输入信号（上图）</p>
<p>&nbsp;</p>
<p><img class="aligncenter size-full wp-image-5289" src="http://www.zhangxinhao.com/wp-content/uploads/2023/02/diodecurve.jpg" alt="" width="707" height="478" /></p>
<p>&nbsp;</p>
<p style="text-align: center;">二极管不是输入信号就立刻导通的，而是需要达到阈值才能导通</p>
<p style="text-align: center;">而且导通后它的电压和电流不是线性的关系</p>
<p style="text-align: center;">这就导致流出的电流是非线性的，所以对输出信号的影响也是非线性的（如下图）</p>
<p>&nbsp;</p>
<p><img class="aligncenter size-full wp-image-5285" src="http://www.zhangxinhao.com/wp-content/uploads/2023/02/diode2.png" alt="" width="868" height="434" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/02/diode2.png 868w, http://www.zhangxinhao.com/wp-content/uploads/2023/02/diode2-768x384.png 768w, http://www.zhangxinhao.com/wp-content/uploads/2023/02/diode2-650x325.png 650w" sizes="(max-width: 868px) 100vw, 868px" /></p>
<p style="text-align: center;">这种特殊的波形影响有以下两个特征：</p>
<p style="text-align: center;">1.产生的新频率与原始信号的频率强相关（泛音点）</p>
<p style="text-align: center;">2.在新泛音点的动态上有一些调制效果</p>
<p>&nbsp;</p>
<h6 style="text-align: center;">听一下</h6>
<p style="text-align: center;"><em>原始信号（缺乏音乐感，有点不在调上的感觉）</em></p>

<audio class="wp-audio-shortcode" id="audio-5266-1" preload="none" style="width: 100%;" controls="controls"><source type="audio/wav" src="http://www.zhangxinhao.com/wp-content/uploads/2023/02/analogdry.wav?_=1" /><a href="http://www.zhangxinhao.com/wp-content/uploads/2023/02/analogdry.wav">http://www.zhangxinhao.com/wp-content/uploads/2023/02/analogdry.wav</a></audio>
<p style="text-align: center;"><em>&#8211;</em></p>
<p style="text-align: center;"><em>算法模拟的硬件感（出现了音乐感）</em></p>
<audio class="wp-audio-shortcode" id="audio-5266-2" preload="none" style="width: 100%;" controls="controls"><source type="audio/wav" src="http://www.zhangxinhao.com/wp-content/uploads/2023/02/analoganalog.wav?_=2" /><a href="http://www.zhangxinhao.com/wp-content/uploads/2023/02/analoganalog.wav">http://www.zhangxinhao.com/wp-content/uploads/2023/02/analoganalog.wav</a></audio>
<p style="text-align: center;"><em>&#8211;</em></p>
<p style="text-align: center;"><em>NEVE调音台的硬件感（带有独特味道的音乐感）</em></p>
<audio class="wp-audio-shortcode" id="audio-5266-3" preload="none" style="width: 100%;" controls="controls"><source type="audio/wav" src="http://www.zhangxinhao.com/wp-content/uploads/2023/02/analogn.wav?_=3" /><a href="http://www.zhangxinhao.com/wp-content/uploads/2023/02/analogn.wav">http://www.zhangxinhao.com/wp-content/uploads/2023/02/analogn.wav</a></audio>
<p>&nbsp;</p>
<h2 style="text-align: center;">3.软件模拟需要注意的地方</h2>
<p><img class="aligncenter size-full wp-image-5334" src="http://www.zhangxinhao.com/wp-content/uploads/2023/02/nnnn.png" alt="" width="1000" height="543" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/02/nnnn.png 1000w, http://www.zhangxinhao.com/wp-content/uploads/2023/02/nnnn-768x417.png 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></p>
<p style="text-align: center;">能够模拟硬件非线性的味道的插件有很多，比如Waves的NLS，需要注意，DRIVE控制的是谐波的多少</p>
<p><img class="aligncenter size-full wp-image-5301" src="http://www.zhangxinhao.com/wp-content/uploads/2023/02/waves.png" alt="" width="1294" height="274" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/02/waves.png 1294w, http://www.zhangxinhao.com/wp-content/uploads/2023/02/waves-768x163.png 768w" sizes="(max-width: 1294px) 100vw, 1294px" /></p>
<h6 style="text-align: center;">所以 Drive控制的重点不是增益 而是 硬件感&amp;音乐感 的多少</h6>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h2 style="text-align: center;">4.其他方法制造“音乐感”</h2>
<p style="text-align: center;">前面已经提到过，用来<strong>承载音乐感的频段</strong>的<strong>动态</strong>需要听上去像是一个<strong>共振的音尾</strong></p>
<p style="text-align: center;">所以可以通过一些效果器制造这种类似动态，进而制造音乐感</p>
<p>&nbsp;</p>
<h6 style="text-align: center;">1.用LFO制造出一个具有共振感拍频感的音响（比如LFOTool）</h6>
<p><img class="aligncenter size-full wp-image-5340" src="http://www.zhangxinhao.com/wp-content/uploads/2023/02/lfotools.png" alt="" width="1398" height="650" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/02/lfotools.png 1398w, http://www.zhangxinhao.com/wp-content/uploads/2023/02/lfotools-768x357.png 768w" sizes="(max-width: 1398px) 100vw, 1398px" /></p>
<p>&nbsp;</p>
<h6 style="text-align: center;">2.用upward压缩来放大信号里本来就具备的但很小声的音尾（比如OTT）</h6>
<p><img class="aligncenter size-full wp-image-5341" src="http://www.zhangxinhao.com/wp-content/uploads/2023/02/ott.png" alt="" width="768" height="1094" /></p>
<p>&nbsp;</p>
<h6 style="text-align: center;">3.用同度/八度奏等配器方式制造频率交叠产生类似拍频感共振感的音响</h6>
<p><img class="aligncenter size-full wp-image-5342" src="http://www.zhangxinhao.com/wp-content/uploads/2023/02/pp.png" alt="" width="688" height="516" srcset="http://www.zhangxinhao.com/wp-content/uploads/2023/02/pp.png 688w, http://www.zhangxinhao.com/wp-content/uploads/2023/02/pp-400x300.png 400w" sizes="(max-width: 688px) 100vw, 688px" /></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p style="text-align: center;">以上☺️</p>
]]></content:encoded>
	<enclosure url="http://www.zhangxinhao.com/wp-content/uploads/2023/02/analogdry.wav" length="1768652" type="audio/wav" />
<enclosure url="http://www.zhangxinhao.com/wp-content/uploads/2023/02/analoganalog.wav" length="1768652" type="audio/wav" />
<enclosure url="http://www.zhangxinhao.com/wp-content/uploads/2023/02/analogn.wav" length="1768652" type="audio/wav" />
		</item>
		<item>
		<title>【逆向安全】反汇编音频插件与Cracking实录</title>
		<link>http://www.zhangxinhao.com/blog/5178</link>
		<pubDate>Sat, 22 Oct 2022 23:19:09 +0000</pubDate>
		<dc:creator><![CDATA[Honour Z]]></dc:creator>
				<category><![CDATA[TECH]]></category>

		<guid isPermaLink="false">http://www.zhangxinhao.com/?p=5178</guid>
		<description><![CDATA[为保护插件不被Cracking，了解其过程是很必要的。 一直以来，关于逆向音频插件的资料在国内外都很少，刚好本... <a href="http://www.zhangxinhao.com/blog/5178" class="excerpt-read-more">Read More</a>]]></description>
				<content:encoded><![CDATA[<p style="text-align: center;"><em>为保护插件不被Cracking</em><em>，了解其过程是很必要的。</em></p>
<p style="text-align: center;"><em>一直以来，关于逆向<strong>音频插件</strong>的资料在国内外都很少，刚好本人最近接触到相关的东西，所以撰写此文分享插件Cracking技术</em></p>
<p style="text-align: center;"><em>其实Cracking音频插件和Cracking软件思路大致是相同的，只不过音频插件是一个模块，本文的案例就是软件Cracking中常见的搜索字符串法</em></p>
<p>&nbsp;</p>
<h2 style="text-align: center;">本文旨在为提升插件开发者水平而分享插件Cracking技术</h2>
<h2 style="text-align: center;">正式使用，还请使用正版</h2>
<p>&nbsp;</p>
<h4 style="text-align: center;">0.准备工具</h4>
<p style="text-align: center;">下载调试工具 <a href="https://x64dbg.com/" target="_blank" rel="noopener">x64dbg</a>(开源软件)</p>
<p style="text-align: center;">设置取消全部的自动断点，点选项-&gt;选项</p>
<p><img class="aligncenter size-full wp-image-5170" src="http://www.zhangxinhao.com/wp-content/uploads/2022/10/p11.png" alt="" width="1446" height="858" /></p>
<p style="text-align: center;">去掉事件下所有的勾</p>
<p><img class="aligncenter size-full wp-image-5167" src="http://www.zhangxinhao.com/wp-content/uploads/2022/10/p2.png" alt="" width="425" height="576" /></p>
<p style="text-align: center;">将 异常 -&gt; Unknow exceptions -&gt; 设定为 “不暂停”</p>
<p><img class="aligncenter size-full wp-image-5168" src="http://www.zhangxinhao.com/wp-content/uploads/2022/10/p3.png" alt="" width="425" height="576" /></p>
<p>&nbsp;</p>
<h4 style="text-align: center;">0.准备被Cracking插件</h4>
<p style="text-align: center;"><a href="https://github.com/DASTUDIO/AudioPluginCrackingTutorial/releases/tag/audioplugin" target="_blank" rel="noopener">这里</a> 我写了一个简单的注册码验证的VST插件</p>
<p style="text-align: center;">下载后放到 C:\Program Files\Common Files\VST3 文件夹里</p>
<p style="text-align: center;">打开宿主加载（这里是测试用的Reaper）</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-5145" src="http://www.zhangxinhao.com/wp-content/uploads/2022/10/1-1.png" alt="" width="1316" height="790" /></p>
<p>&nbsp;</p>
<h4 style="text-align: center;">1.明确目标</h4>
<p style="text-align: center;">音频插件，本质是挂载在一个应用程序(宿主DAW)上的模块，而Cracking要做的事，则是通过调试工具找到并反汇编这个模块，进而分析修改并重新转存这个模块</p>
<p>&nbsp;</p>
<h4 style="text-align: center;">2.信息收集 &#8211; 了解软件行为</h4>
<p style="text-align: center;">为了方便我写了个注册机，你可以用它算出的注册码查看注册成功提示的信息</p>
<p style="text-align: center;">====================================== [注册机] ==================================</p>


<iframe src="http://www.zhangxinhao.com/vsttutorial" width="100%" height="500" scrolling="yes" class="iframe-class" frameborder="0"></iframe>

<p style="text-align: center;">====================================== [注册机] ==================================</p>
<p>&nbsp;</p>
<p style="text-align: center;">这是注册码正确的提示</p>
<p><img class="aligncenter size-full wp-image-5147" src="http://www.zhangxinhao.com/wp-content/uploads/2022/10/3.png" alt="" width="1313" height="790" /></p>
<p style="text-align: center;">这是注册码不正确的情况</p>
<p><img class="aligncenter size-full wp-image-5148" src="http://www.zhangxinhao.com/wp-content/uploads/2022/10/4.png" alt="" width="1309" height="787" srcset="http://www.zhangxinhao.com/wp-content/uploads/2022/10/4.png 1309w, http://www.zhangxinhao.com/wp-content/uploads/2022/10/4-300x180.png 300w, http://www.zhangxinhao.com/wp-content/uploads/2022/10/4-768x462.png 768w, http://www.zhangxinhao.com/wp-content/uploads/2022/10/4-1024x616.png 1024w" sizes="(max-width: 1309px) 100vw, 1309px" /></p>
<p style="text-align: center;">记住正确会弹出 &#8220;You have successfully registered VSTCrackTutorials001&#8221; 的提示，后面会用到</p>
<h4 style="text-align: center;">3.实践分析 &amp; 整理思路</h4>
<p style="text-align: center;">打开x64dbg，点 文件 -&gt; 附加</p>
<p><img class="aligncenter size-full wp-image-5149" src="http://www.zhangxinhao.com/wp-content/uploads/2022/10/5.png" alt="" width="1446" height="858" /></p>
<p style="text-align: center;">在进程中找到宿主DAW(测试用的Reaper)的进程,双击 或 右下角 “附加”</p>
<p><img class="aligncenter size-full wp-image-5201" src="http://www.zhangxinhao.com/wp-content/uploads/2022/10/6.png" alt="" width="1190" height="654" /></p>
<p style="text-align: center;">点击 “符号” 标签页</p>
<p><img class="aligncenter size-full wp-image-5151" src="http://www.zhangxinhao.com/wp-content/uploads/2022/10/7.png" alt="" width="1446" height="858" /></p>
<p style="text-align: center;">找到加载的 &#8220;vstcracktutorial001.vst3&#8221; 模块 （是一个状态为 Loaded 的 用户模块），双击</p>
<p><img class="aligncenter size-full wp-image-5152" src="http://www.zhangxinhao.com/wp-content/uploads/2022/10/8.png" alt="" width="1446" height="858" /></p>
<p style="text-align: center;">双击后会跳到反汇编窗口(CPU标签页)</p>
<p style="text-align: center;">现在可以通过搜索 <strong>注册成功提示的字符串 </strong>来定位 <strong>处理注册逻辑的代码</strong> 在内存中所在的区域，修改那个区域的数据，就可以影响程序的行为</p>
<p style="text-align: center;"><em>（程序需要加载到内存中才能由CPU执行，程序加载到内存后会由一个<strong>相对进程的虚拟地址</strong>来定位）</em></p>
<p style="text-align: center;">标签页里点右键，点 搜索 -&gt; 当前模块 -&gt; 字符串</p>
<p><img class="aligncenter size-full wp-image-5153" src="http://www.zhangxinhao.com/wp-content/uploads/2022/10/9.png" alt="" width="1446" height="858" /></p>
<p style="text-align: center;">等待底部搜索进度条拉满后，在进度条上方的搜索框里搜索 &#8220;You have successfully registered VSTCrackTutorials001&#8243;（前面提到的 注册成功 弹出的信息） 里的内容</p>
<p style="text-align: center;">这里我只搜了一个 successfully</p>
<p style="text-align: center;">第二个是正确提示的内容，双击跳转到该位置的反汇编窗口</p>
<p><img class="aligncenter size-full wp-image-5155" src="http://www.zhangxinhao.com/wp-content/uploads/2022/10/a.png" alt="" width="1446" height="858" /></p>
<p style="text-align: center;">简单分析后可以看到有一个跳转跳过了成功（红线部分），这个应该就是关键跳</p>
<p><img class="aligncenter size-full wp-image-5156" src="http://www.zhangxinhao.com/wp-content/uploads/2022/10/b.png" alt="" width="1446" height="858" /></p>
<p>&nbsp;</p>
<h4 style="text-align: center;">4.实行Cracking &amp; 反馈验证调节</h4>
<p style="text-align: center;">在该跳转的行上 点右键 二进制 -&gt; 用NOP填充 （编程上相当于把这句在内存里注释掉）</p>
<p><img class="aligncenter size-full wp-image-5157" src="http://www.zhangxinhao.com/wp-content/uploads/2022/10/c.png" alt="" width="1446" height="858" /></p>
<p style="text-align: center;">然后输入错的注册码再点Register按钮，看看程序的反应</p>
<p><img class="aligncenter size-full wp-image-5158" src="http://www.zhangxinhao.com/wp-content/uploads/2022/10/d-1.png" alt="" width="1661" height="850" /></p>
<p style="text-align: center;">结果弹出了注册成功的框，说明Cracking成功了</p>
<p><img class="aligncenter size-full wp-image-5159" src="http://www.zhangxinhao.com/wp-content/uploads/2022/10/e.png" alt="" width="1618" height="861" /></p>
<p>&nbsp;</p>
<h4 style="text-align: center;">5.维持访问</h4>
<p style="text-align: center;">接下来需要把Cracking后的插件保存下来</p>
<p style="text-align: center;">在反汇编窗口(CPU标签页)点击 右键 -&gt; 补丁</p>
<p><img class="aligncenter size-full wp-image-5160" src="http://www.zhangxinhao.com/wp-content/uploads/2022/10/f.png" alt="" width="1446" height="858" /></p>
<p style="text-align: center;">点右下角的修补文件，然后找个不需要管理员权限的位置存上就可以，会保存一个格式与原模块相同的文件 (这里是 .vst3)</p>
<p style="text-align: center;">（C:\Program Files\Common Files\VST3需要管理员权限）</p>
<p style="text-align: center;"><em>（这里是把内存中修改的地址转换成了.vst3文件的文件偏移地址，然后把修改后的数据写进去，存为新的.vst3文件）</em></p>
<p><img class="aligncenter size-full wp-image-5154" src="http://www.zhangxinhao.com/wp-content/uploads/2022/10/10-1.png" alt="" width="1446" height="858" /></p>
<p style="text-align: center;">然后用刚存的 .vst3文件 替换掉 C:\Program Files\Common Files\VST3 里的原始.vst3文件，就完成Cracking了。</p>
<p>&nbsp;</p>
<p style="text-align: center;"><img src="https://s.w.org/images/core/emoji/2.3/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
]]></content:encoded>
			</item>
		<item>
		<title>音频开发 Tip（番外篇）自定义图形界面（附源码）</title>
		<link>http://www.zhangxinhao.com/blog/3729</link>
		<pubDate>Tue, 09 Jun 2020 16:00:09 +0000</pubDate>
		<dc:creator><![CDATA[Honour Z]]></dc:creator>
				<category><![CDATA[音频开发]]></category>

		<guid isPermaLink="false">http://www.zhangxinhao.com/?p=3729</guid>
		<description><![CDATA[插件的界面会在心理上影响人们对插件音质的评价，这篇讲讲怎么自定义插件的界面。 主要用到这些类： ImageCo... <a href="http://www.zhangxinhao.com/blog/3729" class="excerpt-read-more">Read More</a>]]></description>
				<content:encoded><![CDATA[<p></br><br />
插件的界面会在心理上影响人们对插件音质的评价，这篇讲讲怎么自定义插件的界面。  </p>
<p></br><br />
主要用到这些类：<strong> ImageComponent ImageCache BinaryData LookAndFeel Graphics</strong><br />
</br><br />
</br></p>
<p>先找两张图，一张背景，一张旋钮。</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/05/background.png" alt="" width="837" height="526" class="alignnone size-full wp-image-3740" /></p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/05/Knob.png" alt="" width="837" height="526" class="alignnone size-full wp-image-3741" /></p>
<p>把它们拖入JUCE的资源管理器里，Juce会自动把它创建为 Binary 的对象。</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/05/Screen-Shot-2020-06-18-at-2.53.06-AM.png" alt="" width="1804" height="1304" class="alignnone size-full wp-image-3743" /></p>
<p></br></p>
<h5>背景图像</h5>
<p></br></p>
<p>声明要用到的 ImageComponent</p>
<div class="codecolorer-container cpp solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">ProcessorEditor.<span style="color: #007788;">h</span><br />
...<br />
<span style="color: #007788;">ImageComponent</span> myImageComponent<span style="color: #008080;">;</span><br />
...</div></td></tr></tbody></table></div>
<p>绘制出来</p>
<div class="codecolorer-container cpp solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">ProcessorEditor.<span style="color: #007788;">cpp</span><br />
...<br />
<span style="color: #007788;">myImageComponent</span>.<span style="color: #007788;">setImage</span><span style="color: #008000;">&#40;</span>ImageCache<span style="color: #008080;">::</span><span style="color: #007788;">getFromMemory</span><span style="color: #008000;">&#40;</span>BinaryData<span style="color: #008080;">::</span><span style="color: #007788;">background_png</span>, BinaryData<span style="color: #008080;">::</span><span style="color: #007788;">background_pngSize</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <br />
myImageComponent.<span style="color: #007788;">setImagePlacement</span><span style="color: #008000;">&#40;</span>RectanglePlacement<span style="color: #008000;">&#40;</span>RectanglePlacement<span style="color: #008080;">::</span><span style="color: #007788;">stretchToFit</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; addAndMakeVisible<span style="color: #008000;">&#40;</span>myImageComponent<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; myImageComponent.<span style="color: #007788;">setBounds</span><span style="color: #008000;">&#40;</span>getLocalBounds<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; setSize <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">837</span>, <span style="color: #0000dd;">526</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
...<br />
<span style="color: #666666;">// resize 时调整大小</span><br />
<span style="color: #0000ff;">void</span> MyImageAudioProcessorEditor<span style="color: #008080;">::</span><span style="color: #007788;">resized</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; myImageComponent.<span style="color: #007788;">setBounds</span><span style="color: #008000;">&#40;</span>getLocalBounds<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><br />
...</div></td></tr></tbody></table></div>
<p></br></p>
<h5>旋钮</h5>
<p></br></p>
<p>先写一个 LookAndFeel 类 继承自LookAndFeel_V3 后面这个V1-4随意<br />
</br><br />
重写它的画旋钮的方法 把我们的图片画上去</p>
<div class="codecolorer-container cpp solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">ProcessorEditor.<span style="color: #007788;">h</span><br />
...<br />
<span style="color: #0000ff;">class</span> MyLookAndFeel <span style="color: #008080;">:</span> <span style="color: #0000ff;">public</span> LookAndFeel_V3<br />
<span style="color: #008000;">&#123;</span><br />
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">void</span> drawRotarySlider <span style="color: #008000;">&#40;</span>Graphics <span style="color: #000040;">&amp;</span>g, <span style="color: #0000ff;">int</span> x, <span style="color: #0000ff;">int</span> y, <span style="color: #0000ff;">int</span> width, <span style="color: #0000ff;">int</span> height, <span style="color: #0000ff;">float</span> sliderPosProportional, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">float</span> rotaryStartAngle, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">float</span> rotaryEndAngle, Slider <span style="color: #000040;">&amp;</span>slider<span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">auto</span> img1 <span style="color: #000080;">=</span>ImageCache<span style="color: #008080;">::</span><span style="color: #007788;">getFromMemory</span><span style="color: #008000;">&#40;</span>BinaryData<span style="color: #008080;">::</span><span style="color: #007788;">Knob_png</span>, BinaryData<span style="color: #008080;">::</span><span style="color: #007788;">Knob_pngSize</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; g.<span style="color: #007788;">drawImageTransformed</span><span style="color: #008000;">&#40;</span>img1, AffineTransform<span style="color: #008080;">::</span><span style="color: #007788;">rotation</span> <span style="color: #008000;">&#40;</span>rotaryEndAngle<span style="color: #000040;">*</span>slider.<span style="color: #007788;">getValue</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, img1.<span style="color: #007788;">getWidth</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #000040;">/</span><span style="color: #0000dd;">2</span>, img1.<span style="color: #007788;">getHeight</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #000040;">/</span><span style="color: #0000dd;">2</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span><br />
...</div></td></tr></tbody></table></div>
<p>声明旋钮以及 LookAndFeel 对象</p>
<div class="codecolorer-container cpp solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">ProcessorEditor.<span style="color: #007788;">h</span><br />
...<br />
&nbsp; &nbsp; <span style="color: #007788;">Slider</span> mySlider<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; MyLookAndFeel<span style="color: #000040;">*</span> myLookAndFeel<span style="color: #008080;">;</span><br />
...</div></td></tr></tbody></table></div>
<p>连接旋钮与LookAndFeel对象，并绘制旋钮</p>
<div class="codecolorer-container cpp solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">ProcessorEditor.<span style="color: #007788;">cpp</span><br />
...<br />
<br />
&nbsp; &nbsp; <span style="color: #007788;">mySlider</span>.<span style="color: #007788;">setBounds</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">837</span>, <span style="color: #0000dd;">526</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; mySlider.<span style="color: #007788;">setSliderStyle</span><span style="color: #008000;">&#40;</span>Slider<span style="color: #008080;">::</span><span style="color: #007788;">SliderStyle</span><span style="color: #008080;">::</span><span style="color: #007788;">RotaryVerticalDrag</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; mySlider.<span style="color: #007788;">setTextBoxStyle</span><span style="color: #008000;">&#40;</span>Slider<span style="color: #008080;">::</span><span style="color: #007788;">NoTextBox</span>, <span style="color: #0000ff;">false</span>, <span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; mySlider.<span style="color: #007788;">setRange</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">1</span>,<span style="color:#800080;">0.01</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; myLookAndFeel <span style="color: #000080;">=</span> <span style="color: #0000dd;">new</span> MyLookAndFeel<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; mySlider.<span style="color: #007788;">setLookAndFeel</span><span style="color: #008000;">&#40;</span>myLookAndFeel<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; addAndMakeVisible<span style="color: #008000;">&#40;</span>mySlider<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
...</div></td></tr></tbody></table></div>
<p>这样就 OK 了</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/05/Screen-Shot-2020-06-18-at-11.57.19-PM.png" alt="" width="1686" height="1308" class="alignnone size-full wp-image-3742" /></p>
<h5><a href="https://github.com/DASTUDIO/Juce_Audio_Tutorial/tree/master/MyImage" rel="noopener" target="_blank">点击这里查看源码</a></5></p>
]]></content:encoded>
			</item>
		<item>
		<title>音频开发 Tip（番外篇）将 JUCE 嵌入 Unity 3D</title>
		<link>http://www.zhangxinhao.com/blog/3703</link>
		<pubDate>Mon, 08 Jun 2020 16:00:45 +0000</pubDate>
		<dc:creator><![CDATA[Honour Z]]></dc:creator>
				<category><![CDATA[音频开发]]></category>

		<guid isPermaLink="false">http://www.zhangxinhao.com/?p=3703</guid>
		<description><![CDATA[在 Unity 中用自己写的音频效果给了我们在 Sound Design 上的更大的自由度，现在我们看看如何实... <a href="http://www.zhangxinhao.com/blog/3703" class="excerpt-read-more">Read More</a>]]></description>
				<content:encoded><![CDATA[<p></br></br><br />
在 Unity 中用自己写的音频效果给了我们在 Sound Design 上的更大的自由度，现在我们看看如何实现它。</p>
<p>&nbsp;</p>
<p>JUCE 在 5.4 之后，增加了对 Unity 的支持，可以将工程作为 Unity 插件导出。</p>
<blockquote><p>这其中有几个需要注意的点，</p>
<p>1.参数需要使用 <strong>AudioParameter</strong> （详见<a href="http://www.zhangxinhao.com/blog/3188" target="_blank" rel="noopener">《音频开发进阶（一）》</a>）, Unity 中 Inspector 中才能看的参数，而参数只有在 Unity 的 Inspector 里能看到才能与 C# 脚本交互。</p>
<p>2.如果你看过英文的资料，那些资料可和实际的情况有些不同。现在已经不用修改 hasEditor 回调的返回值，无论改不改用的都是 Unity 的 Slider。</p></blockquote>
<p>&nbsp;</p>
<p>我们之前在<a href="http://www.zhangxinhao.com/blog/3188" target="_blank" rel="noopener">《音频开发进阶（一）》</a>中，已经有一个现成的使用 AudioParameter 的工程，在里面下载好源码，直接拿来用。</p>
<p>&nbsp;</p>
<p>打开以后，点工程文件</p>
<p><img class="alignnone size-full wp-image-3709" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/1.jpg" alt="" width="954" height="400" /></p>
<p>&nbsp;</p>
<p>然后设置工程为Unity插件，并转到IDE打开</p>
<p><img class="alignnone size-full wp-image-3710" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/2.jpg" alt="" width="1808" height="1308" /></p>
<p>&nbsp;</p>
<p>IDE里导出，(如果是 Xcode 的话 导出完会在 Products 文件夹里，Visual Studio 的导出位置详见<a href="http://www.zhangxinhao.com/blog/3031" target="_blank" rel="noopener">《音频开发技术（二）》</a>)</p>
<p><img class="alignnone size-full wp-image-3711" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/3.jpg" alt="" width="754" height="860" /></p>
<p><img class="alignnone size-full wp-image-3715" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-18-at-12.46.28-AM.png" alt="" width="672" height="520" /></p>
<p>&nbsp;</p>
<p>打开unity，Assets里面新建一个 Plugins 文件夹</p>
<p><img class="alignnone size-full wp-image-3716" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-18-at-12.49.00-AM.png" alt="" width="680" height="538" /></p>
<p>&nbsp;</p>
<p>然后把导出的插件放到这个文件夹里</p>
<p><img class="alignnone size-full wp-image-3712" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/5.jpg" alt="" width="1688" height="946" /></p>
<p>&nbsp;</p>
<p>然后新建一个 Audio Mixer</p>
<p><img class="alignnone size-full wp-image-3719" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-18-at-12.49.34-AM-1.png" alt="" width="1236" height="384" /></p>
<p>双击</p>
<p><img class="alignnone size-full wp-image-3718" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-18-at-12.49.45-AM.png" alt="" width="690" height="300" /></p>
<p>双击音轨</p>
<p><img class="alignnone size-full wp-image-3713" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/6.jpg" alt="" width="852" height="516" /></p>
<p>就可以添加效果了，点 Add Effect 添加我们的插件</p>
<p><img class="alignnone size-full wp-image-3714" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/7.jpg" alt="" width="562" height="1042" /></p>
<p>可以看到显示了 Gate Threshold 参数</p>
<p><img class="alignnone size-full wp-image-3720" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-18-at-12.50.26-AM.png" alt="" width="556" height="576" /></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>在参数上右键，选择 暴露参数给脚本</p>
<p><img class="alignnone size-full wp-image-3721" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/11-1.jpg" alt="" width="1466" height="458" /></p>
<p>这里可修改脚本里的参数名</p>
<p><img class="alignnone size-full wp-image-3722" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/222-1.jpg" alt="" width="2030" height="576" /></p>
<p>&nbsp;</p>
<p>然后就可以在脚本中通过  <strong>你的audioMixer.SetFloat(&#8220;暴露给脚本的参数名&#8221;，要设定的值)  </strong>交互了</p>
<p>&nbsp;</p>
]]></content:encoded>
			</item>
		<item>
		<title>音频开发结语（完结） 前往金银岛！</title>
		<link>http://www.zhangxinhao.com/blog/3197</link>
		<pubDate>Sun, 07 Jun 2020 16:00:59 +0000</pubDate>
		<dc:creator><![CDATA[Honour Z]]></dc:creator>
				<category><![CDATA[音频开发]]></category>

		<guid isPermaLink="false">http://www.zhangxinhao.com/?p=3197</guid>
		<description><![CDATA[&#160; &#160; &#160; 在音频开发的路上，你已经到达十级，现在是时候走出新手村，开始第一次转... <a href="http://www.zhangxinhao.com/blog/3197" class="excerpt-read-more">Read More</a>]]></description>
				<content:encoded><![CDATA[<p>&nbsp;</p>
<div class="gdlr-shortcode-wrapper"><div class="gdlr-player-item-wrapper gdlr-item" ><div class="gdlr-player-item"><div class="gdlr-top-player"><div class="gdlr-top-player-inner"><div class="gdlr-top-player-thumbnail"><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/pkbbb-150x150.jpg" alt="" width="96" height="96" /></div><div class="gdlr-top-player-content"><div class="gdlr-top-player-title">枫叶回忆</div><div class="gdlr-top-player-download"><a class="top-player-download gdlr-download" target="_blank" style="display: none;" ><img src="http://www.zhangxinhao.com/wp-content/themes/musicclub-v1-06/images/icon-download.png" alt="icon-download" /></a><a class="top-player-apple" target="_blank" style="display: none;" ><img src="http://www.zhangxinhao.com/wp-content/themes/musicclub-v1-06/images/icon-apple.png" alt="icon-download" /></a><a class="top-player-amazon" target="_blank" style="display: none;" ><img src="http://www.zhangxinhao.com/wp-content/themes/musicclub-v1-06/images/icon-amazon.png" alt="icon-download" /></a></div></div><div class="clear"></div></div><audio class="gdlr-audio-player" preload="auto" style="width: 100%; height: 50px;"><source type="audio/mpeg" src="http://music.163.com/song/media/outer/url?id=33856223.mp3"></audio></div><ol class="gdlr-player-list"><li class="active" data-title="枫叶回忆" data-download="" data-apple="" data-amazon="" data-mp3="http://music.163.com/song/media/outer/url?id=33856223.mp3" >1. 枫叶回忆</li></ol><div class="clear"></div></div></div></div>
<p>&nbsp;</p>
<p><img class="alignnone size-full wp-image-3200 aligncenter" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/u34639818181190956439fm26gp0.jpg" alt="" width="320" height="320" /></p>
<p>&nbsp;</p>
<p>在音频开发的路上，你已经到达十级，现在是时候走出新手村，开始第一次转职了。</p>
<p>接下来有<strong>三条路线</strong>：<strong>信号处理、音频应用、KONTAKT音源</strong>。</p>
<p>你可以任选一条你喜欢的。</p>
<p>&nbsp;</p>
<h5>一、信号处理</h5>
<p>信号处理关注音频效果的底层算法。<br />
如果你是信号处理专业的学生、教育从业者、科学家、算法设计师、SDK开发者(音频类库)，或是想成为一个高手，这是最适合你的选择。</p>
<p><em>[小一段讲解滤波器的公式]</em><br />
<img class="alignnone size-full wp-image-3219" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-12-at-5.01.14-AM.png" alt="" width="1118" height="576" /></p>
<p>我推荐这本书，它讲述了必备的数学基础与大部分音频效果的原理，并且用JUCE做了演示：<a href="https://pan.baidu.com/s/1Xyklvgf1FDUBdhbNX_Bf3w" target="_blank" rel="noopener">音频效果的理论、实现与应用</a> 提取码: 4uqk | <a href="https://github.com/DASTUDIO/Audio-Effects" target="_blank" rel="noopener">这里是书中内容的源码实现</a></p>
<p>&nbsp;</p>
<h5>二、音频应用</h5>
<p>音频应用关注制作成品效果器/软件。它更多使用成熟稳定的类库与接口，而较少关注算法。<br />
如果你是效果器开发者、音频软件开发者这种追求稳定的，或者是希望短期内快速出一个演示Demo、毕业项目之类的，这是最合适的选择。</p>
<p><em>[JUCE实现的EQ]</em><br />
<img class="alignnone size-full wp-image-3218" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screenshot.png" alt="" width="1817" height="1267" /><br />
<a href="https://github.com/DASTUDIO/Frequalizer" target="_blank" rel="noopener">点击下载上图插件源码</a></p>
<p>学习JUCE，乃至任何一个框架，最好的办法是观看官方的教程、查阅官方的开发文档。然后就是多看代码，Github上有不少优秀的项目可供学习。要开发界面成熟高端的音频应用，最好了解一下JUCE的图形库。<br />
点击访问：<a href="https://juce.com/learn/tutorials" target="_blank" rel="noopener">JUCE官方教程</a>  |  <a href="https://docs.juce.com/master/index.html" target="_blank" rel="noopener">JUCE开发文档</a> | <a href="https://github.com/search?q=juce+audio" target="_blank" rel="noopener">上Github看相关的源码</a></p>
<p>&nbsp;</p>
<h5>三、KONTAKT音源</h5>
<p>&nbsp;</p>
<p>KONTAKT音源关注音响质量，编程上略为简单。<br />
如果你相比编程更擅长录音技术、具有设备优势、总是在混音上有想法，那这是最好的选择。</p>
<p>[实用的KONTAKT音源]<br />
<img class="alignnone size-full wp-image-3217" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-12-at-5.38.47-AM.png" alt="" width="1306" height="1426" /></p>
<p>KONTAKT可以通过看代码学习，加载任何一个KONTAKT音源，点扳手，再点Scirpt Editor里的Edit，可以看到代码，另外这里有两本KONTAKT编程的教程</p>
<p><a href="https://pan.baidu.com/s/1VHv5RDtlPkLCmTY0Za_e6g" target="_blank" rel="noopener">Kontakt Script 简易教程</a>  提取码: q5a3</p>
<p><a href="https://pan.baidu.com/s/1wH-aF-rwGhAnzG4k7ItWnw" target="_blank" rel="noopener">Kontakt Script 官方参考手册</a> 提取码: 8aqr</p>
<p>&nbsp;</p>
<p>&nbsp;<br />
&nbsp;</p>
<h6 style="text-align: center;">《音频开发技术/实战/进阶》教程 由 <strong>张新豪 </strong>于 2020年6月 创作，允许在注明出处与作者的前提下转载。</h6>
<p></br></br><br />
<center></center><center></center><center></p>
<div class="gdlr-chart gdlr-ux" data-percent="100" data-size="155" data-linewidth="8" data-color="#a9e16e" data-bg-color="#e9e9e9" data-background="" >
<div class="chart-content-wrapper">
<div class="chart-content-inner"><span class="chart-content"  style="color: ;"  >课程进度</span><span class="chart-percent-number" style="color:#a9e16e;" >100%</span></div>
</div>
</div>
<p></center></p>
]]></content:encoded>
			</item>
		<item>
		<title>音频开发进阶（三）使用DSP模块（附源码·EQ效果器）</title>
		<link>http://www.zhangxinhao.com/blog/3194</link>
		<pubDate>Sat, 06 Jun 2020 16:00:27 +0000</pubDate>
		<dc:creator><![CDATA[Honour Z]]></dc:creator>
				<category><![CDATA[音频开发]]></category>

		<guid isPermaLink="false">http://www.zhangxinhao.com/?p=3194</guid>
		<description><![CDATA[JUCE 在 5.1 版本之后加入了 dsp 模块，从此可以通过调用接口的方式实现各种音频效果，降低了对开发者... <a href="http://www.zhangxinhao.com/blog/3194" class="excerpt-read-more">Read More</a>]]></description>
				<content:encoded><![CDATA[<p></br><br />
<strong>JUCE 在 5.1 版本之后加入了 dsp 模块，从此可以通过调用接口的方式实现各种音频效果，降低了对开发者算法水平的要求。</strong></p>
<p></br></p>
<h3>确定目标</h3>
<p></br></p>
<p>一个 EQ 效果器</p>
<p></br></p>
<h3>收集信息</h3>
<p></br></p>
<p>在开发文档中的 dsp 分区里，发现 <a href="https://docs.juce.com/master/classdsp_1_1FIR_1_1Filter.html" rel="noopener" target="_blank"><strong>Filter</strong></a> 是我想要的。</p>
<p>在查阅相关资料后,得知 Filter 对象 有三个接口需要调用 :<br />
1.prepare(ProcessSpec&#038;)- 在处理信号前调用，设定采样率等规格参数，必须调用<br />
2.reset &#8211; 重置通道<br />
3.process(ProcessContextReplacing或ProcessContextNonReplacing) &#8211; 处理信号</p>
<p>查到 ProcessorDuplicator 把一个处理器变成双声道立体声两个处理器，同时它为被代理的处理器(比如这里的 dsp::IIR:Filter ) 实现一种适配器的模式。这种模式中对 ProcessorDuplicator 的操作和对原处理器(比如这里的 Filter )的的操作极为类似。<em>（在这里就是 ProcessorDuplicator 对应 Filter, ProcessorDuplicator 的参数字段 state 对应 Coefficients ）</em></p>
<p></br></p>
<h3>整理思路</h3>
<p></br></p>
<p>用 ProcessorDuplicator 代理 Filter，即 Filter 的 prepare、reset、process 都换成 ProcessorDuplicator 的。此外 ProcessorDuplicator 的 state 对象等同于 Filter 的 Coefficients的作用。</p>
<p>用 dsp::IIR::Coefficients<float>::makePeakFilter 接口为 state<em>（代理的Coefficients）</em>参数赋值，用以设置滤波器参数。</p>
<p>在prepareToPlay中调用 prepare，releaseResources调用reset。</p>
<p></br><br />
在Audio Plugin中 输出和输入同源，输入输出都是 getWritePoint 这个数组，所以 process 采用 ProcessContextReplacing 这个参数，而 ProcessContextReplacing 也需要一个AudioBlock参数才能初始化。<br />
（<em>ProssContextReplacint<float>(AudioBlock<float>(buffer))</em></p>
<p></br></p>
<p></br></p>
<h3>付诸行动</h3>
<p></br></p>
<p>先要在JUCE工程中勾选DSP模块，才能打开DSP功能使用 dsp 命名空间。</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-16-at-5.06.09-AM.png" alt="" width="1792" height="1306" class="alignnone size-full wp-image-3664" /></p>
<p>声明推子</p>
<div class="codecolorer-container cpp solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #666666;">// PluginEditor.h</span><br />
...<br />
&nbsp; &nbsp; <span style="color: #007788;">MyEqAudioProcessor</span><span style="color: #000040;">&amp;</span> processor<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; Slider HF_Vol<span style="color: #008080;">;</span> &nbsp;<span style="color: #666666;">// 声明一个推子 &lt;-</span><br />
&nbsp; &nbsp; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR <span style="color: #008000;">&#40;</span>MyEqAudioProcessorEditor<span style="color: #008000;">&#41;</span><br />
...</div></td></tr></tbody></table></div>
<p></br></p>
<p>让推子影响变量</p>
<div class="codecolorer-container cpp solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #666666;">// PluginEditor.cpp</span><br />
...<br />
<span style="color: #007788;">MyEqAudioProcessorEditor</span><span style="color: #008080;">::</span><span style="color: #007788;">MyEqAudioProcessorEditor</span> <span style="color: #008000;">&#40;</span>MyEqAudioProcessor<span style="color: #000040;">&amp;</span> p<span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #008080;">:</span> AudioProcessorEditor <span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>p<span style="color: #008000;">&#41;</span>, processor <span style="color: #008000;">&#40;</span>p<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; HF_Vol.<span style="color: #007788;">setRange</span><span style="color: #008000;">&#40;</span><span style="color:#800080;">0.01</span>, <span style="color: #0000dd;">1</span>, <span style="color:#800080;">0.01</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; HF_Vol.<span style="color: #007788;">setBounds</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">100</span>, <span style="color: #0000dd;">50</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; HF_Vol.<span style="color: #007788;">setSliderStyle</span><span style="color: #008000;">&#40;</span>Slider<span style="color: #008080;">::</span><span style="color: #007788;">SliderStyle</span><span style="color: #008080;">::</span><span style="color: #007788;">LinearHorizontal</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; HF_Vol.<span style="color: #007788;">setTextBoxStyle</span><span style="color: #008000;">&#40;</span>Slider<span style="color: #008080;">::</span><span style="color: #007788;">TextBoxBelow</span>, <span style="color: #0000ff;">true</span>, <span style="color: #0000dd;">100</span>, <span style="color: #0000dd;">30</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;;</span><br />
&nbsp; &nbsp; addAndMakeVisible<span style="color: #008000;">&#40;</span>HF_Vol<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<br />
&nbsp; &nbsp; HF_Vol.<span style="color: #007788;">onValueChange</span> <span style="color: #000080;">=</span> <span style="color: #008000;">&#91;</span><span style="color: #0000dd;">this</span><span style="color: #008000;">&#93;</span> <br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000040;">*</span><span style="color: #008000;">&#40;</span>processor.<span style="color: #007788;">myFilter</span>.<span style="color: #007788;">state</span><span style="color: #008000;">&#41;</span> <span style="color: #000080;">=</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#40;</span>dsp<span style="color: #008080;">::</span><span style="color: #007788;">IIR</span><span style="color: #008080;">::</span><span style="color: #007788;">Coefficients</span><span style="color: #000080;">&lt;</span><span style="color: #0000ff;">float</span><span style="color: #000080;">&gt;</span><span style="color: #008080;">::</span><span style="color: #007788;">makePeakFilter</span><span style="color: #008000;">&#40;</span>processor.<span style="color: #007788;">getSampleRate</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>,<span style="color:#800080;">2400.0f</span>,<span style="color:#800080;">0.7f</span>,HF_Vol.<span style="color: #007788;">getValue</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> &nbsp;<br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span><br />
<br />
&nbsp; &nbsp; setSize <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">400</span>, <span style="color: #0000dd;">300</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000040;">*</span><span style="color: #008000;">&#40;</span>processor.<span style="color: #007788;">myFilter</span>.<span style="color: #007788;">state</span><span style="color: #008000;">&#41;</span> <span style="color: #000080;">=</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#40;</span>dsp<span style="color: #008080;">::</span><span style="color: #007788;">IIR</span><span style="color: #008080;">::</span><span style="color: #007788;">Coefficients</span><span style="color: #000080;">&lt;</span><span style="color: #0000ff;">float</span><span style="color: #000080;">&gt;</span><span style="color: #008080;">::</span><span style="color: #007788;">makePeakFilter</span><span style="color: #008000;">&#40;</span>processor.<span style="color: #007788;">getSampleRate</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color:#800080;">2400.0f</span>, <span style="color:#800080;">0.7f</span>, HF_Vol.<span style="color: #007788;">getValue</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><br />
...</div></td></tr></tbody></table></div>
<p></br></p>
<p>声明处理器</p>
<div class="codecolorer-container cpp solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #666666;">// PluginProcessor.h</span><br />
...<br />
&nbsp; &nbsp; <span style="color: #0000ff;">void</span> setStateInformation <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> data, <span style="color: #0000ff;">int</span> sizeInBytes<span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">override</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; dsp<span style="color: #008080;">::</span><span style="color: #007788;">ProcessorDuplicator</span><span style="color: #000080;">&lt;</span>dsp<span style="color: #008080;">::</span><span style="color: #007788;">IIR</span><span style="color: #008080;">::</span><span style="color: #007788;">Filter</span><span style="color: #000080;">&lt;</span><span style="color: #0000ff;">float</span><span style="color: #000080;">&gt;</span>, dsp<span style="color: #008080;">::</span><span style="color: #007788;">IIR</span><span style="color: #008080;">::</span><span style="color: #007788;">Coefficients</span><span style="color: #000080;">&lt;</span><span style="color: #0000ff;">float</span><span style="color: #000080;">&gt;&gt;</span> myFilter<span style="color: #008080;">;</span> &nbsp; &nbsp; <span style="color: #666666;">// 声明一个处理器 &lt;-</span><br />
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span><br />
...</div></td></tr></tbody></table></div>
<p></br></p>
<p>prepare 与 reset</p>
<div class="codecolorer-container cpp solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #666666;">// PluginProcessor.cpp</span><br />
...<br />
<span style="color: #0000ff;">void</span> MyEqAudioProcessor<span style="color: #008080;">::</span><span style="color: #007788;">prepareToPlay</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">double</span> sampleRate, <span style="color: #0000ff;">int</span> samplesPerBlock<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; dsp<span style="color: #008080;">::</span><span style="color: #007788;">ProcessSpec</span> ps<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; ps.<span style="color: #007788;">maximumBlockSize</span> <span style="color: #000080;">=</span> samplesPerBlock<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; ps.<span style="color: #007788;">numChannels</span> <span style="color: #000080;">=</span> getTotalNumOutputChannels<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; ps.<span style="color: #007788;">sampleRate</span> <span style="color: #000080;">=</span> sampleRate<span style="color: #008080;">;</span><br />
<br />
&nbsp; &nbsp; myFilter.<span style="color: #007788;">prepare</span><span style="color: #008000;">&#40;</span>ps<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <br />
<span style="color: #008000;">&#125;</span><br />
<br />
<span style="color: #0000ff;">void</span> MyEqAudioProcessor<span style="color: #008080;">::</span><span style="color: #007788;">releaseResources</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; myFilter.<span style="color: #007788;">reset</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><br />
...</div></td></tr></tbody></table></div>
<p></br></p>
<p>处理器处理信号</p>
<div class="codecolorer-container cpp solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #666666;">// PluginProcessor.cpp</span><br />
...<br />
<span style="color: #0000ff;">void</span> MyEqAudioProcessor<span style="color: #008080;">::</span><span style="color: #007788;">processBlock</span> <span style="color: #008000;">&#40;</span>AudioBuffer<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">float</span><span style="color: #000080;">&gt;</span><span style="color: #000040;">&amp;</span> buffer, MidiBuffer<span style="color: #000040;">&amp;</span> midiMessages<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; ScopedNoDenormals noDenormals<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; myFilter.<span style="color: #007788;">process</span><span style="color: #008000;">&#40;</span>dsp<span style="color: #008080;">::</span><span style="color: #007788;">ProcessContextReplacing</span><span style="color: #000080;">&lt;</span><span style="color: #0000ff;">float</span><span style="color: #000080;">&gt;</span><span style="color: #008000;">&#40;</span>dsp<span style="color: #008080;">::</span><span style="color: #007788;">AudioBlock</span><span style="color: #000080;">&lt;</span><span style="color: #0000ff;">float</span><span style="color: #000080;">&gt;</span><span style="color: #008000;">&#40;</span>buffer<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><br />
...</div></td></tr></tbody></table></div>
<p></br><br />
这样就完成了<br />
</br></p>
<h5><a href="https://github.com/DASTUDIO/Juce_Audio_Tutorial/tree/master/MyEQ" rel="noopener" target="_blank">点击这里下载源码</a></h5>
<p><center></p>
<div class="gdlr-chart gdlr-ux" data-percent="90" data-size="155" data-linewidth="8" data-color="#a9e16e" data-bg-color="#e9e9e9" data-background="" >
<div class="chart-content-wrapper">
<div class="chart-content-inner"><span class="chart-content"  style="color: ;"  >课程进度</span><span class="chart-percent-number" style="color:#a9e16e;" >90%</span></div>
</div>
</div>
<p></center></p>
]]></content:encoded>
			</item>
		<item>
		<title>音频开发进阶（二）使用API文档 （附源码·混响效果器）</title>
		<link>http://www.zhangxinhao.com/blog/3192</link>
		<pubDate>Fri, 05 Jun 2020 16:00:31 +0000</pubDate>
		<dc:creator><![CDATA[Honour Z]]></dc:creator>
				<category><![CDATA[音频开发]]></category>

		<guid isPermaLink="false">http://www.zhangxinhao.com/?p=3192</guid>
		<description><![CDATA[&#160; 框架的时代 &#160; 如今，我们输出一行 “Hello World” 到屏幕上，已经不需要手... <a href="http://www.zhangxinhao.com/blog/3192" class="excerpt-read-more">Read More</a>]]></description>
				<content:encoded><![CDATA[<p>&nbsp;</p>
<h3>框架的时代</h3>
<p>&nbsp;</p>
<p>如今，我们输出一行 “Hello World” 到屏幕上，已经不需要手动地把数据移动到显存里面了。一句简单地语句就可以搞定。高级程序语言本身就是一种框架。</p>
<h5>不要重复发明轮子</h5>
<p>当你要开发的功能 已经存在了成熟的框架，我劝你最好使用它们。</p>
<p>相比一个人从头开始写底层功能，现成的框架已经有了一段时间的积累，它们更稳定，更安全，优化更好，而且还方便。</p>
<p>当然如果你对某些功能有更深入的理解，或是为了长远的打算，编写一个框架也是件很了不起的事。</p>
<p>&nbsp;</p>
<h5>无论用什么框架开发，都离不开对开发文档的查阅</h5>
<p>&nbsp;</p>
<p>本节我们就了解一下 如何使用 JUCE 开发文档，编写一个 Reverb 混响插件。</p>
<p>&nbsp;</p>
<h3>1.明确需求</h3>
<p>一个混响效果器</p>
<h3>2.收集信息</h3>
<p>&nbsp;</p>
<p>我们先来到 <a href="https://docs.juce.com/master/index.html" target="_blank" rel="noopener">JUCE的开发文档（点击打开）</a>， 看看有没有用得上的东西。</p>
<p>网页里，按下Ctrl + F (Mac 上 Command + F)， 搜索 reverb 然后回车</p>
<p>找到这个，应该是我们想要的</p>
<p><img class="alignnone size-full wp-image-3617" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/rev1.jpg" alt="" width="2074" height="800" /></p>
<p>点进去，看到 Description 里说了，先用 setSampleRate 接口准备一下，然后用 processStereo 或者 processMono 处理信号就行了</p>
<p><img class="alignnone size-full wp-image-3619" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-15-at-7.34.15-PM.png" alt="" width="2316" height="1124" /></p>
<p>看完说明，就大概了解了它的用法。<em>（以后我们接触的东西多了，就不用看说明了，这些方法大同小异）</em></p>
<p>然而现在我们还有一个需求没有得到解决，那就是调节参数。</p>
<p>继续寻找，在上方的 Member Functions 功能接口的描述中，看到了 setParameters 接口，它的传入参数是一个 ‘Parameters’ 类型 的东西，我们点一下那个 Parameters。</p>
<p><img class="alignnone size-full wp-image-3620" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-15-at-7.36.13-PM.png" alt="" width="1698" height="1062" /></p>
<p>发现它是个结构体，里面的字段就是混响的参数，这些参数都是默认初始化过的。</p>
<p>好了，现在已经收集到需要的全部信息了。</p>
<p>&nbsp;</p>
<h3>3.整理思路</h3>
<p>&nbsp;</p>
<p><del>我们看到上面 Reverb 的文档中写的都是些成员方法，理所当然就想到实例化一个 Reverb 的对象来用，在JUCE里，这是不必要的。</del><br />
<del> Reverb 是来自JUCE库里的类，它的对象不用 new 不用 Reverb() 实例化创建，只要声明了它，JUCE 框架就会自动为我们注入一个合适的 Reverb 对象。所以把它当成结构体就可以了，<strong>【Reverb 对象声明完直接使用】</strong>。（<em>这是一个好架构，它让开发者专注于业务逻辑，避免分心</em>）</del></p>
<p>有别于其他语言，C++实例化对象是可以不new的。</p>
<p>一般来说对象都是保存在堆上，但C++可以通过这种不new的方式直接把它保存在栈上，这样实例化出来的对象只作用于函数内部，函数执行后就删除了。</p>
<p>&nbsp;</p>
<p>setParameters 用到的参数是个结构体，值类型的声明后直接用就行了。</p>
<p>Reverb 对象需要在使用前调用一下 <strong>【setSampleRate】</strong>接口。在<a href="http://www.zhangxinhao.com/blog/3126" target="_blank" rel="noopener">《音频开发实战（二）》</a>的时候，我们使用了一个 getSampleRate 接口获取采样频率，而这个接口并不是每一次都有返回。为了更好的稳定性，我们选用PluginProcessor 的回调 <strong>【prepareToPlay (double sampleRate, int samplesPerBlock) 】</strong>中的采样频率。</p>
<p>最后在 processBlock 中用 <strong>【processStereo】</strong> 接口处理立体声，这个接口的传入的参数是 左边的信号序列指针，右边的信号序列指针，处理多少个点。<br />
这三个参数刚好就是 buffer.getWritePointer(0), buffer.getWritePointer(1), buffer.getNumSamples()。</p>
<p>好了，我们已经知道怎么做了</p>
<p>&nbsp;</p>
<h3>4.付诸行动</h3>
<p>&nbsp;</p>
<h5>-&gt; 数据处理</h5>
<p>首先在 processor 的头文件准备好 Reverb 对象 和 它的 参数结构体</p>
<div class="codecolorer-container cpp solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #666666;">// PluginProcessor.h</span><br />
...<br />
<span style="color: #007788;">Reverb</span> reverbInstance<span style="color: #008080;">;</span><br />
Reverb<span style="color: #008080;">::</span><span style="color: #007788;">Parameters</span> reverbParameters<span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span><br />
...</div></td></tr></tbody></table></div>
<p>然后在 prepareToPlay 回调里，调用 Reverb 对象的 setSampleRate 接口</p>
<div class="codecolorer-container cpp solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #666666;">// PluginProcessor.cpp</span><br />
...<br />
<span style="color: #0000ff;">void</span> MyReverbAudioProcessor<span style="color: #008080;">::</span><span style="color: #007788;">prepareToPlay</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">double</span> sampleRate, <span style="color: #0000ff;">int</span> samplesPerBlock<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
reverbInstance.<span style="color: #007788;">setSampleRate</span><span style="color: #008000;">&#40;</span>sampleRate<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><br />
...</div></td></tr></tbody></table></div>
<p>在信号处理的回调 processBlock 中， 把 buffer 写入指针 和 采样点数量的信息 直接传给 Reverb 对象的 processStereo 接口。</p>
<div class="codecolorer-container cpp solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #666666;">// PluginProcessor.cpp</span><br />
...<br />
<span style="color: #0000ff;">void</span> MyReverbAudioProcessor<span style="color: #008080;">::</span><span style="color: #007788;">processBlock</span> <span style="color: #008000;">&#40;</span>AudioBuffer<span style="color: #000040;">&amp;</span>amp<span style="color: #008080;">;</span> buffer, MidiBuffer<span style="color: #000040;">&amp;</span>amp<span style="color: #008080;">;</span> midiMessages<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
ScopedNoDenormals noDenormals<span style="color: #008080;">;</span><br />
<br />
<span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">auto</span> sample <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> sample <span style="color: #000040;">&amp;</span>lt<span style="color: #008080;">;</span> buffer.<span style="color: #007788;">getNumSamples</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> sample<span style="color: #000040;">++</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
reverbInstance.<span style="color: #007788;">processStereo</span><span style="color: #008000;">&#40;</span>buffer.<span style="color: #007788;">getWritePointer</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span>, buffer.<span style="color: #007788;">getWritePointer</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span>, buffer.<span style="color: #007788;">getNumSamples</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><br />
<span style="color: #008000;">&#125;</span><br />
...</div></td></tr></tbody></table></div>
<p>运算的部分就写完了。</p>
<blockquote><p>那么 setParameters 在哪呢？ 我们还没有写，要知道processor的初始化是早于editor的，毕竟它是作为editor构造方法的参数被传入的，那既然 processor 中没有调用 setParameters 接口，在设置参数前没有参数的情况下 processStereo 被调用了怎么办呢。</p>
<p>没有关系，Reverb 已经为我们初始化了一个默认的结构体，这个默认的结构体里包含默认的参数值。</p>
<p>F12 到 Reverb 里看一下它的定义</p>
<p><img class="alignnone size-full wp-image-3636" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-15-at-11.51.34-PM.png" alt="" width="1528" height="802" /></p></blockquote>
<p>&nbsp;</p>
<h5>-&gt; 界面</h5>
<p>在头文件里声明一个推子</p>
<div class="codecolorer-container cpp solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #666666;">// PluginEditor.h</span><br />
...<br />
<span style="color: #007788;">MyReverbAudioProcessor</span><span style="color: #000040;">&amp;</span>amp<span style="color: #008080;">;</span> processor<span style="color: #008080;">;</span><br />
Slider RoomSize<span style="color: #008080;">;</span><br />
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR <span style="color: #008000;">&#40;</span>MyReverbAudioProcessorEditor<span style="color: #008000;">&#41;</span><br />
...</div></td></tr></tbody></table></div>
<p>我们已经知道了 Reverb::Parameters 是有默认值的，于是我们调整推子的位置到默认的参数的地方。</p>
<p>然后写推子监听方法：当推子位置改变时调节 reverbParameters 结构体，并把它应用到 reverbInstance 上。</p>
<div class="codecolorer-container cpp solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #666666;">// PluginEditor.cpp</span><br />
...<br />
<span style="color: #007788;">MyReverbAudioProcessorEditor</span><span style="color: #008080;">::</span><span style="color: #007788;">MyReverbAudioProcessorEditor</span> <span style="color: #008000;">&#40;</span>MyReverbAudioProcessor<span style="color: #000040;">&amp;</span>amp<span style="color: #008080;">;</span> p<span style="color: #008000;">&#41;</span><br />
<span style="color: #008080;">:</span> AudioProcessorEditor <span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>amp<span style="color: #008080;">;</span>p<span style="color: #008000;">&#41;</span>, processor <span style="color: #008000;">&#40;</span>p<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
RoomSize.<span style="color: #007788;">setRange</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">1</span>, <span style="color:#800080;">0.01</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
RoomSize.<span style="color: #007788;">setBounds</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">300</span>, <span style="color: #0000dd;">50</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
RoomSize.<span style="color: #007788;">setSliderStyle</span><span style="color: #008000;">&#40;</span>Slider<span style="color: #008080;">::</span><span style="color: #007788;">SliderStyle</span><span style="color: #008080;">::</span><span style="color: #007788;">LinearHorizontal</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
RoomSize.<span style="color: #007788;">setTextBoxStyle</span><span style="color: #008000;">&#40;</span>Slider<span style="color: #008080;">::</span><span style="color: #007788;">TextBoxBelow</span>,<span style="color: #0000ff;">true</span>,<span style="color: #0000dd;">100</span>,<span style="color: #0000dd;">50</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<br />
RoomSize.<span style="color: #007788;">setValue</span><span style="color: #008000;">&#40;</span>processor.<span style="color: #007788;">reverbParameters</span>.<span style="color: #007788;">roomSize</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
RoomSize.<span style="color: #007788;">onValueChange</span> <span style="color: #000080;">=</span> <span style="color: #008000;">&#91;</span><span style="color: #0000dd;">this</span><span style="color: #008000;">&#93;</span><br />
<span style="color: #008000;">&#123;</span><br />
processor.<span style="color: #007788;">reverbParameters</span>.<span style="color: #007788;">roomSize</span> <span style="color: #000080;">=</span> RoomSize.<span style="color: #007788;">getValue</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
processor.<span style="color: #007788;">reverbInstance</span>.<span style="color: #007788;">setParameters</span><span style="color: #008000;">&#40;</span>processor.<span style="color: #007788;">reverbParameters</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span><br />
<br />
addAndMakeVisible<span style="color: #008000;">&#40;</span>RoomSize<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
setSize <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">400</span>, <span style="color: #0000dd;">300</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><br />
...</div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<blockquote><p>这里 []{} 也就是 [](){}， C++ 中 Lambda 表达式的小括号 &#8216;()&#8217; 没有参数时可以省略</p></blockquote>
<p>&nbsp;</p>
<h3>5.验证 &amp; 反馈调节</h3>
<p>&nbsp;</p>
<p>OK 没有任何问题</p>
<p><img class="alignnone size-full wp-image-3648" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-16-at-1.53.02-AM.png" alt="" width="786" height="466" /></p>
<h5><a href="https://github.com/DASTUDIO/Juce_Audio_Tutorial/tree/master/MyReverb" target="_blank" rel="noopener">点击这里下载源码</a></h5>
<p><center></p>
<div class="gdlr-chart gdlr-ux" data-percent="80" data-size="155" data-linewidth="8" data-color="#a9e16e" data-bg-color="#e9e9e9" data-background="" >
<div class="chart-content-wrapper">
<div class="chart-content-inner"><span class="chart-content"  style="color: ;"  >课程进度</span><span class="chart-percent-number" style="color:#a9e16e;" >80%</span></div>
</div>
</div>
<p></center></p>
]]></content:encoded>
			</item>
		<item>
		<title>音频开发进阶（一）保存插件状态 (附源码·门限器)</title>
		<link>http://www.zhangxinhao.com/blog/3188</link>
		<pubDate>Thu, 04 Jun 2020 16:00:18 +0000</pubDate>
		<dc:creator><![CDATA[Honour Z]]></dc:creator>
				<category><![CDATA[音频开发]]></category>

		<guid isPermaLink="false">http://www.zhangxinhao.com/?p=3188</guid>
		<description><![CDATA[在《音频开发实战（三）》，我们讨论 KSP 脚本语言的时候， 谈及了 make_persistent 这个接口... <a href="http://www.zhangxinhao.com/blog/3188" class="excerpt-read-more">Read More</a>]]></description>
				<content:encoded><![CDATA[<p></br><br />
<em>在<a href="http://www.zhangxinhao.com/blog/3128" rel="noopener" target="_blank">《音频开发实战（三）》</a>，我们讨论 KSP 脚本语言的时候， 谈及了 make_persistent 这个接口。</p>
<p>它的作用是让一个参数被系统自动保存，这样我们的参数就可以被记录在宿主软件的工程文件里，这个过程叫做 <strong>数据持久化</strong>。</p>
<p>在JUCE中，也是一样的，倘若我们的参数没有做过数据持久化，那么在工程下一次被打开时，所有参数都会全部消失，调好的旋钮、推子都会清零。</p>
<p>这一节，我们看一下JUCE中如何实现数据持久化，即如何保存应用的参数。</em></p>
<p></br></p>
<h3>制作基本Gate门限器</h3>
<p>新建一个 Audio Plugin 工程 MyGate -> IDE中打开</p>
<p>类似<a href="http://www.zhangxinhao.com/blog/3107" rel="noopener" target="_blank">《音频开发实战（一）》</a>中写音量推子那样，不同的是这次的运算：判断如果音量没有达到阈值，则不输出。</p>
<p></br><br />
<em>PluginEditor.h</em></p>
<div class="codecolorer-container cpp solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #666666;">//PluginEditor.h</span><br />
...<br />
&nbsp; &nbsp; <span style="color: #007788;">MyGateAudioProcessor</span><span style="color: #000040;">&amp;</span> processor<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; Slider Threshold<span style="color: #008080;">;</span> &nbsp; <span style="color: #666666;">// 声明一个推子 &lt;-</span><br />
&nbsp; &nbsp; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR <span style="color: #008000;">&#40;</span>MyGateAudioProcessorEditor<span style="color: #008000;">&#41;</span><br />
...</div></td></tr></tbody></table></div>
<p></br><br />
<em>PluginEditor.cpp</em></p>
<div class="codecolorer-container cpp solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #666666;">//PluginEditor.cpp</span><br />
...<br />
<span style="color: #007788;">MyGateAudioProcessorEditor</span><span style="color: #008080;">::</span><span style="color: #007788;">MyGateAudioProcessorEditor</span> <span style="color: #008000;">&#40;</span>MyGateAudioProcessor<span style="color: #000040;">&amp;</span> p<span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #008080;">:</span> AudioProcessorEditor <span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>p<span style="color: #008000;">&#41;</span>, processor <span style="color: #008000;">&#40;</span>p<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; Threshold.<span style="color: #007788;">setBounds</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">300</span>, <span style="color: #0000dd;">100</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; Threshold.<span style="color: #007788;">setRange</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">1</span>, <span style="color:#800080;">0.01</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; Threshold.<span style="color: #007788;">setSliderStyle</span><span style="color: #008000;">&#40;</span>Slider<span style="color: #008080;">::</span><span style="color: #007788;">SliderStyle</span><span style="color: #008080;">::</span><span style="color: #007788;">LinearHorizontal</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; Threshold.<span style="color: #007788;">setTextBoxStyle</span><span style="color: #008000;">&#40;</span>Slider<span style="color: #008080;">::</span><span style="color: #007788;">TextBoxBelow</span>,<span style="color: #0000ff;">true</span>,<span style="color: #0000dd;">100</span>,<span style="color: #0000dd;">50</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; Threshold.<span style="color: #007788;">onValueChange</span> <span style="color: #000080;">=</span> <span style="color: #008000;">&#91;</span><span style="color: #0000dd;">this</span><span style="color: #008000;">&#93;</span> <span style="color: #008000;">&#123;</span>processor._threshold <span style="color: #000080;">=</span> Threshold.<span style="color: #007788;">getValue</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; addAndMakeVisible<span style="color: #008000;">&#40;</span>Threshold<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; setSize <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">400</span>, <span style="color: #0000dd;">300</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><br />
...</div></td></tr></tbody></table></div>
<p></br><br />
<em>PluginProcessor.h</em></p>
<div class="codecolorer-container cpp solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #666666;">//PluginProcessor.h</span><br />
...<br />
&nbsp; &nbsp; <span style="color: #0000ff;">void</span> setStateInformation <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> data, <span style="color: #0000ff;">int</span> sizeInBytes<span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">override</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">double</span> _threshold <span style="color: #000080;">=</span> <span style="color:#800080;">0.0</span><span style="color: #008080;">;</span> &nbsp; &nbsp; <span style="color: #666666;">// 声明一个变量 &nbsp;&lt;-</span><br />
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span><br />
...</div></td></tr></tbody></table></div>
<p></br><br />
<em>PluginProcessor.cpp</em></p>
<div class="codecolorer-container cpp solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #666666;">//PluginProcessor.cpp</span><br />
...<br />
<span style="color: #0000ff;">void</span> MyGateAudioProcessor<span style="color: #008080;">::</span><span style="color: #007788;">processBlock</span> <span style="color: #008000;">&#40;</span>AudioBuffer<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">float</span><span style="color: #000080;">&gt;</span><span style="color: #000040;">&amp;</span> buffer, MidiBuffer<span style="color: #000040;">&amp;</span> midiMessages<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; ScopedNoDenormals noDenormals<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #0000ff;">auto</span><span style="color: #000040;">*</span> channelL <span style="color: #000080;">=</span> buffer.<span style="color: #007788;">getWritePointer</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">auto</span><span style="color: #000040;">*</span> channelR <span style="color: #000080;">=</span> buffer.<span style="color: #007788;">getWritePointer</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">auto</span> sample <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> sample <span style="color: #000080;">&lt;</span> buffer.<span style="color: #007788;">getNumSamples</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> sample<span style="color: #000040;">++</span><span style="color: #008000;">&#41;</span> <br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; channelL<span style="color: #008000;">&#91;</span>sample<span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> std<span style="color: #008080;">::</span><span style="color: #0000dd;">abs</span><span style="color: #008000;">&#40;</span>channelL<span style="color: #008000;">&#91;</span>sample<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span> <span style="color: #000080;">&gt;</span> _threshold <span style="color: #008080;">?</span> channelL<span style="color: #008000;">&#91;</span>sample<span style="color: #008000;">&#93;</span> <span style="color: #008080;">:</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; channelR<span style="color: #008000;">&#91;</span>sample<span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> std<span style="color: #008080;">::</span><span style="color: #0000dd;">abs</span><span style="color: #008000;">&#40;</span>channelR<span style="color: #008000;">&#91;</span>sample<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span> <span style="color: #000080;">&gt;</span> _threshold <span style="color: #008080;">?</span> channelR<span style="color: #008000;">&#91;</span>sample<span style="color: #008000;">&#93;</span> <span style="color: #008080;">:</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
<br />
<span style="color: #008000;">&#125;</span><br />
...</div></td></tr></tbody></table></div>
<p></br></p>
<blockquote><p>1.这里我用了一个三目运算符，意思是：【条件 ? 条件成立返回的值 ： 条件不成立返回的值】<br />
2.为了方便，接收被赋值的变量时 我用了auto关键字，它就像是c#或js的 var 一样，能够自动判断类型。
</p></blockquote>
<p></br></p>
<h6>验证</h6>
<p>OK 没问题</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-15-at-4.11.21-PM.png" alt="" width="796" height="466" class="alignnone size-full wp-image-3590" /></p>
<p></br></p>
<h3>持久化参数</h3>
<p></br></p>
<h6>改变参数的类型</h6>
<p></br></p>
<p>我们先把 在 PluginProcessor 定义的变量 换成 JUCE 提供的 AudioParameterFloat 类型的指针. <em>(同理还有 AudioParameterInt 等其他类型)</em></p>
<p>它在使用的时候和普通Float指针没区别。</p>
<p><em>PluginProcessor.h</em></p>
<div class="codecolorer-container cpp solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #666666;">//PluginProcessor.h</span><br />
...<br />
&nbsp; &nbsp; <span style="color: #666666;">// double _threshold = 0.0;</span><br />
&nbsp; &nbsp; AudioParameterFloat<span style="color: #000040;">*</span> _threshold<span style="color: #008080;">;</span><br />
...</div></td></tr></tbody></table></div>
<p></br></p>
<p>从变量改成了指针，那用到它的地方就需要把它当作指针来使用，这样修改。</p>
<p><em>PlugiProcessor.h</em></p>
<div class="codecolorer-container cpp solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #666666;">//PlugiProcessor.h</span><br />
...<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// channelL[sample] = std::abs(channelL[sample]) &gt; _threshold ? channelL[sample] : 0;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// channelR[sample] = std::abs(channelR[sample]) &gt; _threshold ? channelR[sample] : 0;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; channelL<span style="color: #008000;">&#91;</span>sample<span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> std<span style="color: #008080;">::</span><span style="color: #0000dd;">abs</span><span style="color: #008000;">&#40;</span>channelL<span style="color: #008000;">&#91;</span>sample<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span> <span style="color: #000080;">&gt;</span> <span style="color: #000040;">*</span>_threshold <span style="color: #008080;">?</span> channelL<span style="color: #008000;">&#91;</span>sample<span style="color: #008000;">&#93;</span> <span style="color: #008080;">:</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; channelR<span style="color: #008000;">&#91;</span>sample<span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> std<span style="color: #008080;">::</span><span style="color: #0000dd;">abs</span><span style="color: #008000;">&#40;</span>channelR<span style="color: #008000;">&#91;</span>sample<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span> <span style="color: #000080;">&gt;</span> <span style="color: #000040;">*</span>_threshold <span style="color: #008080;">?</span> channelR<span style="color: #008000;">&#91;</span>sample<span style="color: #008000;">&#93;</span> <span style="color: #008080;">:</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span><br />
...</div></td></tr></tbody></table></div>
<p>还有这里也要修改。</p>
<p><em>PluginEditor.cpp</em></p>
<div class="codecolorer-container cpp solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #666666;">//PluginEditor.cpp</span><br />
...<br />
&nbsp; &nbsp; <span style="color: #666666;">// Threshold.onValueChange = [this] {processor._threshold = Threshold.getValue(); };</span><br />
&nbsp; &nbsp; Threshold.<span style="color: #007788;">onValueChange</span> <span style="color: #000080;">=</span> <span style="color: #008000;">&#91;</span><span style="color: #0000dd;">this</span><span style="color: #008000;">&#93;</span> <span style="color: #008000;">&#123;</span><span style="color: #000040;">*</span><span style="color: #008000;">&#40;</span>processor._threshold<span style="color: #008000;">&#41;</span> <span style="color: #000080;">=</span> Threshold.<span style="color: #007788;">getValue</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span><br />
...</div></td></tr></tbody></table></div>
<p>我们希望每次重新打开工程的时候，界面上的推子的位置也是我们的保存的参数。来到 PluginEditor 的构造方法，加上这句。</p>
<p><em>PluginEditor.cpp</em></p>
<div class="codecolorer-container cpp solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #666666;">//PluginEditor.cpp</span><br />
...<br />
&nbsp; &nbsp; <span style="color: #007788;">Threshold</span>.<span style="color: #007788;">onValueChange</span> <span style="color: #000080;">=</span> <span style="color: #008000;">&#91;</span><span style="color: #0000dd;">this</span><span style="color: #008000;">&#93;</span> <span style="color: #008000;">&#123;</span><span style="color: #000040;">*</span><span style="color: #008000;">&#40;</span>processor._threshold<span style="color: #008000;">&#41;</span> <span style="color: #000080;">=</span> Threshold.<span style="color: #007788;">getValue</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; Threshold.<span style="color: #007788;">setValue</span><span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span><span style="color: #008000;">&#40;</span>processor._threshold<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #666666;">// 设置推子组件的值为保存的参数 &lt;-</span><br />
&nbsp; &nbsp; addAndMakeVisible<span style="color: #008000;">&#40;</span>Threshold<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
...</div></td></tr></tbody></table></div>
<p></br></p>
<p></br></p>
<h6>负责持久化的回调函数</h6>
<p></br></p>
<p>记得在<a href="http://www.zhangxinhao.com/blog/3055" rel="noopener" target="_blank">《音频开发技术（三）》</a>中我们提到过，PluginProcessor中有一大堆方法都是可选功能吗。</p>
<p>持久化的回调函数就在这一大堆可选功能中，在其中找到 getStateInformation 和 setStateInformation 这两个回调。</p>
<p><strong>getStateInformation 储存到插件的信息到内存<br />
setStateInformation 从内存中提取插件的信息</strong></p>
<p>getStateInformation 中用 MemoryOutputStream 对象的 writeFloat 方法</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-15-at-5.33.38-PM.png" alt="" width="1146" height="194" class="alignnone size-full wp-image-3604" /></p>
<p>setStateInformation 中用 MemoryInputStream 对象的 readFloat 方法</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-15-at-5.32.37-PM.png" alt="" width="1400" height="304" class="alignnone size-full wp-image-3603" /></p>
<p>现在编写代码。</p>
<p><em>PluginProcessor.cpp</em></p>
<div class="codecolorer-container cpp solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #666666;">//PluginProcessor.cpp</span><br />
...<br />
<span style="color: #0000ff;">void</span> MyGateAudioProcessor<span style="color: #008080;">::</span><span style="color: #007788;">getStateInformation</span> <span style="color: #008000;">&#40;</span>MemoryBlock<span style="color: #000040;">&amp;</span> destData<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; MemoryOutputStream<span style="color: #008000;">&#40;</span>destData, <span style="color: #0000ff;">true</span><span style="color: #008000;">&#41;</span>.<span style="color: #007788;">writeFloat</span><span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span>_threshold<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><br />
<br />
<span style="color: #0000ff;">void</span> MyGateAudioProcessor<span style="color: #008080;">::</span><span style="color: #007788;">setStateInformation</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> data, <span style="color: #0000ff;">int</span> sizeInBytes<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000040;">*</span>_threshold <span style="color: #000080;">=</span> MemoryInputStream<span style="color: #008000;">&#40;</span>data, <span style="color: #0000ff;">static_cast</span><span style="color: #000080;">&lt;</span><span style="color: #0000ff;">size_t</span><span style="color: #000080;">&gt;</span><span style="color: #008000;">&#40;</span>sizeInBytes<span style="color: #008000;">&#41;</span>, <span style="color: #0000ff;">false</span><span style="color: #008000;">&#41;</span>.<span style="color: #007788;">readFloat</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><br />
...</div></td></tr></tbody></table></div>
<p></br></p>
<p>生成导出试了一下，已经可以保存参数了。</p>
<p></br></p>
<h6>持久化的细节</h6>
<p></br></p>
<p>我们只是把插件的信息写到了内存中，而最终的持久化还是DAW宿主软件为我们做的。</p>
<p>宿主软件把内存中的信息编码保存在了工程文件中。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h5><a href="https://github.com/DASTUDIO/Juce_Audio_Tutorial/tree/master/MyGate" rel="noopener" target="_blank">点击这里下载源码</a></h5>
<p><center></p>
<div class="gdlr-chart gdlr-ux" data-percent="70" data-size="155" data-linewidth="8" data-color="#a9e16e" data-bg-color="#e9e9e9" data-background="" >
<div class="chart-content-wrapper">
<div class="chart-content-inner"><span class="chart-content"  style="color: ;"  >课程进度</span><span class="chart-percent-number" style="color:#a9e16e;" >70%</span></div>
</div>
</div>
<p></center></p>
]]></content:encoded>
			</item>
		<item>
		<title>音频开发实战（三）制作KONTAKT音源 (附源码) [KSP编程]</title>
		<link>http://www.zhangxinhao.com/blog/3128</link>
		<pubDate>Wed, 03 Jun 2020 16:00:30 +0000</pubDate>
		<dc:creator><![CDATA[Honour Z]]></dc:creator>
				<category><![CDATA[音频开发]]></category>

		<guid isPermaLink="false">http://www.zhangxinhao.com/?p=3128</guid>
		<description><![CDATA[&#160; 这节，我们制作一个这样的音源 前言 说起上一节中能自主产生波形的合成器，我们不免想到和它相对的，... <a href="http://www.zhangxinhao.com/blog/3128" class="excerpt-read-more">Read More</a>]]></description>
				<content:encoded><![CDATA[<p>&nbsp;</p>
<h6 style="text-align: center;">这节，我们制作一个这样的音源</h6>
<p style="text-align: center;"><img class="alignnone size-full wp-image-3132" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/pic.png" alt="" width="1296" height="952" /></p>
<h6>前言</h6>
<p>说起上一节中能自主产生波形的合成器，我们不免想到和它相对的，利用人工录制的采样发声的采样器。</p>
<p>比起开发一个采样器来说，开发Kontakt是更好的选择。</p>
<p><em>编写采样器有一些底层的，现阶段没有必要了解的内容。</em></p>
<p>&nbsp;</p>
<h6>开发Kontakt?</h6>
<p>可能在我们印象中，Kontakt的作用就是打开它然后选音色用，和编程没什么联系。</p>
<p>但实际上，Kontakt是一个可编程的采样器。两个重点：</p>
<ol>
<li>它是一个采样器。</li>
<li>它可被编程。</li>
</ol>
<p>&nbsp;</p>
<h6>重新认识Kontakt</h6>
<p>打开Kontakt，不加载任何音色</p>
<p>点击那个保存样子的按钮，然后选New instrument新建一个乐器</p>
<p><img class="alignnone size-full wp-image-3146" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/11.jpg" alt="" width="1984" height="1322" /></p>
<p>然后就出现一个新的空乐器，点击扳手</p>
<p><img class="alignnone size-full wp-image-3147" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/22.jpg" alt="" width="1352" height="338" /></p>
<p>然后就出现了 Kontakt采样器功能的界面, 我们平时用的各种Kontakt音源就是在这里被制作的</p>
<p><img class="alignnone size-full wp-image-3150" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-11-at-9.45.55-PM.png" alt="" width="1286" height="1078" /></p>
<p>先看一下界面的最下面有四排：</p>
<p><strong>| InstrumentBuses | InsertEffects | SendEffects | Modulation |</strong></p>
<p><em>这四排是可以展开的标签页，点左边的三角就可以展开/关闭。</em></p>
<p>它们<strong>全是效果</strong>，用的地方不同。</p>
<p>&nbsp;</p>
<p>再看界面的最上面有五个按钮：</p>
<p><strong>| Instrument Options | Group Editor | Mapping Editor | Wave Editor | Script Editor |</strong></p>
<p>它们分别是：</p>
<p><strong>乐器设置、群组编辑器、映射编辑器、波形编辑器、脚本编辑器。</strong></p>
<p>&nbsp;</p>
<h6>制作音源（设置背景）</h6>
<p>先看看第一个按钮，点一下<strong>Instrument Options(乐器设置)</strong></p>
<p><img class="alignnone size-full wp-image-3153" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-11-at-11.04.53-PM.png" alt="" width="980" height="540" /></p>
<p>看到有个<strong>Instrument Wallpaper（乐器墙纸）</strong>，那我们找张图</p>
<p><em>我在网上搜了张图，稍微P了一下，如下</em></p>
<p><img class="alignnone size-full wp-image-3135" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/7.png" alt="" width="650" height="405" /></p>
<p><em>图需要png或tga的格式</em></p>
<p>设置成Wallpaper，点扳手回到主界面</p>
<p><img class="alignnone size-full wp-image-3147" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/22.jpg" alt="" width="1352" height="338" /></p>
<p><img class="alignnone size-full wp-image-3154" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-11-at-11.39.55-PM.png" alt="" width="1284" height="276" /></p>
<p>不管怎么说，背景改变了 （<em>后期可以用代码控制界面大小来让背景显示的多一些）</em></p>
<p>&nbsp;</p>
<h6>制作音源（映射采样）</h6>
<p>接下来点击第三个按钮：<strong>Mapping Editor（映射编辑器）</strong></p>
<p><em>映射的意思是把采样（录音文件）对应到MIDI键盘上，当你某这个键的时候就播放上面对应的那个采样（录音文件）</em></p>
<p>我们先在左边的文件浏览器里找到我们准备的录音文件，我这里用的是洛天依的.wav格式的呼吸包做例子</p>
<p><img class="alignnone size-full wp-image-3269" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-12-at-12.26.33-PM.png" alt="" width="2022" height="1458" /></p>
<p>从左边按住一个波形文件，拖动到对应的按键，我们看到现在这个音频对应了好几个键（这样的话这几个键按下去都是这同一个声）</p>
<p><img class="alignnone size-full wp-image-3266" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/opt1.jpg" alt="" width="1980" height="1423" /></p>
<p>没关系，保持拖动不要放开，把鼠标向下移动一些，它就收窄了。（或者松开然后拖拽白块的左右边界也能调节宽窄）</p>
<p><img class="alignnone size-full wp-image-3267" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/opt2.jpg" alt="" width="2004" height="1435" /></p>
<p>就这样把所有波形拖进来</p>
<p><img class="alignnone size-full wp-image-3268" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-12-at-12.28.36-PM.png" alt="" width="1236" height="784" /></p>
<p>按下键盘，有声音了！</p>
<p>&nbsp;</p>
<blockquote><p><strong>力度分层</strong>：一个人大喊出来的声音和他平时说话的声音，除了音量不同，声音内容也是完全不同的，乐器也是如此。为了模拟乐器这种真实自然的效果，我们在音源制作中，常常会让一个按键对应多个录音文件，演奏时由力度决定采样器播放哪个音频文件。</p>
<p>力度体现在KONTAKT的映射编辑器里就是纵轴。刚才我们说过，映射块可以拖动左右边界调整映射到键盘的范围。其实这个映射块还可以上下拖动来调整这个录音文件对应的力度范围。</p>
<p><em>例如：图中选中的这个块（黄块）对应的力度是43-80</em></p>
<p><img class="alignnone size-full wp-image-3283" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/vel.jpg" alt="" width="683" height="659" /></p></blockquote>
<p>&amp;</p>
<blockquote><p><em><strong>群组编辑器与波形编辑器：</strong>本例中并不需要使用它们，我简单介绍下用在什么地方。</em></p>
<p><em>-&gt; 群组编辑器的一个作用是切换音色，一架钢琴，后盖盖上和打开是不同的音色，如果希望把这两种音色都涵盖到音源里，那么就要录两遍给两个群组。开盖一遍，合盖再一遍，这样我们拥有两组映射。我们用写代码切换群组的方式切换音源当前的音色。</em></p>
<p><em>群组还有一个用途是合成，有些音源是好几个麦克风录的，实现多个麦克风的声音合到一起的就是多个群组一起播放。</em></p>
<p>再有就是管弦音源会通过群组摆位实现一些效果。</p>
<p><em>-&gt; 波形编辑器：调整波形，告诉采样器这个波形要怎么用。比如我们的录音文件就1s，但我们希望在按着它时它能发出持续的声音，不是1秒就没了。这就要用波形编辑器，在里面设置个Loop。这个编辑器里还有很多细节，影响音源精细程度。</em></p></blockquote>
<h6></h6>
<h6>制作音源（开始编程）</h6>
<p>介绍完了前四个按钮，就只剩最后一个按钮了，<strong>Script Editor（脚本编辑器）</strong></p>
<p>点开什么也没有，灰色的一个条，点这个灰条左下角的Edit打开编辑窗口</p>
<p><img class="alignnone size-full wp-image-3289" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/12345.jpg" alt="" width="1244" height="278" /></p>
<p>我们就在这个白框里写KSP脚本，写好点击右上角Apply应用脚本</p>
<p><img class="alignnone size-full wp-image-3290" src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-12-at-2.32.45-PM.png" alt="" width="1222" height="808" /></p>
<p>&nbsp;</p>
<h5><strong>-&gt; 认识KSP脚本</strong></h5>
<p>&nbsp;</p>
<p>接下来我们一起认识一下KSP脚本语言</p>
<p>&nbsp;</p>
<h6><strong>变量</strong></h6>
<div class="codecolorer-container python solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: black;">&#123;</span>这是一条注释<span style="color: black;">&#125;</span><br />
<br />
<span style="color: black;">&#123;</span>数值变量<span style="color: black;">&#125;</span><br />
declare $x :<span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1</span>                      <br />
<br />
<span style="color: black;">&#123;</span>数值数组变量<span style="color: black;">&#125;</span><br />
declare %myArr<span style="color: black;">&#91;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span>            <br />
<br />
%myArr<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span> :<span style="color: #66cc66;">=</span> <span style="color: #ff4500;">7</span><br />
%myArr<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> :<span style="color: #66cc66;">=</span> -<span style="color: #ff4500;">10</span>               </div></td></tr></tbody></table></div>
<div class="gdlr-code-item ">
<div class="gdlr-code-title"><i class="icon-plus"></i>点此查看更多变量</div>
<div class="gdlr-code-content">
<p>@myText &#8211; 字符串变量<br />
!myArray[] &#8211; 字符串数组<br />
const $myVariable &#8211; 数值常量<br />
polyphonic $i &#8211; 也是数值变量。不同的是如果写在on note 里 多个音同时按下时 这个量对每一音都是独立的</p>
</div>
</div>
<p></br></p>
<h6><strong>界面组件</strong></h6>
<p>界面组件声明后会立即出现在界面上。<br />
&nbsp;</p>
<div class="codecolorer-container ruby solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color:#006600; font-weight:bold;">&#123;</span>旋钮：<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">0</span>,<span style="color:#006666;">100</span>,<span style="color:#006666;">1</span><span style="color:#006600; font-weight:bold;">&#41;</span>的意思是取值<span style="color:#006666;">0</span>到<span style="color:#006666;">100</span>，每次移动<span style="color:#006666;">1</span>个单位。这里只是举个例子，可以自由调整<span style="color:#006600; font-weight:bold;">&#125;</span><br />
declare ui_knob <span style="color:#ff6633; font-weight:bold;">$mySlider</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">0</span>,<span style="color:#006666;">100</span>,<span style="color:#006666;">1</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
<br />
<span style="color:#006600; font-weight:bold;">&#123;</span>按钮：有按下和没按下的两种状态，可以直接用$myParam :=<span style="color:#006666;">1</span>设置它为按下的状态 <span style="color:#006600; font-weight:bold;">&#125;</span><br />
declare ui_button <span style="color:#ff6633; font-weight:bold;">$myParam</span>;</div></td></tr></tbody></table></div>
<div class="gdlr-code-item ">
<div class="gdlr-code-title"><i class="icon-plus"></i>点此查看更多组件</div>
<div class="gdlr-code-content">
ui_slider &#8211; 推子<br />
ui_label &#8211; 纯文字<br />
ui_menu &#8211; 下拉菜单<br />
ui_switch &#8211; 切换开关(还是个按钮)<br />
ui_table &#8211; 一个步进器 可以画力度、ARP之类的<br />
ui_file_selector &#8211; 加载文件用的<br />
ui_level_meter &#8211; 显示音量的电平表<br />
ui_text_edit &#8211; 可输入文字的文本框<br />
ui_value_edit &#8211; 可输入数值的数值框<br />
ui_waveform &#8211; 波形显示器
</div>
</div>
<p></br></p>
<h6><strong>回调方法</strong></h6>
<p><em>我们在 ‘<a href="http://www.zhangxinhao.com/blog/3055" rel="noopener" target="_blank">音频开发技术（三）</a>’里已经提到过，回调方法是框架让你写东西的地方，不同的回调会在不同的条件下被框架执行，你把功能写在里面，就可以在特定条件下执行你写在里面的功能。</em></p>
<h6><strong>KSP中所有代码必须写在回调方法里，外部没有写代码的地方</strong></h6>
<div class="codecolorer-container ruby solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">on init<br />
<span style="color:#006600; font-weight:bold;">&#123;</span>这里的代码在初始化时执行。你可以把初始化和构造方法理解为这个软件一打开就执行的代码<span style="color:#006600; font-weight:bold;">&#125;</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span> on<br />
<br />
<br />
on note<br />
<span style="color:#006600; font-weight:bold;">&#123;</span>这里的代码在有MIDI音符被按下时执行，类似游戏引擎中的KeyDown<span style="color:#006600; font-weight:bold;">&#125;</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span> on<br />
<br />
<br />
on release<br />
<span style="color:#006600; font-weight:bold;">&#123;</span>这里的代码在有MIDI音符被抬起时执行，类似游戏引擎的KeyUp<span style="color:#006600; font-weight:bold;">&#125;</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span> on<br />
<br />
<br />
on ui_control<br />
<span style="color:#006600; font-weight:bold;">&#123;</span>这里的代码在界面组件和用户交互时（拖动了推子，点了按钮等）执行<span style="color:#006600; font-weight:bold;">&#125;</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span> on</div></td></tr></tbody></table></div>
<p></br></p>
<h6><strong>内置变量</strong></h6>
<p>内置变量就是可以直接使用的变量，是系统定义并赋值的，我们通过它们从系统获取信息，比如当前哪个键被按着<br />
</br><br />
了解内置变量前我们先了解一下MIDI，每次接收到MIDI信号都会触发on note回调函数，而每个MIDI信号被当成一个事件EVENT处理，每个事件都有自己的事件id，note number(哪一个键)和note velocity（力度），后两者都是0-127的数值。</p>
<div class="codecolorer-container lua solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="lua codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #66cc66;">&#123;</span>当前MIDI事件是哪个键被按下，返回<span style="color: #cc66cc;">0</span><span style="color: #66cc66;">-</span><span style="color: #cc66cc;">127</span>的数值<span style="color: #66cc66;">,</span>多用在on note里<span style="color: #66cc66;">&#125;</span><br />
$EVENT_NOTE<br />
<br />
<span style="color: #66cc66;">&#123;</span>当前MIDI事件按下的键多少力度，返回<span style="color: #cc66cc;">0</span><span style="color: #66cc66;">-</span><span style="color: #cc66cc;">127</span>的数值<span style="color: #66cc66;">,</span>多用在on note里<span style="color: #66cc66;">&#125;</span><br />
$EVENT_VELOCITY<br />
<br />
<span style="color: #66cc66;">&#123;</span>（常用）用来给set<span style="color: #66cc66;">/</span>get_engine_par接口指明调整<span style="color: #66cc66;">/</span>获取什么地方的参数 具体参数多是从KSP官方参考手册上查阅得来<span style="color: #66cc66;">&#125;</span><br />
$ENGINE_PAR_相应功能</div></td></tr></tbody></table></div>
<div class="gdlr-code-item ">
<div class="gdlr-code-title"><i class="icon-plus"></i>点此查看更多内置变量</div>
<div class="gdlr-code-content">
$EVENT_ID &#8211; 当前MIDI事件的ID，一些设计中会用到,多用在on note里<br />
$PLAYED_VOICES_INST &#8211; 有多少个键在被按下<br />
$NOTE_HELD &#8211; 音符正在被按着就是1，没被按着就是0<br />
$ALL_GROUPS &#8211; 表示操作全部组，放在接口参数里用来操作全部的组
</div>
</div>
<p></br></p>
<h6><strong>功能接口</strong></h6>
<div class="codecolorer-container lua solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br /></div></td><td><div class="lua codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #66cc66;">&#123;</span>设置界面高度为几个格子<span style="color: #66cc66;">&#125;</span><br />
set_ui_height<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">4</span><span style="color: #66cc66;">&#41;</span><br />
<br />
<span style="color: #66cc66;">&#123;</span>把界面组件放到指定格子的位置<span style="color: #66cc66;">&#125;</span><br />
move_control<span style="color: #66cc66;">&#40;</span>界面组件<span style="color: #66cc66;">,</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span><br />
<br />
<span style="color: #66cc66;">&#123;</span>在主音色窗口显示我们写的界面组件。写代码时预览窗会显示但回到主音色窗口就不显示，需要加这句<span style="color: #66cc66;">&#125;</span><br />
make_perfview<br />
<br />
<span style="color: #66cc66;">&#123;</span>输出信息到Kontakt最下面的状态栏 一般用来Debug<span style="color: #66cc66;">&#125;</span><br />
message<span style="color: #66cc66;">&#40;</span><span style="color: #ff6666;">&quot;输出信息&quot;</span><span style="color: #66cc66;">&#41;</span><br />
<br />
<span style="color: #66cc66;">&#123;</span>设置旋钮显示的单位<span style="color: #66cc66;">&#125;</span><br />
set_knob_unit<span style="color: #66cc66;">&#40;</span>界面组件，表示单位类型的内置变量<span style="color: #66cc66;">&#41;</span> <br />
<br />
<span style="color: #66cc66;">&#123;</span>设置旋钮默认的值<span style="color: #66cc66;">&#125;</span><br />
set_knob_defval<span style="color: #66cc66;">&#40;</span>界面组件<span style="color: #66cc66;">,</span> 默认的值<span style="color: #66cc66;">&#41;</span> <br />
<br />
<span style="color: #66cc66;">&#123;</span>让kontakt自动保存和载入这个组件或变量的值<span style="color: #66cc66;">&#125;</span><br />
make_persistent<span style="color: #66cc66;">&#40;</span>界面组件<span style="color: #66cc66;">/</span>变量<span style="color: #66cc66;">&#41;</span><br />
<br />
<span style="color: #66cc66;">&#123;</span>设定指定的系统参数<span style="color: #66cc66;">&#125;</span><br />
set_engine_par<span style="color: #66cc66;">&#40;</span>表示要调整的地方的内置变量，数值，作用于第几个Group，第几个效果器，哪个效果条<span style="color: #66cc66;">&#41;</span><br />
<br />
<span style="color: #66cc66;">&#123;</span>获取指定的系统参数<span style="color: #66cc66;">&#125;</span><br />
get_engine_par<span style="color: #66cc66;">&#40;</span>表示要获取的地方的内置变量，作用于第几个Group，第几个效果器，哪个效果条<span style="color: #66cc66;">&#41;</span></div></td></tr></tbody></table></div>
<div class="gdlr-code-item ">
<div class="gdlr-code-title"><i class="icon-plus"></i>点此查看更多功能接口</div>
<div class="gdlr-code-content">
<p>set_key_color(按键MIDI编号，颜色) &#8211; 设置一个MIDI按键的颜色</p>
<p>play_note(哪个键，力度，样本偏移，持续多少毫秒) &#8211; 播放一个按键映射的采样，多用在on note里<br />
ignore_event($EVENT_ID) &#8211; 无视当前MIDI事件，即按下去不发声，多用在on note里，之后常用play_note重定向</p>
<p>_get_engine_par_disp(表示要获取的地方的内置变量，作用于第几个Group，第几个效果器，哪个效果条) &#8211; 获取系统显示的参数</p>
<p>disallow_group(1) &#8211; 禁用或mute一个组，如果是全部组可用$ALL_GROUPS<br />
allow_group(0) &#8211; 激活一个组</p>
<p>set_script_title(&quot;标题&quot;) &#8211; 设置代码编辑窗口的标题<br />
set_ui_height_px(200) &#8211; 用像素设置界面高度<br />
set_text(组件,新名) &#8211; 改显示名<br />
set_knob_label() &#8211; 为旋钮设置显示内容</p>
<p>inc($myValue) &#8211; 自加，等同于$myValue = $myValue + 1<br />
dec($myValue)) &#8211; 自减，等同于$myValue = $myValue &#8211; 1</p>
<p>wait(1000000) &#8211; 等待多少微秒，一秒等于1,000,000微秒</p>
<p>change_note($EVENT_ID, $EVENT_NOTE + 12) &#8211; 改变音高 本例中提高八度<br />
change_velo($EVENT_ID, $EVENT_VELOCITY / 2) &#8211; 改变力度 本例中力度减半<br />
change_pan($EVENT_ID, -1000, 0) &#8211; 移动摆位 本例中极左摆位<br />
change_vol($EVENT_ID, -5000, 0) &#8211; 改变MIDI音量 本例中减少5db<br />
change_tune($EVENT_ID, 50000, 0) &#8211; 改变音高偏移 本例中音高偏移50个cents</p>
</div>
</div>
<p></br><br />
<strong>-> 格子</strong><br />
kontakt 的界面规格通常是由‘格子’来衡量的，而不是像素<br />
<em>来自 Toby Pitman 的图，演示了 Kontakt 的 ‘格子’，图中格子的 x, y 颠倒了，比如 1，2 那个位置的格子实际是 2，1</em><br />
<img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/gird.jpg" alt="" width="631" height="412" class="alignnone size-full wp-image-3360" /></p>
<p><strong>-> 哪个效果条</strong> </br><em>set_engine_par 和 get_engine_par 中最后一个参数的代表的不同效果条对应的值 Group:-1 Inseret:1 Send:0</em><br />
<img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/pos2.jpg" alt="" width="1268" height="888" class="alignnone size-full wp-image-3395" /><br />
</br></p>
<h6><strong>流程控制</strong></h6>
<p>KSP中用来判断用的是&#8217;=&#8217;，用来赋值的是&#8217;:=&#8217;。</p>
<div class="codecolorer-container lua solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br /></div></td><td><div class="lua codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">on note<br />
<br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#123;</span> &nbsp;<span style="color: #aa9900; font-weight: bold;">if</span> &nbsp;<span style="color: #66cc66;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #aa9900; font-weight: bold;">if</span><span style="color: #66cc66;">&#40;</span>$EVENT_VELOCITY<span style="color: #66cc66;">&gt;</span><span style="color: #cc66cc;">100</span><span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; message<span style="color: #66cc66;">&#40;</span><span style="color: #ff6666;">&quot;力度大于100&quot;</span><span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #aa9900; font-weight: bold;">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; message<span style="color: #66cc66;">&#40;</span><span style="color: #ff6666;">&quot;力度小于100&quot;</span><span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #aa9900; font-weight: bold;">end</span> <span style="color: #aa9900; font-weight: bold;">if</span><br />
<br />
<br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#123;</span> &nbsp;<span style="color: #aa9900; font-weight: bold;">while</span> &nbsp;<span style="color: #66cc66;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #aa9900; font-weight: bold;">while</span><span style="color: #66cc66;">&#40;</span>$NOTE_HELD <span style="color: #66cc66;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; message<span style="color: #66cc66;">&#40;</span><span style="color: #ff6666;">&quot;MIDI按键正在被按着&quot;</span><span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #aa9900; font-weight: bold;">end</span> <span style="color: #aa9900; font-weight: bold;">while</span><br />
<br />
<span style="color: #aa9900; font-weight: bold;">end</span> on</div></td></tr></tbody></table></div>
<div class="gdlr-code-item ">
<div class="gdlr-code-title"><i class="icon-plus"></i>点此查看更多流程控制</div>
<div class="gdlr-code-content">
    {  select  }<br />
    select($EVENT_NOTE)<br />
        case 60<br />
        message(&quot;按了C3&quot;)<br />
        case 62<br />
        message(&quot;按了D3&quot;)<br />
    end select
</div>
</div>
<p></br></p>
<h6><strong>查阅文档</strong></h6>
<p>真实开发中，我们需要一个字典一样的手册用来参考。<br />
点此下载 <a href="https://pan.baidu.com/s/1wH-aF-rwGhAnzG4k7ItWnw" target="_blank" rel="noopener">Kontakt Script 官方参考手册</a> 提取码: 8aqr<br />
<em>（若你所在的区域无法使用百度网盘，<a href="https://www.native-instruments.com/fileadmin/ni_media/downloads/manuals/kontakt/KONTAKT_620_KSP_Reference_Manual.pdf" rel="noopener" target="_blank">点击这里查看NI官网版本</a>）</em><br />
这手册像字典，不是用来看的，而是用来查的<br />
下载下来，打开，然后按下快捷键 Ctrl + F (Mac是 command + F)<br />
输入你要找的，比如 set_key_color，回车，阅读它的用法和各种颜色的代码。</p>
<p></br></p>
<h5><strong>-> 开始写代码</strong></h5>
<p>我说过KSP所有代码必须写在回调方法里，外部没有写代码的地方，那我们先写一个回调：</p>
<div class="codecolorer-container lua solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br /></div></td><td><div class="lua codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">on init<br />
<span style="color: #aa9900; font-weight: bold;">end</span> on</div></td></tr></tbody></table></div>
<p>这个回调里是在音源被加载/打开时被 kontakt 执行的<br />
我们先用 make_perfview 打开音源显示界面组件的功能，然后用 set_ui_height() 调节一下界面高度</p>
<div class="codecolorer-container lua solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="lua codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">on init<br />
<br />
make_perfview<br />
set_ui_height<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">6</span><span style="color: #66cc66;">&#41;</span><br />
<br />
<span style="color: #aa9900; font-weight: bold;">end</span> on</div></td></tr></tbody></table></div>
<p>点击代码框右上角Apply提交<br />
<img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-13-at-9.32.37-PM.png" alt="" width="1160" height="474" class="alignnone size-full wp-image-3397" /><br />
再点扳手回到主界面看到，设置高度后背景显示出来了<br />
<img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-13-at-5.36.50-PM.png" alt="" width="1268" height="648" class="alignnone size-full wp-image-3370" /></p>
<h6><strong>界面</strong></h6>
<p>接着，我们定义一个旋钮，然后用 move_control 功能接口把它移动到 ‘1,3’ 位置的格子上<br />
</br><br />
有个细节，kontakt 不用小数，而是用整数，表示 0% 到 100% 的 0-1 对应在 kontakt 里是 0-1 000 000 。<br />
千分之称之为毫，千分之的千分之称为微，把 0-1 变成（0，1000000，1）这样的参数就达到了微分精度。<br />
<em> 201x 年左右，一些银行的金融系统处理小数运算是先乘 100 算完然后除 100，这和编程语言的特性有关。kontakt 这么做可能是同样原因。</em></p>
<div class="codecolorer-container lua solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="lua codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">on init<br />
<br />
<span style="color: #66cc66;">...</span><br />
<br />
declare ui_knob $RevVol <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">1000000</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span><br />
move_control <span style="color: #66cc66;">&#40;</span>$RevVol<span style="color: #66cc66;">,</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">3</span><span style="color: #66cc66;">&#41;</span><br />
<br />
<span style="color: #aa9900; font-weight: bold;">end</span> on</div></td></tr></tbody></table></div>
<p>运行，出现了一个旋钮</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-13-at-6.21.17-PM.png" alt="" width="514" height="410" class="alignnone size-full wp-image-3374" /></p>
<p>同样地，定义四个旋钮</p>
<div class="codecolorer-container lua solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br /></div></td><td><div class="lua codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">on init<br />
<br />
<span style="color: #66cc66;">...</span><br />
<br />
declare ui_knob $RevVol <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">1000000</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span><br />
move_control <span style="color: #66cc66;">&#40;</span>$RevVol<span style="color: #66cc66;">,</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">3</span><span style="color: #66cc66;">&#41;</span><br />
<br />
declare ui_knob $RevTime <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">1000000</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span><br />
move_control <span style="color: #66cc66;">&#40;</span>$RevTime<span style="color: #66cc66;">,</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">5</span><span style="color: #66cc66;">&#41;</span><br />
<br />
declare ui_knob $DelayVol <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">1000000</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span><br />
move_control <span style="color: #66cc66;">&#40;</span>$DelayVol<span style="color: #66cc66;">,</span><span style="color: #cc66cc;">2</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">3</span><span style="color: #66cc66;">&#41;</span><br />
<br />
declare ui_knob $DelTime <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">1000000</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span><br />
move_control <span style="color: #66cc66;">&#40;</span>$DelTime<span style="color: #66cc66;">,</span><span style="color: #cc66cc;">2</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">5</span><span style="color: #66cc66;">&#41;</span><br />
<br />
<span style="color: #aa9900; font-weight: bold;">end</span> on</div></td></tr></tbody></table></div>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-13-at-6.25.03-PM.png" alt="" width="606" height="518" class="alignnone size-full wp-image-3375" /></p>
<p>我们看到，这四个旋钮下方的数值都没有单位，用 set_knob_unit 功能接口为它们加上单位。<br />
这接口怎么用呢，文档里搜一下，找到 $KNOB_UNIT_DB 和 $KNOB_UNIT_MS 参数 是我们需要的。</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-13-at-6.47.04-PM.png" alt="" width="1034" height="800" class="alignnone size-full wp-image-3377" /></p>
<div class="codecolorer-container lua solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></div></td><td><div class="lua codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">on init<br />
<br />
<span style="color: #66cc66;">...</span><br />
<br />
set_knob_unit <span style="color: #66cc66;">&#40;</span>$RevVol<span style="color: #66cc66;">,</span>$KNOB_UNIT_DB<span style="color: #66cc66;">&#41;</span><br />
set_knob_unit <span style="color: #66cc66;">&#40;</span>$DelayVol<span style="color: #66cc66;">,</span>$KNOB_UNIT_DB<span style="color: #66cc66;">&#41;</span><br />
<br />
set_knob_unit <span style="color: #66cc66;">&#40;</span>$RevTime<span style="color: #66cc66;">,</span>$KNOB_UNIT_HZ<span style="color: #66cc66;">&#41;</span><br />
set_knob_unit <span style="color: #66cc66;">&#40;</span>$DelTime<span style="color: #66cc66;">,</span>$KNOB_UNIT_HZ<span style="color: #66cc66;">&#41;</span><br />
<br />
<br />
<span style="color: #aa9900; font-weight: bold;">end</span> on</div></td></tr></tbody></table></div>
<p>好了，现在就显示单位了</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-13-at-6.49.34-PM.png" alt="" width="572" height="400" class="alignnone size-full wp-image-3379" /></p>
<p>接下来我希望让 kontakt 保存这些旋钮，否则当用户关闭再打开这个工程时，这些旋钮全部会自动清零，无法保存在工程中。使用 make_persistent() 的功能接口，可以让某个组件被自动保存在工程中 <em>(在编程中，这个步骤叫做 数据持久化)</em></p>
<div class="codecolorer-container lua solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br /></div></td><td><div class="lua codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">on init<br />
<br />
<span style="color: #66cc66;">...</span><br />
<br />
make_persistent<span style="color: #66cc66;">&#40;</span>$RevVol<span style="color: #66cc66;">&#41;</span><br />
make_persistent<span style="color: #66cc66;">&#40;</span>$DelayVol<span style="color: #66cc66;">&#41;</span><br />
<br />
make_persistent<span style="color: #66cc66;">&#40;</span>$RevTime<span style="color: #66cc66;">&#41;</span><br />
make_persistent<span style="color: #66cc66;">&#40;</span>$DelTime<span style="color: #66cc66;">&#41;</span><br />
<br />
<span style="color: #aa9900; font-weight: bold;">end</span> on</div></td></tr></tbody></table></div>
<p>好了，现在我们定义了控制混响音量和时长的旋钮，以及控制延迟音量和时长的旋钮，接下来要实现混响和延迟的功能。</p>
<h6><strong>Kontakt Script 实现音频效果的方式主要是 -> 挂上kontakt内置的效果器 -> 用代码控制内置效果器参数</strong></h6>
<p>我们先挂上效果器吧，有三个位置可以挂，Group, Insert, Send。自己根据需求挂不同地方，这里我把效果挂在 Insert 里。挂在不同的位置会影响到后面使用 set_engine_par 和 get_engine_par 的最后一个参数的不同。</p>
<p><em>set_engine_par 和 get_engine_par 中最后一个参数的代表的不同效果条对应的值 Group:-1 Inseret:1 Send:0</em><br />
<img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/pos2.jpg" alt="" width="1268" height="888" class="alignnone size-full wp-image-3395" /><br />
</br><br />
我们来到InsertEffects标签页，点第一个效果框右下角的加号，挂上一个 Delay</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-13-at-7.22.55-PM.png" alt="" width="658" height="514" class="alignnone size-full wp-image-3385" /><br />
然后同理，在第二个效果框上挂一个 Reverb</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-13-at-7.23.12-PM.png" alt="" width="774" height="562" class="alignnone size-full wp-image-3386" /><br />
然后点击 Delay, 我们看一下，下面这些 Delay 的参数也就是在代码中用 get_engine_par 和 set_engine_par 交互到的参数。</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-13-at-7.23.33-PM.png" alt="" width="1264" height="376" class="alignnone size-full wp-image-3387" /><br />
Reverb也是同理。<br />
我们根据自己的混音经验预先调整好一些，然后选几个常用的让我们写的界面组件控制。</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-13-at-7.23.43-PM.png" alt="" width="1260" height="376" class="alignnone size-full wp-image-3388" /></p>
<h6><strong>用界面控制效果器</strong></h6>
<p>现在编写让界面组件和效果器的参数交互的代码。</p>
<p>那么，要把代码写在什么地方呢？我之前说过，ksp 的代码只能写在回调方法里，之前的代码都是写在 on init 回调里的，这个回调只在一开始打开 kontakt 时执行。<br />
如果要让一段代码在每次旋钮转动时就设定效果器的参数，那显然不能写在 on init 里。因为 on init 里的代码只在音源一打开的时候执行一次，之后就不再执行了。<br />
细心的同学应该看到，在上面的‘ -> 认识KSP脚本 的 回调方法 里’，还有 on ui_control 这个回调，它在界面组件和用户发生交互时执行，那就把代码写在这个回调里。</p>
<div class="codecolorer-container lua solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br /></div></td><td><div class="lua codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">on ui_control<span style="color: #66cc66;">&#40;</span>$RevVol<span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; set_engine_par<span style="color: #66cc66;">&#40;</span>$ENGINE_PAR_SEND_EFFECT_OUTPUT_GAIN<span style="color: #66cc66;">,</span> $RevVol<span style="color: #66cc66;">,</span> <span style="color: #66cc66;">-</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #aa9900; font-weight: bold;">end</span> on</div></td></tr></tbody></table></div>
<p>首先，我们用 on ui_control() 后面的括号指定了是当 $RevVol 这个旋钮转动时才执行它里面的代码</p>
<p>然后我们用了 </p>
<h6><strong>set_engine_par</strong></h6>
<p> 来看一下这个接口的参数：<br />
</br><br />
  1.第一个参数是指定设置系统哪一种参数，这里的 ‘$ENGINE_PAR_SEND_EFFECT_OUTPUT_GAIN’ 它告诉 kontakt，我要控制的是效果器 wet 量，也就是效果器的效果音的成分。</p>
<p>  2.第二个参数，就是指把要设置的系统参数改成什么值，同样也是 0-1000000 的范围，这个范围在 kontakt 里代表 0% 到 100%。这里我们直接把旋钮扭到的值赋给 wet 量，也就是效果音的量。（这就之前为什么把旋钮的取值设定为从0-1000000 : <em>declare ui_knob $RevVol (0,1000000,1)</em>）</p>
<p>  3.第三个参数为操作哪一个组，0代表第一个组，1代表第二个组，以此类推。这里我们的效果器是放在 Insert 里的，它作用于全局，不属于任何一个组，所以这里填上 -1。</p>
<p>  4.第四个参数就是第几个效果块，英文管这叫slot中文是插槽的意思。看一下上面那张图，在 InsertEffects 标签页中，我们之在第一个插槽上挂的是Delay，第二个插槽上挂的Reverb。所以Reverb在第二个，那这里就写1。（0 代表第一个，1 代表第二个）</p>
<p>  5.最后一个参数就是指在哪个效果条（标签页）里了，下面这张图在本文是第三次出现了。我是把效果器挂在InsertEffect标签页里的，这个标签页对应的的是1。这里就写1。</p>
<p><em>set_engine_par 和 get_engine_par 中最后一个参数的代表的不同效果条标签页所对应的值 Group: -1 Inseret: 1 Send: 0</em><br />
<img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/pos2.jpg" alt="" width="1268" height="888" class="alignnone size-full wp-image-3395" /><br />
</br></p>
<p>好，以此类推，我们再连接第二个旋钮</p>
<div class="codecolorer-container lua solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br /></div></td><td><div class="lua codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">on ui_control<span style="color: #66cc66;">&#40;</span>$RevTime<span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; set_engine_par<span style="color: #66cc66;">&#40;</span>$ENGINE_PAR_RV2_TIME<span style="color: #66cc66;">,</span> $RevTime<span style="color: #66cc66;">,</span> <span style="color: #66cc66;">-</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #aa9900; font-weight: bold;">end</span> on</div></td></tr></tbody></table></div>
<p>和第一个按钮的代码一样，只是把参数换成了 $ENGINE_PAR_RV2_TIME，这是我在操作手册中查到对应混响时间的参数。</p>
<p>接着连接控制Delay的两个旋钮。</p>
<div class="codecolorer-container lua solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="lua codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">on ui_control<span style="color: #66cc66;">&#40;</span>$DelayVol<span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; set_engine_par<span style="color: #66cc66;">&#40;</span>$ENGINE_PAR_SEND_EFFECT_OUTPUT_GAIN<span style="color: #66cc66;">,</span> $DelayVol<span style="color: #66cc66;">,</span> <span style="color: #66cc66;">-</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #aa9900; font-weight: bold;">end</span> on<br />
<br />
on ui_control<span style="color: #66cc66;">&#40;</span>$DelTime<span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; set_engine_par<span style="color: #66cc66;">&#40;</span>$ENGINE_PAR_RDL_TIME<span style="color: #66cc66;">,</span> $DelTime<span style="color: #66cc66;">,</span> <span style="color: #66cc66;">-</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #aa9900; font-weight: bold;">end</span> on</div></td></tr></tbody></table></div>
<p>试一下，起效果了！</p>
<p></br></p>
<h6><strong>显示数值</strong></h6>
<p>等等，我们发现旋钮下方显示的值不太对，显示的是 0 &#8211; 1000000 的值，之前提到过，这个值在 kontakt 里 代表 0% 到 100%。 </p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-14-at-1.01.13-AM.png" alt="" width="196" height="116" class="alignnone size-full wp-image-3425" /></p>
<p>但是在 InsertEffects 里 Reverb 参数中的显示却是正确的。</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-14-at-1.03.55-AM.png" alt="" width="253" height="139" class="alignnone size-full wp-image-3426" /></p>
<p>于是我想把这里显示的值拿到旋钮下面显示，就用到这个接口：_get_engine_par_disp，它是获取系统参数显示出来的值，而不是对应 kontakt 的 0% 到 100% 的 0-1000000 的微分值。<br />
获取到以后 用 set_knob_label 放到旋钮上显示</p>
<div class="codecolorer-container lua solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br /></div></td><td><div class="lua codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">on ui_control<span style="color: #66cc66;">&#40;</span>$RevVol<span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; set_knob_label<span style="color: #66cc66;">&#40;</span>$RevVol<span style="color: #66cc66;">,</span> _get_engine_par_disp<span style="color: #66cc66;">&#40;</span>$ENGINE_PAR_SEND_EFFECT_OUTPUT_GAIN<span style="color: #66cc66;">,-</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #aa9900; font-weight: bold;">end</span> on</div></td></tr></tbody></table></div>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-14-at-1.44.22-AM.png" alt="" width="194" height="86" class="alignnone size-full wp-image-3433" /></p>
<p>如此类推，应用到四个旋钮上，界面就全部搞定了。</p>
<p><em><br />
练习：<br />
已知如下接口可以设置效果器的旁通 bypass<br />
set_engine_par($ENGINE_PAR_SEND_EFFECT_BYPASS, 0, -1, 1或0, 1) ：关<br />
set_engine_par($ENGINE_PAR_SEND_EFFECT_BYPASS, 1, -1, 1或0, 1) ：开<br />
你能否设计两个按钮来控制 reverb 和 delay 的旁通效果？</p>
<p>(答案见源码)<br />
</em> </p>
<p></br></p>
<h6><strong>键盘色彩</strong></h6>
<p>我听了一下这个呼吸包，发现里面有一些呼吸声比较甜，还有一些则像是吸面条般的声音，我不知道是用在哪的。<br />
然后我想把比较甜的声音标记出来，在键盘上面，把它们的位置标红。</p>
<p>这里用到 set_key_color 接口，打开手册查一下它</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-14-at-1.18.32-AM.png" alt="" width="768" height="1356" class="alignnone size-full wp-image-3427" /></p>
<p>根据这些参数。我设置了一下整体键盘的色彩，之前在Ksp中更多功能接口里写了，inc($x) 是 $x 自加的意思 $x = $x + 1</p>
<div class="codecolorer-container lua solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br /></div></td><td><div class="lua codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">on init<br />
<span style="color: #66cc66;">...</span><br />
declare $keys<br />
set_key_color<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">36</span><span style="color: #66cc66;">,</span> $KEY_COLOR_RED<span style="color: #66cc66;">&#41;</span><br />
set_key_color<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">38</span><span style="color: #66cc66;">,</span> $KEY_COLOR_MAGENTA<span style="color: #66cc66;">&#41;</span><br />
$keys <span style="color: #66cc66;">:=</span> <span style="color: #cc66cc;">40</span><br />
<span style="color: #aa9900; font-weight: bold;">while</span> <span style="color: #66cc66;">&#40;</span>$keys<span style="color: #66cc66;">&lt;</span><span style="color: #cc66cc;">52</span><span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; set_key_color<span style="color: #66cc66;">&#40;</span>$keys<span style="color: #66cc66;">,</span> $KEY_COLOR_NONE<span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; inc<span style="color: #66cc66;">&#40;</span>$keys<span style="color: #66cc66;">&#41;</span><br />
<span style="color: #aa9900; font-weight: bold;">end</span> <span style="color: #aa9900; font-weight: bold;">while</span><br />
<br />
set_key_color<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">52</span><span style="color: #66cc66;">,</span> $KEY_COLOR_RED<span style="color: #66cc66;">&#41;</span><br />
set_key_color<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">53</span><span style="color: #66cc66;">,</span> $KEY_COLOR_MAGENTA<span style="color: #66cc66;">&#41;</span><br />
$keys <span style="color: #66cc66;">:=</span> <span style="color: #cc66cc;">54</span><br />
<span style="color: #aa9900; font-weight: bold;">while</span> <span style="color: #66cc66;">&#40;</span>$keys<span style="color: #66cc66;">&lt;</span><span style="color: #cc66cc;">72</span><span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; set_key_color<span style="color: #66cc66;">&#40;</span>$keys<span style="color: #66cc66;">,</span> $KEY_COLOR_GREEN<span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; inc<span style="color: #66cc66;">&#40;</span>$keys<span style="color: #66cc66;">&#41;</span><br />
<span style="color: #aa9900; font-weight: bold;">end</span> <span style="color: #aa9900; font-weight: bold;">while</span><br />
<br />
set_key_color<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">72</span><span style="color: #66cc66;">,</span> $KEY_COLOR_RED<span style="color: #66cc66;">&#41;</span><br />
set_key_color<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">74</span><span style="color: #66cc66;">,</span> $KEY_COLOR_MAGENTA<span style="color: #66cc66;">&#41;</span><br />
$keys <span style="color: #66cc66;">:=</span> <span style="color: #cc66cc;">75</span><br />
<span style="color: #aa9900; font-weight: bold;">while</span> <span style="color: #66cc66;">&#40;</span>$keys<span style="color: #66cc66;">&lt;</span><span style="color: #cc66cc;">92</span><span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; set_key_color<span style="color: #66cc66;">&#40;</span>$keys<span style="color: #66cc66;">,</span> $KEY_COLOR_CYAN<span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; inc<span style="color: #66cc66;">&#40;</span>$keys<span style="color: #66cc66;">&#41;</span><br />
<span style="color: #aa9900; font-weight: bold;">end</span> <span style="color: #aa9900; font-weight: bold;">while</span><br />
<span style="color: #aa9900; font-weight: bold;">end</span> on</div></td></tr></tbody></table></div>
<p>Apply后，得到这样的效果</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-14-at-1.21.20-AM.png" alt="" width="766" height="150" class="alignnone size-full wp-image-3428" /></p>
<p>到这我们的音源就完成了。</p>
<p></br></p>
<h5><strong>扩展阅读</strong></h5>
<p></br></p>
<h6>-> 如何录制多个Group 实现多套映射</h6>
<p>我们之前在介绍 Group Editor 的时候提到过，多个 Group 可以实现音色切换、合成多个摆位的麦克风等功能。<br />
这都是非常实用的功能，我们来看看是怎么做的。</p>
<p>1.先打开 Group Editor, 然后点击 Create Empty Group</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/group0.jpg" alt="" width="1260" height="1044" class="alignnone size-full wp-image-3403" /><br />
&nbsp;</p>
<p>2.选中新的 Group，双击可以重命名。</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-13-at-9.59.49-PM.png" alt="" width="1268" height="324" class="alignnone size-full wp-image-3411" /></p>
<p>3.打开 Mapping Editor，先取消勾选 &#8216;AutoSel. Grp'(是默认选中的)，然后勾选 &#8216;Selected Groups only&#8217;。</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Group1.jpg" alt="" width="1232" height="1048" class="alignnone size-full wp-image-3404" /></p>
<p>现在映射窗口里就是新的组了。<br />
<em>点击 Group1 再点新创建的 Group, 就看见映射窗的内容不同了（如果做过映射）。</em></p>
<p></br></p>
<h6>-> Wave Editor 怎么用</h6>
<p>同样地，之前在介绍 Wave Editor 时，我提到过，这个编辑器可以实现让一段不持续的音无限持续延长的功能。<br />
现代作品中，这个技术在弦乐和人声比较常见，我们来看一下具体怎么做。</p>
<p>1.先把其他Editor关了，就打开 Mapping Editor 和 Wave Editor 两个窗口。</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/wave.jpg" alt="" width="1266" height="200" class="alignnone size-full wp-image-3409" /></p>
<p>2.在Mapping Editor 映射窗里中选中一个音频块，然后就在Wave Editor里看到它了。<br />
接下来开启 Sample Loop 的开关，然后就出现了设置Loop范围的黄色的区域，接下来拖动黄色区域调整Loop的范围就行了。</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/wave3.jpg" alt="" width="1250" height="950" class="alignnone size-full wp-image-3410" /></p>
<h5><strong>工欲善其事，必先利其器</strong></h5>
<p>在 kontakt 的 Script Editor 里写代码，除了最后 Apply 时知道对错之外，中途就完全没有任何信息。<br />
选用一款合适的文本编辑器，可以大大提升我们的效率和体验。它可以像个助理一样告诉你代码的对错，提示你各种接口的用法，以及帮你自动输入变量和接口。<br />
我们可以在外界用文本编辑器写好代码，写完再放到 kontakt 的 Script Editor 里运行。</p>
<p>打开 <a href="https://www.sublimetext.com/" rel="noopener" target="_blank">Sublime Text官网</a> 下载对应你的系统的 Sublime Text -> 安装 -> 打开</p>
<p>然后在 Sublime Text 中 按下 Shift + Ctrl + P (Mac是 shift + command + P) 出现一个输入框，输入 install，选中这个 回车 （或点击它）</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/sl0.jpg" alt="" width="1286" height="1000" class="alignnone size-full wp-image-3405" /></p>
<p>等一会 出现这个界面，</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-13-at-8.12.32-PM.png" alt="" width="1290" height="1004" class="alignnone size-full wp-image-3414" /></p>
<p>点确定，然后再次按下 Shift + Ctrl + P，输入 install, 选择 Install Package<br />
等一会，就会出现了一个新的<strong>空的</strong>输入框，在新的输入框里输入 ksp，选这个，回车（或点击它）</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/sl21.jpg" alt="" width="1282" height="1002" class="alignnone size-full wp-image-3407" /></p>
<p>等一会弹出这个界面，整个就安装好了。</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-13-at-8.28.55-PM.png" alt="" width="1276" height="1006" class="alignnone size-full wp-image-3415" /></p>
<p>用的时候在右下角这里选上 KSP 类型</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/st3.jpg" alt="" width="488" height="396" class="alignnone size-full wp-image-3408" /></p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-13-at-8.29.30-PM.png" alt="" width="628" height="634" class="alignnone size-full wp-image-3416" /></p>
<p>就有代码提示和自动补全了</p>
<p><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/Screen-Shot-2020-06-13-at-8.34.24-PM.png" alt="" width="1418" height="1012" class="alignnone size-full wp-image-3417" /></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h5><strong>后记</strong></h5>
<p><em>一切技术在理解了以后都是简单的。如果我们觉得一个东西很厉害很高端，那只说明我们不够了解它。</em><br />
</br></p>
<p><em>WE CAN KEEP IT SIMPLE BABY, LETS NO MAKE IT COMPLICATED.<br />
LABELS ARE SO OVERRATED, LETS NO MAKE IT COMPLICATED.</em></p>
<div class="gdlr-shortcode-wrapper"><div class="gdlr-player-item-wrapper gdlr-item" ><div class="gdlr-player-item"><div class="gdlr-top-player"><div class="gdlr-top-player-inner"><div class="gdlr-top-player-thumbnail"><img src="http://www.zhangxinhao.com/wp-content/uploads/2020/06/cp489-150x150.jpg" alt="" width="96" height="96" /></div><div class="gdlr-top-player-content"><div class="gdlr-top-player-title">Complicated &#8211; Dimitri Vegas &#038; Like Mike / David Guetta / Kiiara</div><div class="gdlr-top-player-download"><a class="top-player-download gdlr-download" target="_blank" style="display: none;" ><img src="http://www.zhangxinhao.com/wp-content/themes/musicclub-v1-06/images/icon-download.png" alt="icon-download" /></a><a class="top-player-apple" target="_blank" style="display: none;" ><img src="http://www.zhangxinhao.com/wp-content/themes/musicclub-v1-06/images/icon-apple.png" alt="icon-download" /></a><a class="top-player-amazon" target="_blank" style="display: none;" ><img src="http://www.zhangxinhao.com/wp-content/themes/musicclub-v1-06/images/icon-amazon.png" alt="icon-download" /></a></div></div><div class="clear"></div></div><audio class="gdlr-audio-player" preload="auto" style="width: 100%; height: 50px;"><source type="audio/mpeg" src="http://music.163.com/song/media/outer/url?id=493283657.mp3 "></audio></div><ol class="gdlr-player-list"><li class="active" data-title="Complicated &#8211; Dimitri Vegas &#038; Like Mike / David Guetta / Kiiara" data-download="" data-apple="" data-amazon="" data-mp3="http://music.163.com/song/media/outer/url?id=493283657.mp3 " >1. Complicated &#8211; Dimitri Vegas &#038; Like Mike / David Guetta / Kiiara</li></ol><div class="clear"></div></div></div></div>
<p>&nbsp;</p>
<h5><a href="https://github.com/DASTUDIO/Tianyi_Breath_Kontakt6" target="_blank" rel="noopener">点击这里下载源码</a></h5>
<p><center></p>
<div class="gdlr-chart gdlr-ux" data-percent="60" data-size="155" data-linewidth="8" data-color="#a9e16e" data-bg-color="#e9e9e9" data-background="" >
<div class="chart-content-wrapper">
<div class="chart-content-inner"><span class="chart-content"  style="color: ;"  >课程进度</span><span class="chart-percent-number" style="color:#a9e16e;" >60%</span></div>
</div>
</div>
<p></center></p>
]]></content:encoded>
			</item>
	</channel>
</rss>
