带有电话录音的多会话Adobe Audition的软件形式

在上一篇文章中,我写过有关使用类似于甘特图的电话图生成SVG矢量图形的信息。我从详细信息中获取了有关电话的信息,这些信息是通过我的帐户从移动运营商的网站上下载的。差不多是四年前。当前,我有一个使该项目更加复杂的想法:从电话交谈的音频记录中,在声音编辑器Adobe Audition 1.5中建立多会话。同时,应严格按照时间以及曲目对应的日期将这些音频记录放入多区段中。同时,从视觉上看,这样的多会话将类似于上一篇文章中构建的图表。另外,有可能在白天以“混合”和“独奏”模式快速缩放和收听电话对话的记录。



为了避免Adobe Audition出现不必要的混乱情况,我决定从一个日历月中积累的录音中创建一个多会话。当然,可以手动建立这样的会话,但这是一项漫长而艰苦的工作。此任务的主要兴趣是通过软件自动构建多会话。更准确地说,编写一个程序,该程序基于音频记录文件的列表将为Adobe Audition多会话生成SES文件。对于那些不知道的人:简而言之,多区段是一个项目,它由许多不同的音频记录组成,这些音频记录在时间和轨道上分布并设计为混合在一起。



首先,值得讨论一下我如何接收电话交谈的录音。现代智能手机具有使用各种内置于系统和第三方工具中的工具来记录电话的能力已不是什么秘密。我个人使用的是Lenovo TAB3平板电脑(带有MT8735P处理器)。该设备允许您以压缩格式在手动模式下进行音频录制,并接收扩展名为3gpp的文件。可以通过分离的声道以立体声获得录音:在一个声道中,录制用户的语音,在另一个声道中,录制自己的声音。录音的压缩格式会影响其在播放期间的失真。因此,我使用了第三方录音应用程序,其中有无数。我最喜欢的应用程序之一是“记录我的通话”。此应用程序以自动模式记录呼叫,具有许多设置,尤其是与音频记录格式和质量的选择有关。另外,作为奖励,该应用程序具有一个非常方便的内置调用日志,该日志被保存到db数据库文件中(图1)。





数字: 1.在“记录我的通话”应用程序中通话记录。



音质最好的录音参数是WAV 8000Hz 16bit Stereo。使用这样的设置,尽管录音会占用更多的存储空间,但不会失真,声音清晰。该应用程序的配置方式使得即使在电话对话开始之前,音频记录也会自动开始:在“接听电话”之前到达来电,或在响铃时拨打号码。即,未接来电也被记录。可以配置为仅记录对话。录音文件名格式也可以配置。就我而言,我对其进行了配置,如图2





所示。 2.在“记录我的通话”中设置文件名格式。



在多会话生成程序的开发过程中,有必要获取有关电话录音的日期和时间的信息。此信息将从固定位置的文件名中获取。



在开始创建多会话SES文件之前,您需要了解此类文件的工作方式。当然,任何地方都没有这种格式的文档,因此我不得不依靠个人经验和知识自行解决。该文件不是文本文件,因此在记事本中打开它毫无意义。 “ WinHex”-一个十六进制编辑器可以解决。我已经写了许多有关处理二进制数据和解密信息的文章,特别是有关编写264-avi视频重新打包程序的文章。在那儿,我或多或少地详细介绍了avi文件的设备。



首先,我在Adobe Audition 1.5中创建了一个简单的任意多会话,它由一个音轨和一个音频文件组成(图3),并将其保存到具有ses扩展名的文件中。该文件的大小为2422字节。然后我在WinHex中打开此文件(图4)。





数字: 3. Adob​​e Audition 1.5中的多会话视图-示例1





。 4.在WinHex中打开了多会话文件。



乍一看,一点都不清楚。在窗口的符号部分,您可以看到语义词“ COOLNESS”,“ hdr”,“ Master”。如果您滚动浏览下面的文档,则可以看到包含文件完整路径的文本(以及两个版本),该文本在多会话中使用。如图5所示,并以绿色概述。紧随其后的是在同一图中用红色框圈起的简短语义词。





数字: 5.多会话音频文件的路径字节。



从头到尾仔细查看该文档,我注意到了其他一些简短的语义词。我还注意到,任何有意义的单词的长度都是四的倍数。显然,这些词是组成整个多会话文件的块的标题。它使我想起了一个avi或wav文件的RIFF结构,该文件由也具有相同大小的标头的块组成。这些标头后跟一个32位数字(4个字节),指示当前块的大小。考虑到这一事实,我决定检查此原理是否适用于ses文件?事实证明,在ses格式的情况下,这也有效(图6)。





数字: 6.与RIFF结构相似(例如,“ WLST”块)。



ses文件中的第一个单词“ COOLNESS”似乎是此文件的主要标头和类型。接下来的4个字节是内容的大小,该大小位于文件的末尾。也就是说,如果仔细计算,该值比整个文件的大小小12个字节。进一步的内容包括不同块的集合。一个块具有四个或八个字节的标头,后跟4个字节,指示该块的大小,其后跟随该块的内容。在某些块中,我确定了子块的存在,但这将在每个块的更详细描述过程中进行讨论。在此文件中,在示例中,我计算了17个块,它们在图7的表中列出





。 7.组成多会话的块列表。



从表中可以看到,一些相同的信息以不同的版本显示在不同的块中。这样做可能是为了使程序的不同版本兼容。展望未来,这些块将以绿色突出显示,否则,示例中呈现的多会话将不存在。两个4字节的块以灰色突出显示,这在本节中是虚构的。确实,我有一个问题:如果从文件中删除某些块,将会发生什么?毕竟,例如,我不需要有关节拍器和速度的信息,并且在我的简单示例中不存在剪辑(更确切地说是一个剪辑)上的信封。信封是音频剪辑顶部的曲线,用于设置声音参数(音量,平衡)随时间变化的动态。我依次开始从给定的文件中剪切块,不要忘记重新计算和更正单词“ COOLNESS”之后的值。结果,成功打开了多会话,并以绿色突出显示了至少五个块。该会话包含音频文件列表的两个块。他们中的任何一个都可以留下。我更喜欢第二个选项(“ LISTFILE”块),因为在第一个选项(“ WLST”块)中,文件路径描述中每个字符有两个字节。对于扩展字符字母,可能已经完成了此操作,但是标准ASCII字母对我来说已经足够了。而且,如您所见,俄语字符得到了很好的支持。音频剪辑的描述分为三个版本。我选择第一个选项(块“ bk20”),因为我最快地找到了它的描述。会话包含音频文件列表的两个块。他们中的任何一个都可以留下。我喜欢第二个选项(“ LISTFILE”块),因为在第一个选项(“ WLST”块)中,文件路径描述中每个字符有两个字节。对于扩展字符字母可能已经完成了此操作,但是标准ASCII字母对我来说已经足够了。而且,如您所见,俄语字符得到了很好的支持。音频剪辑的描述分为三个版本。我选择第一个选项(块“ bk20”),因为我最快地找到了它的描述。该会话包含音频文件列表的两个块。他们中的任何一个都可以留下。我更喜欢第二个选项(“ LISTFILE”块),因为在第一个选项(“ WLST”块)中,文件路径描述中每个字符有两个字节。对于扩展字符字母,可能已经完成了此操作,但是标准ASCII字母对我来说已经足够了。而且,如您所见,俄语字符得到了很好的支持。音频剪辑的描述分为三个版本。我选择第一个选项(块“ bk20”),因为我最快地找到了它的描述。但是标准的ASCII字母对我来说就足够了。而且,如您所见,俄语字符得到了很好的支持。音频剪辑的描述分为三个版本。我选择第一个选项(块“ bk20”),因为我最快地找到了它的描述。但是标准的ASCII字母对我来说就足够了。而且,如您所见,俄语字符得到了很好的支持。音频剪辑的描述分为三个版本。我选择第一个选项(块“ bk20”),因为我最快地找到了它的描述。



电话对话的录音中的多会话在复杂度上将类似于此示例中呈现的多会话。唯一的区别是它将更加庞大:音频文件的数量将非常大,并且曲目的数量将等于一个月中的天数。对于这样的多会话,不需要其他“铃铛和口哨声”。块大小“ hdr”和“ stat”是静态的,并且无论多会话的大小如何,始终分别为936和40字节。 “ trks”和“ bk20”块的大小分别取决于多会话中的轨道和音频剪辑的数量。但是“ LISTFILE”块的大小是最不可预测的:它不仅取决于多会话中音频文件的数量,还取决于它们的名称和位置路径的长度。



解密和组成多会话文件块的完整描述是一项相当艰巨的任务。因此,我对信息进行了部分解码,仅注意形成简化内容的多会话时必须考虑的那些字节部分。在本文中,我将对能够解密的每个块的内容进行描述。



在多会话标题块“ hdr”的内容(末尾只有一个空格)中,关键字节是前12个字节,即3个单词,每个4个字节(图8)。第一个词是多会话中样本的采样率。对于我的多会话,此值为8000 Hz(0x1F40)。在图8中以绿色填充突出显示。让我提醒您,数字值字的字节是向后读取的。第二个单词是多会话的持续时间(长度),以样本数表示(图中的橙色填充)。在此示例中,此值为0x1A365E(1717854)。如果将其转换为分钟,则会得到1717854/8000/60,大约是三分半钟。事实如此:在最小规模上,多会话恰好具有此持续时间。对于来自电话记录的多会话,持续时间应为一天,或24 * 3600 * 8000 = 691200000 = 0x2932E000样本。顺便说一下,在这种情况下,下面面板上多会话的当前播放时间(是相对时间)将与当前电话(或一天中的一组呼叫)的绝对时间值完全一致。以黄色突出显示的下一个单词表示多会话中音频剪辑的数量。在示例中,该值等于1,但在通话的情况下,此类剪辑的数量将等于音频文件的数量。展望未来,最后的陈述并不完全正确。实际上,音频剪辑的数量可能比音频文件的数量略多。如果发生以下情况,一个文件可以包含两个剪辑如果在电话交谈中新的一天到来。在这种情况下,您将不得不将录音“传输”到新轨道,并且一个剪辑将不起作用。但是这种情况在实践中很少见,因为到新一天的转换发生在晚上,而电话活动很少。顺便说一下,在上一篇文章中形成SVG图时,我没有考虑到这一点。紧随其后的是块数的值的字,很可能是两个字节0x0020的“半字”,即十进制形式的32。它也可以用颜色填充突出显示,因为很可能意味着混合的位深度。在Adobe Audition中,底部的状态栏显示:8000 Hz,32位混合。除了“ hdr”内容的三个最重要的词外,还有其他晦涩的字节。例如,我什至不知道“大师”一词它指的是什么。显然,这是主要混合总线的名称。但是,我最感兴趣的一组字节在一个灰色框中盘旋。事实是,此序列通常在多会话文件的其他块中找到。我恰好将8个字节组合到一个组中并不是偶然的,因为很可能这是一个真实的数据类型。特别是,Double类型的编辑器将此常量“ 00 00 00 00 00 00 00 F0 3F” HEX解释为1.0e + 0,即一个单位。这些很有可能是响度水平和其他``扭曲''的值,但不是以分贝为单位,而是以系数的形式指定。我必须立即说,我无法识别(或不必要)的任何块的所有字节都将被写入生成的多会话文件,而无需进行更改,如示例中所示。但是,我最感兴趣的一组字节在一个灰色框中盘旋。事实是,此序列通常在多会话文件的其他块中找到。我恰好将8个字节组合到一个组中并不是偶然的,因为很可能这是一个真实的数据类型。特别是,Double类型的编辑器将此常量“ 00 00 00 00 00 00 00 F0 3F” HEX解释为1.0e + 0,即一个单位。这些很有可能是响度水平和其他``扭曲''的值,但不是以分贝为单位,而是以系数的形式指定。我必须立即说,我无法识别(或不必要)的任何块的所有字节都将被写入生成的多会话文件,而无需进行更改,如示例中所示。但是,我最感兴趣的一组字节在一个灰色框中盘旋。事实是,此序列通常在多会话文件的其他块中找到。我恰好将8个字节组合到一个组中并不是偶然的,因为很可能这是一个真实的数据类型。特别是,Double类型的编辑器将此常量“ 00 00 00 00 00 00 00 F0 3F” HEX解释为1.0e + 0,即一个单位。这些很有可能是响度水平和其他``扭曲''的值,但不是以分贝为单位,而是以系数的形式指定。我必须立即说,我无法识别(或不必要)的任何块的所有字节都将被写入生成的多会话文件,而无需进行更改,如示例中所示。我恰好将8个字节组合到一个组中并不是偶然的,因为很可能这是一个真实的数据类型。特别是,Double类型的编辑器将此常量“ 00 00 00 00 00 00 00 F0 3F” HEX解释为1.0e + 0,即一个单位。这些很有可能是响度水平和其他``扭曲''的值,但不是以分贝为单位,而是以系数的形式指定。我必须立即说,我无法识别(或不必要)的任何块的所有字节都将被写入生成的多会话文件,而无需进行更改,如示例中所示。我恰好将8个字节组合到一个组中并不是偶然的,因为很可能这是一个真实的数据类型。特别是,Double类型的编辑器将此常量“ 00 00 00 00 00 00 00 F0 3F” HEX解释为1.0e + 0,即一个单位。这些很有可能是响度水平和其他``扭曲''的值,但不是以分贝为单位,而是以系数的形式指定。我必须立即说,我无法识别(或不必要)的任何块的所有字节都将被写入生成的多会话文件,而无需进行更改,如示例中所示。并作为系数。我必须立即说,我无法识别(或不必要)的任何块的所有字节都将被写入生成的多会话文件,而无需进行更改,如示例中所示。并作为系数。我必须立即说,我无法识别(或不必要)的任何块的所有字节都将被写入生成的多会话文件,而无需进行更改,如示例中所示。





. 8. «hdr ».



我决定不研究当前多会话状态(最短)的“状态”块。我从一个音频文件创建了另一个示例多会话,将其拉伸了24小时,并使其水平完整显示(缩放)。在垂直方向上,缩放了轨道的视图,以便在扩展Adobe Audition窗口时,FullHD屏幕上将容纳31条轨道。这是一个月中的最大天数。多会话光标位于最开始的位置。然后,我将此多会话保存到另一个文件,然后拉出带有所有标头的“ stat”块。我将这些字节保存在文件“ stat_31_full.BLK”中,以供开发程序时进一步使用。这样的文件的内容如图9所示。该文件的大小为48字节(块内容的40字节+标头的4字节+内容大小的描述4字节)。





. 9. «stat» .



为了在撰写本文时更直观地描述接下来的三个块,我决定创建一个更复杂的多会话,它由两个轨道,两个文件和三个剪辑组成(图10)。第一个文件“ Incoming_Call-20200622_124844-+ 74999545237.wav”的持续时间为281280个样本。第二个文件“ Outgoing_Call-20200621_231753-+ 79536170218.wav”的持续时间为63360个样本。名为“ First”(重命名)的第一首曲目包含两个剪辑。第一个剪辑从会话开始时偏移了10秒(偏移了80,000个样本)。该片段由第一个音频文件的全部内容表示,即片段的持续时间与文件的持续时间相同。第二个剪辑从会话开始时偏移了50秒(偏移了50 * 8000 = 400000个样本)。该剪辑由第二音频文件的不完整内容表示。在给定的剪辑中,音频从文件的开头开始,但仅持续5秒(40,000个样本)。即,剪辑长度为5秒。第二个曲目名为“第二个”,其中包含一个剪辑。从会话开始将其偏移一秒钟(8000个样本)。该剪辑由第一个音频文件的不完整内容表示。在此剪辑中,音频不是从头开始,而是在3秒钟后开始,但直到最后才包含。因此,此剪辑内音频数据的偏移为3秒(24,000个样本)。然后,将给定剪辑的长度计算为相应音频的持续时间与剪辑内音频数据的偏移量之差。在这种情况下,剪辑长度为281280-24000 = 257280个样本。该剪辑由第一个音频文件的不完整内容表示。在此剪辑中,音频不是从头开始,而是在3秒钟后开始,但直到最后才包含。因此,此剪辑内音频数据的偏移为3秒(24,000个样本)。然后,将给定剪辑的长度计算为相应音频的持续时间与剪辑内音频数据的偏移量之差。在这种情况下,剪辑长度为281280-24000 = 257280个样本。该剪辑由第一个音频文件的不完整内容表示。在此剪辑中,音频不是从头开始,而是在3秒钟后开始,但直到最后才包含。因此,此剪辑内音频数据的偏移为3秒(24,000个样本)。然后,将给定剪辑的长度计算为相应音频的持续时间与剪辑内音频数据的偏移量之差。在这种情况下,剪辑长度为281280-24000 = 257280个样本。在这种情况下,剪辑长度为281280-24000 = 257280个样本。在这种情况下,剪辑长度为281280-24000 = 257280个样本。





. 10. Adobe Audition 1.5 — 2.



图11显示了“ trks”轨道描述块的内容。块标题的4个字节在红色框中突出显示,块内容的大小在绿色中突出显示。上面已经讨论过了。接下来是该块的内容,该块的字节在WinHex编辑器中以典型的蓝色填充突出显示。所选内容的大小显示在编辑器的右下角(也用绿色圈出),该大小与标题后面的字节中的值一致,并且在此示例中已经为308字节。如果在一个轨道的第一个(上一个)示例中,块大小为156字节,而在当前一个(上一个)示例中为308字节,则可以得出以下结论。由于假设磁道的均质性和等效性,因此每个磁道的描述区域应具有相同的大小。可以说,这些区域是“ trks”块的子块。它们在图中以蓝色概述。事实证明,一个这样的子块的大小是152个字节。在连续子块的开始处,有一个四个字节的子标题,在图中用黄色填充标记。这四个字节无非是多会话中的磁道数或子块数的值。因此,可以通过公式S = 4 + 152 * n计算“ trks”块内容的大小S,其中n是会话中的磁道数。因此是:4 + 152 * 1 = 156,和4 + 152 * 2 = 308。可以通过公式S = 4 + 152 * n计算“ trks”块内容的大小S,其中n是会话中的磁道数。因此是:4 + 152 * 1 = 156,和4 + 152 * 2 = 308。可以通过公式S = 4 + 152 * n计算“ trks”块内容的大小S,其中n是会话中的磁道数。因此是:4 + 152 * 1 = 156,和4 + 152 * 2 = 308。





. 11. «trks».



现在让我们继续描述子块的内容。那里有很多东西,但是我只解读了最基本的东西。只有三个参数:4个字节的二进制标志(用红色圈出),轨道名称(用棕色圈出)和轨道ID(用蓝色圈出)。轨道标识符是其序列号。需要在音频剪辑的描述中指示指向轨道的链接(稍后会对此进行更多介绍)。曲目名称占用36个字节的区域。这是音轨名称中的最大字符数,但可以减少,如当前示例所示。未使用的字节为零。在多段通话录音中,曲目名称将与相应日期的录音匹配。您可以使用缩写形式的两个大写字母在日期旁边添加星期几。四个字节的二进制标志(总共32个标志)用于描述轨道固有的二进制参数。实际上,它们可能少于32个,我仅解码了部分标志。其中,至少三个标志指示轨道是“ R”(记录),“ S”(独奏)还是“ M”(静音)。在给定的示例中,没有按下轨道上的这三个按钮,并且二进制标志的值为零(0x00000000)。但是,如果您按下轨道上的“ R”按钮(即,将轨道记录在案)并重新保存会话,则二进制标志的值将变为0x00000004,换句话说,从右边开始的第三位(bit2)将变为单个。正是此位负责磁道的“记录”属性。此属性在我的项目中没有任何价值,因为我的多会话专为视觉查看和播放而设计。但是,我想到在对应于周末的那些曲目上按下了“ R”按钮。此技术将使可视化多会话更加容易。



多会话“ LISTFILE”的音频文件列表的块(图12)由以下部分组成。与轨道描述块一样,也可以根据会话中文件的数量将其分为子块。与图11相似,我还用红色框突出了8字节块头,并用绿色框突出了其内容的大小。在此特定示例中,此值为188字节。内容以类似于图2的方式突出显示。 11.它分为两个区域,并用蓝线突出显示。这些是文件列表块的子块。





数字: 12.音频文件“ LISTFILE”的描述块的字节。



每个子块对应一个音频文件。该示例使用两个音频文件,因此子块的数量合适。与前面的轨道说明不同,没有关于子块数量的子标题。子块包含4个字节的“ wav”标头(以黑色突出显示)和4个字节,指示其他内容的大小(以品红色突出显示)。对于两个子块,此值在此示例中相同,为0x56(86)字节。这是由于文件位于相同的路径并且具有相同的名称。更准确地说,完全限定的文件名具有相同数量的字符。否则,子单元将具有不同的大小。子块内容区域(更多字节)包含以下信息。标识音频文件的数字以蓝色框突出显示。与曲目ID不同,该编号不是文件序列号。据我了解,保存多会话时,会为每个文件随机或伪随机地分配它。最主要的是,这些值之间没有巧合。当我两次保存多会话并按内容比较ses文件时,我对此深信不疑。结果,事实证明文件的字节数相差很大。而不仅仅是这些。在“ ep20”块中,还将一个随机数分配给信封层的ID。但是,如上所述,在此方框中,完全没有必要,因此本文中将不考虑其描述。需要音频ID才能将其链接到片段。该链接发生在带有剪辑描述的块中。在我的情况下,对于带有电话记录的多会话,音频文件的标识符将是一个自然数序列,但不是从零开始,而是例如从1000开始。在两个子块中,我未突出显示的下4个字节的值为0x13。最有可能的是,该值指示音频文件格式的类型。您可以有条件地将此值视为一个常数,因为我的所有音频文件都是同一类型。以下字节字符串描述了音频文件的全名,带有空终止符(例如行终止符)。该链的大小比音频文件全名中的字符数大一个。接下来是常数0xFFFFFFFF。紧随其后的是一个值,该值指示此音频文件中的样本数(在图12中以黄色框突出显示)。对于第一个文件,此值为0x44AC0,对于第二个文件,此值为0xF780。它们分别分别对应于十进制值281280和63360,它们已经在上面的第二个多会话示例的描述中出现过。



最后,仍然需要考虑最困难的块的描述-用于描述音频剪辑“ bk20”的块(图13)。与前两个图类似,突出显示了块内容的标题和大小。





数字: 13.音频剪辑“ bk20”的描述块的字节。



在块的内容中,首先有两个子标题,每个子标题4个字节。它们以洋红色和青色填充突出显示。第一个字幕是会话中的剪辑数。该示例中有三个。第二个字幕是常数0x48(72)。显然,它指示了每个子块的大小,并且它们进一步扩大了。它们的数量与会话中的剪辑数量一致。每个这样的子块描述一个剪辑的参数。顺便说一下,事实证明,“ bk20”块内容的大小D可通过公式D = 8 + 72 * b计算,其中b是多会话中音频剪辑的数量。在该图中,子块内没有说明性的字节分配,因为有很多必要的参数。它们在单独的表中列出(图14)。蓝色填充标记了我项目中必需的那些参数,而灰色填充标记了无法识别的常数。该表还显示了上一个示例中三个多会话剪辑中每个剪辑的参数值。





. 14. .



第一个字(4字节一组)是对信封的引用,我们不需要。第二个参数是指向音频文件的链接。此参数的值等于此音频剪辑所对应的音频文件的标识符的值。然后有两个实常数,它们早已出现。它们后面是三个协调参数,以样本数表示:剪辑从会话开始的偏移量,剪辑在会话中的长度(持续时间)以及剪辑内音频的偏移量。这些参数的名称应使所有内容都清楚。早些时候,当详细描述多会话的第二个示例时,我指出了所有偏移量和持续时间的数值。在图14中,该表以十六进制形式列出了每个剪辑的参数。通过直接从图13重写它们来将这些值输入到表中。但是如果将它们转换为十进制形式,那么它们将与第二个示例的描述中对应的值一致(单独检查)。应该注意的是,到第一个和第三个剪辑的音频文件的链接具有相同的值0x3F5B050,因为两个剪辑都使用相同的标识符引用相同的音频文件。随后是一个二进制参数字节的块(4个字节)。与磁道的描述一样,我仅解码了部分比特。默认值为0x00080000,即,如果转换为二进制,则只有一位19被“提升”为1,其余31位等于0。如实践所示,如果没有这一点,多会话将拒绝加载。在当前示例中,此值是第一个和第二个剪辑的特性,但是对于第三个剪辑,由于某种原因,标志的值等于0x000A0000。如果进行计数,则在该值中将“升高”两位:仍然是位19和另一个位17。我不知道为什么会这样。我尝试将bit17重置为零,像在相邻剪辑中一样,将整个参数的值更改为0x00080000。结果,Adobe Audition中的会话打开了,没有任何可见的更改。在Adobe Audition中工作时,我注意到剪辑属性,例如“及时修复”和“仅修复播放”。逻辑上假设二进制参数块中的某些位负责存储这些属性。剪辑还有其他二进制属性,但我们不需要它们。并且列出的两个属性将非常有用。 “及时修复”属性很有用,因为可以保护剪辑免于鼠标指针在水平方向上意外移动的可能性。但是,在这样的剪辑上,将在左下角视觉上绘制一个圆形锁形式的符号,这对于查看是不必要的图形信息。片段“仅修复播放”的第二个属性很有用,因为当在相应的轨道上激活参数“ R”(记录)时,片段将不会获得强制的红色。对于我决定在某些轨道上使用参数“ R”的原因,它已在上面编写。根据经验,我发现bit1负责剪辑的第一个属性,而bit3负责第二个属性。根据以上所述,以下是。要设置“剪辑时间”属性,您需要将值0x00080002写入二进制参数。对于“仅用于播放”属性-0x00080008。对于这两个属性,它们的逻辑和为0x0008000A。处理二进制参数。在这些字节之后,有一个指向剪辑所在轨道的链接。实际上,轨道标识符已注册,与其序列号一致。顺便说一下,Adobe Audition 1.5支持的轨道数不超过128个,因此尽管此标识符以32位值列出,但它适合一个字节。然后有未解密的零常数(4个常数,每个4个字节)。最后,最后一个重要参数是剪辑的颜色。 Adobe Audition 1.5编辑器允许您在相应对话框中为剪辑设置从0到239的颜色值,或从调色板中选择它(图15)。调色板不是特别令人满意,但是没有给出其他选项。默认剪辑颜色为102(0x66)(绿色)。顺便说一句,它支持不超过128个磁道,因此,尽管该标识符被列为32位值,但它却适合一个字节。然后有未解密的零常数(4个常数,每个4个字节)。最后,最后一个重要参数是剪辑的颜色。 Adobe Audition 1.5编辑器允许您在相应的对话框中为剪辑设置0到239的颜色值,或从调色板中选择它(图15)。调色板不是特别令人满意,但是没有给出其他选项。默认剪辑颜色为102(0x66)(绿色)。顺便说一句,它支持不超过128个磁道,因此,尽管该标识符被列为32位值,但它却适合一个字节。然后有未解密的零常数(4个常数,每个4个字节)。最后,最后一个重要参数是剪辑的颜色。 Adobe Audition 1.5编辑器允许您在相应对话框中为剪辑设置从0到239的颜色值,或从调色板中选择它(图15)。调色板不是特别令人满意,但是没有给出其他选项。默认剪辑颜色为102(0x66)(绿色)。5允许在相应对话框中为剪辑设置一个0到239的颜色值,或从调色板中选择它(图15)。调色板不是特别令人满意,但是没有给出其他选项。默认剪辑颜色为102(0x66)(绿色)。5允许在相应对话框中为剪辑设置一个0到239的颜色值,或从调色板中选择它(图15)。调色板不是特别令人满意,但是没有给出其他选项。默认剪辑颜色为102(0x66)(绿色)。





. 15. Adobe Audition 1.5.



ses文件中的color参数为32位,实际上只有240种颜色,适合一个字节。其他三个最高有效字节为零。我有一个想法,如果我尝试为不同的值编辑这些字节,那么在打开多会话时,剪辑上会出现新的颜色。但是这个技巧没有用。如前一篇文章所述,图表中的颜色对于可视地突出显示电话的特定功能很有用。多段通话的电话录音将类似于类似的图表,因此剪辑的颜色将非常有帮助。剪辑颜色参数后跟两个零字。这样就完成了对子单元的描述。这八个零字节是最后一个块的子块中的最后一个。因此,它们也将是整个ses文件中的最后一个。



在考虑该项目时,我想到了另一个想法:在多会话中添加标记(提示点),每小时放置一次,并在其上签名相应的标记。如果我们将此想法与上一篇文章进行比较,则这完全类似于图上每小时绘制的垂直线。为了使提示点出现在多会话中,必须考虑称为“提示”的第六个块。我没有开始了解此块的字节。类似于“ stat”块,在创建的24小时多会话中,我每小时手动放置23个提示点,并为其指定适当的名称。然后,我将多会话保存为单独的ses文件,剪切出“ cues”块的内容,并将其保存到“ cues_24h.BLK”文件中。开发程序时将考虑该文件。该文件的字节如图16所示。我不知道为什么,但我完全保存了内容,没有标题和内容大小字段(与“ stat_31_full.BLK”相对)。这两个词将添加到程序代码中。内容大小为556字节。其中,字幕(提示点数)占用4个字节,每个23个子块占用24个字节。在图16中,第一个子块的内容字节被填充。我决定对提示点(标签)进行如下命名:01h,02h,…,23h。





. 16. «cues» .



到此结束了对多会话格式的描述。现在我们有了必要的知识库,可以开始编写用于创建多会话的程序。与学习和解密ses格式相比,编写程序更容易。我在两个晚上完成了该计划,并且花了至少一周的时间研究格式。此外,我使用以前使用的功能编写了程序,尤其是处理文件和目录。因此,编写该程序的主要支持不是参考书或Internet,而是我以前在Habré上写过的项目。从Internet上,我仅使用了一个按日期返回星期几的函数。但是在引用该程序的文本之前,我决定分享一些更多的信息,而我最初不想在本文中写这些信息。



当我使用更新版本的Adobe Audition 3.0(该软件支持通过ASIO进行音频输入/输出)时,我想到了从电话录音中形成多会话的想法。保存多会话时,我发现它可以两种格式保存:通常的经典SES和新的XML格式,该格式不在程序的早期版本中。将会话保存为XML格式后,我立即在记事本中打开了该文件,在其中找到了以复杂的层次结构链接在一起的一堆参数的描述。为了方便查看此层次结构,我使用了WMHelp XmlPad程序。图17显示了该程序的屏幕截图,其中打开了一个试用版的简单多会话文件。左侧是文档层次结构。层次结构中的活动(选定)元素是第一个音频文件的长度参数,在音频文件描述块的第一个子块中。





. 17. XML Adobe Audition 3.0.



我决定研究这种特殊格式,并在将来以编程方式生成所需的XML文本,从而在输出中获得所需的多会话。甚至有一个想法将Excel用于此目的。困难在于轨道描述块占用了整个XML文件的大约95%。有很多参数,在不损害多会话的情况下我无法排除。事实是,在此版本的Adobe Audition中,还有更多与音轨相关的功能。从逻辑上讲,我的简单多会话不需要这些功能。但是,通过从XML文档中排除相应的字段,会话将停止。而且,对于最简单的会话,我将不得不在每个轨道的描述中“拉出”这块巨大的文本。这是生成多会话XML文件时的唯一不便之处。知识,当然,在文本XML研究中获得的多会话变体在二进制ses的研究中很有用。即使在XML中,我也无法解密某些参数。每个参数的字段都有英文的缩写名称,但是即使如此,我仍不能始终理解该参数的含义。最主要的是,我能够研究和解释主要的必要参数,它们的层次结构块和字段。然后我被一个问题折磨了很长时间:如何在旧版本的Adobe Audition中打开这样的会话?程序的新版本具有过于复杂的界面(几乎为3D),这对于可视化多会话(如图表)非常不便。并且由于Adobe Audition 3.0中的“三分法”功能在FullHD屏幕上具有完全扩展的窗口,因此最大(最小比例)可容纳28条轨道。在Adobe Audition 1.5中,适合37个用户(图。18,比例为1:2)。屏幕上总共需要显示31条曲目。





. 18. Adobe Audition .



但是最重​​要的是,在新版本的程序中以8000 Hz的频率播放多会话时,我的音质得到了改善。声音不是很好,存在谐波失真。这是由于以下事实:声音以不同的采样率(48 kHz)输出,而ASIO无法这样做。如果在设置中选择其他输出设备“ Audition 3.0 Windows Sound”,则情况不会改变。该程序的新版本不支持经典的“ DirectSound”输出设备(我称之为3.0版)。图19显示了在Adobe Audition 3.0中播放8 kHz音频(或会话)时出现的音频频谱,其中存在反向频谱谐波失真。这些频率以绿色圈出,应该听起来很理想(没有其他声音)。频率用红色圈出,这是额外的失真。这种效果很可能是由于在上采样过程之后缺少滤波。在此之后,我决定研究更简单,更有趣的Adobe Audition 1.5程序的SES二进制格式。我希望从新版本的程序中学习“人为” XML格式后,鉴于我对二进制文件的经验,对我来说不难理解。事情就这样发生了:我很快就“推广”了SES格式。最主要的是,向前兼容,向后兼容效果很好:在1.5版中成功建立了一个针对1.5版的会话。上面,我指出了Adobe Audition 3.0与声音质量和图形界面有关的缺点。但是此程序版本在多会话导航中具有优势。例如,通过用鼠标单击一个音频剪辑然后向右移动,可以在多会话中有效地收听一个音频剪辑。





数字:19.播放过程中的谐波失真。



现在,我将在扰流板下方给出程序的文本。该程序当然没有图形界面,因为该任务不需要它。该程序的文本提供有详细的注释,因此不需要其他说明。该程序在命令行上启动,并在第二秒内处理四百个文件的列表,形成一个多会话文件。程序中有四个参数变量,如果需要,它们可以允许您不生成提示标记,在周末不将“ R”放到曲目上,不设置片段的“ Fix in time”属性并选择为片段着色的标准(按呼叫类型或电话号码) ... 这三个变量必须从程序文本中排除并“带出”,也就是说,在带有程序参数的单独文件中。



C程序源代码
/********************************************************************
  "RMC"     ,  
  wav    .   
 ,    .
       yyyy-mn, 
  .      .
      (.. -),  
   .  
    ,    ,
    "RMC"   "I:".
*********************************************************************/
#include <windows.h>
#include <stdio.h>
#include <string.h>

DWORD wr; // ,   ;
DWORD ww; // ,   ;
DWORD wi; // ,   ;

//    (     );
int Date( int D, int M, int Y ){
    int a, y, m, R;
    a = ( 14 - M ) / 12;
    y = Y - a;
    m = M + 12 * a - 2;
    R = 6999 + ( D + y + y / 4 - y / 100 + y / 400 + (31 * m) / 12 );
    return R % 7;
}

//   ;
HANDLE openInputFile(const char * filename) {
       return CreateFile ( filename,      // Open Two.txt.
            GENERIC_READ,          // Open for writing
            0,                      // Do not share
            NULL,                   // No security
            OPEN_ALWAYS,            // Open or create
            FILE_ATTRIBUTE_NORMAL,  // Normal file
            NULL);                  // No template file       
}

//   ;
HANDLE openOutputFile(const char * filename) {
       return CreateFile ( filename,      // Open Two.txt.
            GENERIC_WRITE,          // Open for writing
            0,                      // Do not share
            NULL,                   // No security
            OPEN_ALWAYS,            // Open or create
            FILE_ATTRIBUTE_NORMAL,  // Normal file
            NULL);                  // No template file       
}

//    ;
void filepos(HANDLE f, __int64 p){
  LONG HPos;
  LONG LPos;
  HPos = p>>32;
  LPos = p;
  SetFilePointer (f, LPos, &HPos, FILE_BEGIN);
}

// 32-  ;
void write32(HANDLE f, signed long int a){
  WriteFile(f, &a, 4, &ww, NULL);  
}

//  ;
void fill(HANDLE f, signed long int a, unsigned char c){
  unsigned char i;
  for(i=0;i<c;i++){
    write32(f,a);
  }
}

int main(){
  HANDLE out; //   Adobe Audition;
  HANDLE stat; //     "stat" (+ );
  HANDLE cues; //     "cues";
  HANDLE lf; //     "LISTFILE";
  HANDLE blk; //     "bk20";
  char* week[7]={"", "", "", "", "", "", ""}; //  -;
  unsigned char dm[]={31,29,31,30,31,30,31,31,30,31,30,31}; //   ;
  unsigned char p_cues=1; //:    (cues);
  unsigned char p_R=1; //:   "R" (  )    ;
  unsigned char p_lock=1; //:    ;
  unsigned char p_color=2; //   ;
  unsigned char flg; // ,    .   ;
  unsigned long int lfsize=0; //  "LISTFILE";
  unsigned long int blksize=0; //  "bk20";
  unsigned long int smp; //   ;
  unsigned long int offset; //    ;
  unsigned int cfile=0; //  ;
  unsigned int cblk=0; //  ;
  char name[100]; //   (  ...);
  char fullname[100]; //      ;
  char infld[8]; //  ;
  char number[11]; //    . ;
  unsigned char len; //    ;
  printf("Input yyyy-dd name of folder:\n"); //   ;
  scanf("%s",infld); //      ;
  WIN32_FIND_DATA fld; //       ;
  HANDLE hf; //  (   ,     );
  char buf1[48],buf2[556]; //     "stat"  "cues";
  char str[16]; //   ;
  unsigned long int outpos=0; //   ;
  unsigned char byte; //      "LISTFILE"  "bk20";
  unsigned char i; //  ;
  unsigned char mn,d,dw,h,m,s; // -;
  unsigned char cdm; //    ;
  int yy; //  ;
  yy=2000+(infld[2]-48)*10+(infld[3]-48); //    ;
  mn=(infld[5]-48)*10+(infld[6]-48); //    ;
  sprintf(name,"I:\\RMC\\%s.ses",infld); //     ( );
  out=openOutputFile(name); //    ;
  WriteFile(out, "COOLNESS", 8, &wi, NULL); // :    ;
  write32(out,0); //   (  ,     );
  WriteFile(out, "hdr ", 4, &wi, NULL); //,    :  ;
  write32(out,936); //   ,  936;
  write32(out,8000); //   ;
  write32(out,24*3600*8000); //    (. 24 );
  write32(out,0); //    ( );
  write32(out,0x00010020);
  write32(out,0);
  write32(out,0x3ff00000);
  write32(out,0);
  write32(out,0x3ff00000);
  filepos(out,328); //   ;
  write32(out,0x20);
  WriteFile(out, "", 6, &wi, NULL); //  ;
  filepos(out,376); //   ;
  write32(out,0x3ff00000);
  filepos(out,892); //   ;
  write32(out,0x0430041c);
  write32(out,0x04420441);
  write32(out,0x04400435);
  filepos(out,956); //   ;
  stat=openInputFile("stat_31_full.BLK"); //     ,
  ReadFile(stat, &buf1, 48, &wr, NULL); //       ;
  WriteFile(out, buf1, 48, &wi, NULL);
  CloseHandle(stat);
  if(mn==2){ // ,
    if(!(yy%4)){ //   ,
      cdm=29; // 29 ,
    }else{
      cdm=28; // - 28;
    }
  }else{ //  ,
    cdm=dm[mn-1]; //       ;
  }
  WriteFile(out, "trks", 4, &wi, NULL); //    ;
  write32(out,4+cdm*152); //      ;
  write32(out,cdm); //       ;
  outpos=1016; //     ;
  for(i=0;i<cdm;i++){ //      
    dw=Date(i+1,mn,yy); //     ;
    write32(out,0); //      ses,       ;
    write32(out,0x3ff00000); 
    write32(out,0); //   8-  double;
    write32(out,0x3ff00000);
    if((dw%7==5||dw%7==6)&&p_R){ //   -  ,      "R",
      write32(out,4); //     "R",
    }else{
      write32(out,0); // -   ;
    }
    sprintf(str,"%02d.%02d.%i %s",i+1,mn,yy,week[dw]); //  ,    ;
    WriteFile(out, str, strlen(str), &wi, NULL);
    filepos(out,1072+152*i); //      (i+1)- ;
    write32(out,1); //  ,     ;
    write32(out,1);
    write32(out,4);
    write32(out,0);
    write32(out,0);
    write32(out,0x40590000);
    write32(out,0);
    write32(out,0);
    write32(out,0xffffff9d);
    write32(out,0xffffff9d);
    write32(out,i+1); //  ,    ;
    fill(out,0,11);
    write32(out,4);
    write32(out,0);
    outpos+=152; //  ;
  }
  if(p_cues){ //        ,    "cues";
    WriteFile(out, "cues", 4, &wi, NULL); //  ,
    write32(out,556); //  -  ;
    cues=openInputFile("cues_24h.BLK"); //   ,   ;
    ReadFile(cues, &buf2, 556, &wr, NULL); //(    ,   "stat");
    WriteFile(out, buf2, 556, &wi, NULL);
    CloseHandle(cues);
    outpos+=564;
  }
  DeleteFile("LISTFILE"); //  (      )
  DeleteFile("bk20"); //  "LISTFILE"  "bk20",
  lf=openOutputFile("LISTFILE"); // ()    
  blk=openOutputFile("bk20"); //      ;
  WriteFile(lf, "LISTFILE", 8, &wi, NULL); //     ;
  WriteFile(blk, "bk20", 4, &wi, NULL);
  write32(lf,0);
  write32(blk,0);
  write32(blk,0);
  write32(blk,0x48); //  ,      ;
  sprintf(name,"I:\\RMC\\%s\\*.wav",infld); //   wav    ;
  hf=FindFirstFile(name,&fld); //  ;
  do{ //  ;
    len=strlen(fld.cFileName); //    ;
    for(i=10;i>=1;i--){ //  10      ;
      number[10-i]=fld.cFileName[len-i-4]; //  ;
    }
    number[10]=0; //   ,    ;
    cfile+=1; //   ;
    sprintf(fullname,"I:\\RMC\\%s\\%s",infld,fld.cFileName); //     ;
    d=(fld.cFileName[22]-48)*10+(fld.cFileName[23]-48); //  ()   ;
    h=(fld.cFileName[25]-48)*10+(fld.cFileName[26]-48); //    ;
    m=(fld.cFileName[27]-48)*10+(fld.cFileName[28]-48); //    ;
    s=(fld.cFileName[29]-48)*10+(fld.cFileName[30]-48); //    ;
    offset=(h*3600+m*60+s)*8000; //    ;
    smp=(fld.nFileSizeLow-44)/4; //     (   );
    WriteFile(lf, "wav ", 4, &wi, NULL); //     ;
    write32(lf,17+strlen(fullname)); //   (    );
    write32(lf,1000+cfile); //  ( ,      1000   );
    write32(lf,0x14); //  ( );
    WriteFile(lf, fullname, strlen(fullname), &wi, NULL); //   ( );
    WriteFile(lf, "\0", 1, &wi, NULL); //   ;
    write32(lf,0xffffffff); //;
    write32(lf,smp); //   ;
    lfsize+=(25+strlen(fullname)); //   "LISTFILE";
    cblk+=1; //     ;
    write32(blk,0); //     ,       ;
    write32(blk,1000+cfile); //   ();
    write32(blk,0); //   ;
    write32(blk,0x3ff00000);
    write32(blk,0);
    write32(blk,0x3ff00000);
    write32(blk,offset); //    ;
    if(((24*3600*8000)-offset)>smp){ //  ( )     ,
      write32(blk,smp); //     ,
    }else{
      write32(blk,(24*3600*8000)-offset); //       ;
    }
    write32(blk,0); //     ;
    if(p_lock){ //       ,
      write32(blk,0x0008000a); //     (3   32 ),
    }else{
      write32(blk,0x00080008); //    (2   32 );
    } //     -   "   ";
    write32(blk,d); //   ( );
    fill(blk,0,4); // ;
    switch(p_color){ //   ;
      case 1: //   ;
        switch(fld.cFileName[0]){ //     ;
          case 'I': // "I" (   ),
            write32(blk,0); //  ;
          break;
          case 'O': // "O" (   ),
            write32(blk,102); //   (  );
          break;
          default: //  - ,
            write32(blk,102); //   ;
          break;
        }
      break;
      case 2: //  ;
        flg=0; // ;
        if(!strcmp("9530000000",number)){ // - - ,
          write32(blk,05); //  - -,
          flg=1; //( );
        }
        #include "numbers_and_colors.cpp" //      -    ();
        if(!flg){ //     (     ),
          write32(blk,102); //    ;
        }
      break;
    }
    write32(blk,0);
    write32(blk,0);
    if(((24*3600*8000)-offset)<=smp){ //  ( )     ( ),
      cblk+=1; //      ;
      write32(blk,0); //   ,  ;
      write32(blk,1000+cfile);
      write32(blk,0);
      write32(blk,0x3ff00000);
      write32(blk,0);
      write32(blk,0x3ff00000);
      write32(blk,0); //        ,
      write32(blk,smp-((24*3600*8000)-offset)); //    ,
      write32(blk,(24*3600*8000)-offset); //    ,     ;
      if(p_lock){
        write32(blk,0x0008000a);
      }else{
        write32(blk,0x00080008);
      }
      write32(blk,d+1); //  ()     ();
      fill(blk,0,4);
      switch(p_color){ //     ;
        case 1: //   ;
          switch(fld.cFileName[0]){ //       ( );
            case 'I': // ,
              write32(blk,0); //  ;
            break;
            case 'O': // ,
              write32(blk,102); //  ,   ;
            break;
            default: //  -  (  ),
              write32(blk,102); //   ;
            break;
          }
        break;
        case 2: //  ;
          flg=0;
          if(!strcmp("9530000000",number)){ // - - ,
            write32(blk,05); //  - -,
            flg=1; //( );
          }
          #include "numbers_and_colors.cpp" //      ( );
          if(!flg){ //   ,
            write32(blk,102); //   ;
          }
        break;
      }
      write32(blk,0);
      write32(blk,0);
    }  
  }while(FindNextFile(hf,&fld)); //    wav ;
  filepos(lf,8);
  write32(lf,lfsize); //   "LISTFILE",    ;
  filepos(blk,4);
  blksize=8+72*cblk; //   "bk20",   ;
  write32(blk,blksize); //   "bk20";
  write32(blk,cblk); //  ;
  blksize+=8; //   "bk20",     .  ;
  lfsize+=12; //   "LISTFILE",     .  ;
  CloseHandle(lf); // . ;
  CloseHandle(blk); // . ;
  lf=openInputFile("LISTFILE"); // .       ;
  do{ //  ,     (   );
    ReadFile(lf, &byte, 1, &wr, NULL);
    if(wr){
      WriteFile(out, &byte, 1, &wi, NULL);
    }
  }while(wr);
  CloseHandle(lf); // . ;
  blk=openInputFile("bk20"); // .       ;
  do{ //  ,     (   );
    ReadFile(blk, &byte, 1, &wr, NULL);
    if(wr){
      WriteFile(out, &byte, 1, &wi, NULL);
    }
  }while(wr);
  CloseHandle(blk); // . ;
  outpos=outpos+blksize+lfsize; //    ;
  filepos(out,8);
  write32(out,outpos-12); //      ;
  filepos(out,28);
  write32(out,cblk); //      ;
  CloseHandle(out); //   !  ;
  printf("c_files: %i\nc_block: %i\n",cfile,cblk); //    (   );
  system("PAUSE");
  return 0;
}




现在,您可以显示结果的屏幕截图。其中将有几种:在不同的观看比例,程序的不同版本以及不同的着色标准下。正在处理目录“ 2020-05”,即当年5月的记录。共处理了446条记录。块数是相同的,因为在过渡到新的一天时没有记录。





数字:20.通过电话涂色全面查看多会话的视图。数字。





数字:21.全面查看多会话的视图,并按呼叫类型进行着色。





数字:22.中等规模的多会话类型。





数字:23.大规模多届会议的看法。





数字:24. Adob​​e Audition 3.0中相同的多会话视图。






All Articles