1.dts解码器和dac解码器有什么不同?
2.基于stm32的PCM510X模块I2S接口调试总结
3.DAC of CLR(0)
dts解码器和dac解码器有什么不同?
DTS是“Digital Theatre System”的缩写,是“数字化影院系统”的意思,是一种用于**和音乐的高质量多音轨环绕声技术。DTS解码器就是对带有DTS格式音频进行解码还原所有声道声音信息。DAC解码器是Digital to Analog Converter-数模转换器,一种将[1]数字信号转换成模拟信号的装置。 DAC的云开发模板源码下载位数越高,信号失真就越小。声音也更清晰稳定。能不能接独立声卡取决于你的声卡,DTS解码器是电脑能给他数字源码即可,DAC只是把数字音频转换成能喇叭发声的模拟电声信号。两个功能不一样,童鞋你搞错了没有可比性。说个发烧友配置方向图给你参考就明白了,音频播放器(声卡输出)或者高端CD---DTS解码器(一般双解码的并且能支持后级给DAC输出功能)-----DAC解码器+前置放大器----后级放大器----分频器----喇叭
基于stm的PCMX模块I2S接口调试总结
一 前记
最近在项目实践中,我使用了PCMX DAC功放芯片。由于是初次接触,确实遇到了不少问题,花费了不少时间才解决,现将经验总结如下。
二 问题数理
在调试过程中,我发现数据每隔一段就会丢失。经过深入分析,发现原因是数据输入时出现了错误。实际上,这些数据被转换成了位,素材下载小程序源码因此长度应该是位,而不是8位字节。以下是正确的源代码:
2.数据丢失的具体情况如图所示:
分析后发现,数据丢失的原因是发送缓冲区长度设置过长。如果按照时钟FIFO模式发送,每帧的长度不宜过长,否则可能出现数据未发送完的情况。我设置的长度为时是可行的,但当设置为个short时,就出现了这个问题。
3.经过一系列的调试和尝试,我得到了以下结果:
正弦波输出非常完美,我终于得到了理想的结果。
DAC of CLR(0)
数据访问组件(Data Access Component,简称 DAC)是一个与 CLR(Common Language Runtime)一同发布的动态链接库(DLL),可以在 (core)clr.dll 目录下找到。在.NET Framework 中,其名称为 mscordacwks.dll,而在.NET Core 及后续版本中则更改为 mscordaccore.dll。DAC 主要提供有关 CLR 运行时的信息,比如查看已加载的 AppDomain(在.NET Core 及以后版本恒为 1 个),遍历加载的 Module、Heap(遍历)和 Stack(遍历)等。
值得注意的是,DAC 采用 out-of-process 方式运行,小程序源码加注释这意味着它不仅能够访问正在运行的进程(live process),还能访问调试器生成的崩溃转储文件,甚至在不同机器之间操作。
实际上,DAC 是实现 .NET 调试的基础。尽管我们更熟悉 CLR 调试 API,因为它们在 MSDN 上有完善的文档,但这些 API 实际上是基于 DAC 的底层实现。
网络上关于 DAC 的资料相对稀缺,无论是国内还是国外都如此。除了阅读源码之外,唯一比较系统化的文档只能在 coreclr/runtime 中找到,对于英语较好的读者,也可以直接查看原文: DAC Notes。
本文系列旨在结合源码的具体内容进行总结,补充文档和源码中可能令人困惑的部分,并填补中文文档的空白。
如何初始化 DACDAC 是随着 CLR 发布的,这隐含了两个关键信息:它主要用作调试工具;与 CLR 结构上紧密相连。
DAC 的 DLL 本身是 C-Style Exported 的,但不提供静态库和头文件(除非通过 CLR 源码)。因此,要使用 DAC,程序需要通过 LoadLibrary 加载 DLL 到内存中,然后通过 GetProcAddress 找到入口点。红米内核源码下载DAC 的典型入口点符号如下:
该函数返回值为 HRESULT,这是 Windows COM 的通用状态码。S_OK(0)表示成功;非 S_OK 的返回值则表示遇到了可接受的错误或严重的错误(Critical Error)。调用函数后务必检查返回值,只有返回 S_OK 才能正常工作。
参数包括 iid:需要获取的 COM 接口的 Guid,data_target:被调试目标的抽象表示(后面会详细展开),iface:用于接收 iid 对应 COM 接口实现的指针。这个函数遵循 COM 编程规范,因此,如果读者熟悉 COM,就很容易理解这个函数。
其中的 iid 取值范围较广,但真正具有泛用性的只有两个接口:IXCLRDataProcess 和 ISOSDacInterface。它们对应的 Guid 和具体函数表(以及其他可能的接口)可以在 runtime 仓库中找到:ISOSDac... 和 IXCLRDataProc...
入口点被调用后,DAC 完全初始化。之后,使用者可以通过上述提到的两个接口访问被调试对象的 CLR 信息。
ICLRDataTargetICLRDataTarget 是入口点函数第二个参数的类型。这意味着要调用入口点,必须传入一个 ICLRDataTarget 类型的实例。然而,ICLRDataTarget 实际上是一个接口,定义可以在以下链接中找到:ICLRDataTarget。
DAC 通过 ICLRDataTarget 要求调用者提供对目标的获取网页文字源码 IO 操作实现,例如,ReadVirtual 和 WriteVirtual。
如果将 ReadVirtual 实现为读取目标进程内存(ReadProcessMemory),那么 DAC 就在访问该进程的 CLR 信息;如果实现为对转储文件的读取,那么 DAC 访问的就是该文件;甚至,如果实现为从互联网或其他 IO 设备读取,那么 DAC 可以在更广泛的场景下工作。
例如,潜在的应用是远程监控或调试运行中的 .NET 程序,以便做出更灵活的决策。
简而言之,DAC 不关心真正的目标是谁,ICLRDataTarget 提供了对被调试目标的抽象,称为 Data Target。
由于 DAC 可能被用于调试文件或其他只读数据,所以 DAC 默认假设被调试目标的状态不变。这意味着,即使被调试的是进程,DAC 也默认调用者(而不是 DAC)会将该进程挂起。如果调用者未这样做,可能会出现数据过时的情况,因为 DAC 为了提高 IO 效率,会缓存此前读取过的数据,这基于被调试目标状态不变的假设。
当然,也可以强制让 DAC 放弃缓存并重新读取,这个操作通过 HRESULT IXCLRDataProcess.Flush() 完成。不过,频繁操作会使 DAC 的效率严重降低。
基于 DAC 对目标状态不变的假设,ICLRDataTarget 接口中的写入操作(如 WriteVirtual 和 SetThreadContext)声明实际上不会由 DAC 执行,因此,对这些函数也可以提供一个空的实现。
经过作者的大量测试,ICLRDataTarget 的实现无法通过 .NET 的通用 COM Interop 提供。因此,如果读者想在 C# 中使用 DAC,对 ICLRDataTarget 的实现必须通过人工构造 VTable 的方式。
ISOSDacInterface 和 IXCLRDataProcessISOSDacInterface 是 DAC 提供的接口之一,其名称中的 SOS 全称为 Son of Strike。关于 CLR 命名历史的详细信息,请参考这些链接中的回答:What the "EE" means in SOS? What's the story behind......
ISOSDacInterface 与 IXCLRDataProcess 提供的功能在侧重上有所不同。总体而言,前者提供更普遍、更广泛的信息,更接近 CLR 的实现细节。例如,通过 SOSDac(简称)我们可以遍历 Module 中所有 Type 相关的(mdToken 和对应 TypeHandle)的 Map 关系,访问具体的信息主要使用 TypeHandle、MethodDesc、FieldDesc 等 CLR 直接使用的数据。
相比之下,IXCLRDataProcess 本身提供的功能不多,但它衍生出一系列 API,这些 API 的共同点是全部以 IXCLRData 作为前缀,并且可以在定义 IXCLRDataProcess 的 .idl 文件中找到(上面已给出链接)。
这些 API 构成了数据抽象层(Data Abstraction Layer),它屏蔽了 CLR 的具体细节,不呈现任何从 CLR 获得的原始数据(Raw Data),转而使用标准 COM 规范构建了一整套类型系统来表示 CLR 的运行时状态。这套类型系统仅仅是一个包装,它的工作仍然依赖于 CLR 的细节。
除了 ISOSDacInterface 它本身外,还存在另外 9 个包含编号后缀的补充接口,从 ISOSDacInterface2 到 ISOSDacInterface。从它们中的任何一个,都可以通过调用 QueryInterface 获得其他 9 个。值得注意的是,根据文件中的定义本应还存在一个接口 ISOSDacInterface,但当前的源码并未提供该接口的实现。
IXCLRDataProcess 以及这系列的其他所有 API 与 .NET 的结构层次基本一致。从 Process 出发,我们可以获取所有 AppDomain、Assembly 和 Module,得到的对象就是诸如 IXCLRDataAssembly 这样的实例。从这些实例出发,我们又可以获取其他层次和范围的信息。
IXCLRData 系列 API 的一个显著特点是提供大量遍历操作,它们以三个函数为一组同时出现,例如 IXCLRDataModule 的 { StartEnumTypeDefinitions, EnumTypeDefinition, EndEnumTypeDefinitions }。通过这些遍历操作,我们可以获取 CLR 在不同层次和不同范围内的信息。
看起来 IXCLRDataAPI 非常“美好”、安全、严格,符合 OOP 编程规范。不过,实际上它们在某些方面令人恼火。
例如,有些函数不接受无效缓冲区(nullptr 与 size 参数为 0),否则会发生 critical error(例如:IXCLRDataTypeInstance.GetName),而有些函数则允许(例如:IXCLRDataMethodInstance.GetName)。无效缓冲区通常用于探测(probing),以预先确定真正需要的缓冲区大小。SOSDac 并没有这个问题。
例如,IXCLRTypeInstance.GetName 和 IXCLRTypeDefinition.GetName 无法获得 Nested Types 的完全限定名称(FullyQualifiedName,以符号 '+' 连接 Enclosing Type 和 Nested Type),而只能获取 Type 本身名称。SOSDac 并没有这个问题。
实际上最致命的问题是,SOSDac 和 IXCLRDataAPI 的互动非常困难。因为后者隐藏了 CLR 的细节,调用者无法从那里获取例如 TypeHandle 这种 SOSDac 工作所必需的信息;而 SOSDac 反过来也不提供任何后者的接口。
因此,这两套 API 基本上平行工作,但又互相补充。例如,SOSDac 无法获得 Type 的 Rank 和 ElementTypeHandle(如果是数组类型),而 IXCLRDataAPI 却可以获取这些信息。另一方面,IXCLRDataAPI 总是在细节上存在缺陷,例如上面提到的那些问题;还有些函数空有声明,实际上并未实现(源码中只返回一个 E_NOTIMPL,例如 IXCLRDataTypeDefinition.EnumIntance)。相比之下,SOSDac 明显更加稳定可靠,也更加透明,在需要深入具体的底层细节时非常有用。总的来说,作者在 IXCLRDataAPI 上遇到的挫折远多于在 SOSDac 上。
总结这是 CLR Underlying 专栏的第二篇文章。最近一直在阅读 CLR 源码,发现水平提高了很多,感觉可以写出一个现代编程语言的运行时了。
本文系列仅介绍了如何使用 DAC,同时也因为 DAC 部分过于“边缘”,属于 CLR 内部,资料稀缺,只好将每一点细节都详细阐述,显得有些啰嗦。
DAC 系列的下一篇文章将详细解释 DAC 的工作原理,并侧重于解释 DAC 的结构和原理,而不只是 API 的应用。在此之前,可能会先写点其他内容,毕竟每次引用相关名词时都会考虑读者是否了解,是否需要顺便解释,但过多解释可能导致文章冗长,如果有现成的文章可以引用就好了。