过程也可以被调用?为啥?啥样的是?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了过程也可以被调用?为啥?啥样的是?相关的知识,希望对你有一定的参考价值。
1.建立Sub过程一般格式如下
[Static][Privatc][Public] Sub 过程名([参数列表])
……
End Sub
说明:
(1)Sub过程以Sub开头,以End Sub 结束,在Sub和End Sub之间是描述过程操作的语句块,称为"过程体"或"子程序体"。
(2)End Sub 标志着Sub过程的结束。为了能正确运行,每个Sub过程必须有一个End Sub 字句。当程序执行到End Sub时,将退出该过程,并立即返回到调用语句下面的语句。此外,在过程体内可以用一个或多个Exit Sub语句从过程中退出。
(3)Sub过程不能嵌套。也就是说,在Sub过程内,不能定义Sub过程或Function过程;不能用GOTO语句进入或转出一个Sub过程,而且可以嵌套调用。
Sub过程 格式中有关可选项及参量的说明
1)Static(静态):指定过程中的局部变量在内存中的默认存储方式。如果使用了Static,则过程中的局部变量就是"Static"型的,即每次调用过程时,局部变量的值保持不变;如果省略了"Static",则局部变量就默认为"自动"的,即在每次调用过程时,局部变量被初始化为0或空字符串。Static对在过程之外定义的变量没有影响,即使这些变量在过程中使用。
2)Private(私有的):表示Sub过程是私有过程,只能被本模块中的其他过程访问,而不能被其他模块中的过程访问。
3)Public(公有的):表示Sub过程是公有过程,可以在程序的任何地方调用它。各窗体通用的过程一般在标准模块中用Public定义,而窗体层定义的通用过程通常在本窗体模块中使用,如果在其他窗体快中使用,则应加上窗体名作为前缀。
4)过程名:是一个长度不超过255个字符的变量名,在同一个模块中,同一个变量名不能既用做Sub过程名又用作Function过程名。
5)参数列表:含有在调用时传送给该过程的简单变量名或数组名,各名字之间用逗号隔开。它指明了调用时传送给过程的参数的类型和个数,每个参数的格式为:
[ByVal] 变量名 [()] [As 数据类型]
如果加上Buval 则表明该参数是"传值"参数,没有加"Byval"(或则加ByRef)的参数称为"引用参数"。
在定义Sub过程时,"参数列表"中的参数称为"形式参数",简称"形参",不能用定长字符串变量或定长字符串数组作为形式参数。不过,可以在调用语句中用简单定长字符串变量作为"实际参数",在调用SUB过程之前,VB把它转换为变长字符串变量。
2.Sub过程的调用
(1)把过程名作为一个语句来使用。
(2)把过程名字放在一个Call语句中。
其格式为:Call 过程名 [(实际参数)]
用Call语句调用一个过程时,如果过程本身没有参数,则"实际参数"和"()"可以省略;否则应给出相应的实际参数,并把参数放进括号中,"实际参数"是传送给Sub过程的变量或常量
例如: Call a(x,y)
而在调用Sub过程时,如果省略关键字Call 和 "()",就成为把过程名作为一个语句来使用的形式。
3.通用过程与事件过程
事件过程也是Sub过程,但它是一种特殊的Sub过程,它附加在窗体和控件上。一个控件的事件过程由控件的实际名字、下划线和事件名组成;而窗体事件过程由"Form"、下划线和事件名组成。也就是说,窗体的事件过程不能由用户任意定义,而是由系统指定的。
通用过程是可以放在标准模块中,也可以放在窗体模块中,而事件过程只能放在窗体模块中,不同模块中的过程可以互相调用。
当过程名唯一时,可以直接通过过程名调用;如果俩个或俩个以上的标准模块中含有相同的过程名,则在调用时必须用模块名限定,其一般格式为:
模块名.过程名(参数表)
一般来说,通用过程之间、事件过程之间、通用过程与事件过程之间,都可以互相调用。
二、Function 过程
前面介绍了Sun过程,它不直接返回值,可以作为独立的基本语句调用。而Function过程要返回一个值,通常出现在表达式中,从初学者的角度上来理解,Function(即函数)过程类似于数学里面的公式。这一节将介绍Function(函数)过程的定义和条用。
1、建立Function过程
[Static或Public或Private] Function 过程名 [参数列表][As 类型]
… …
end Function
(1)Function过程以Function开头,以End Function结束,中间是描述过程操作的语句块("过程体"或"函数体")。格式中"过程名"、"参数列表"、"Static"、"Private"、"Public"含义与Sub过程中相同。"As 类型"是Function过程返回值(结果)的数据类型,可以是Integer、Long、Single、Double、Currency或String,如省略,则为Variant。
(2)如前所述,过程不能嵌套。因此不能在事件过程中定义通用过程(包括Sub过程和Function过程),只能在实践过程内调用通用过程。也就是说,Function过程和Sub过程一样可定义在标准模块和窗体模块中,而不能定义在事件过程中,但是在事件过程中可以调用Function过程。
(3)相对来说,调用Sub过程相当于执行一个语句,不直接返回值;而调用Function过程则要返回一个值,因此可以像内部函数一样在表达式中使用。由Function过程返回的值放在Function与End Function之间,通过"过程名=表达式"的方法把它的值赋给"过程名"。若在Function过程中省略"过程名=表达式",则该过程返回一个默认值0或空字符串。因此为了使Function过程完成所指定的操作,通常要在过程中为"过程名"赋值。
例如:在数学公式中,矩形的周长=(长+宽)*2,根据这个公司,在计算矩形周长时,只需要把相应的长和宽的数值代入公式即可。而这个公式,在VB中可以由一个Function过程来定义:
Function z(x as Double, y as Double) as Double
z = (x + y) * 2
End Function
这就是一个定义计算矩形周长的Z函数过程,它由俩个参数(即x 和 y ,分别把他们当做矩形的长和宽),这俩个参数均为双精度浮点数,该过程根据所传送给它的两个实参来返回一个双精度浮点数结果,并将这个结果赋值给函数名Z,因为:俩个双精度浮点数相加后再乘以2的结果也肯定是双精度浮点数,所以把这个Z函数过程的返回值也定义为双精度浮点数。
2、调用Function 过程
Function过程的调用比较简单,因为可以像使用VB内部函数一样来调用它。
实际上,由于能够返回一个值,因此完全可以把Function过程看成是一个函数,它与内部函数(如Val、Str、int等函数)没什么区别,只不过内部函数由语言系统提供,而Function过程是由用户自己定义。
例如:调用上面那个例子的Function过程
dim a as integer
dim b as integer
dim c as integer
a = 3
b = 4
c = z(a,b) '调用Function过程 参考技术A 记住,任何一段不违反语言规则的代码,都可以在任何时候被执行,过程是一段被命名了的代码,过程名就是这段代码的名字,比如“中国人民解放军”,它的内部构成只不过是人,但它可以用来对付侵略,也可以用来镇压内乱,也可以用来抗灾。是一样的道理。 参考技术B 过程和函数都可以被调用。区别在于函数有返回值。
函数mm
function mm()
mm = 1
end function
调用函数 call mm
当然函数一般是把结果赋值给变量或者直接输出的。
dim m as long
m = mm
msgbox m
此时显示mm函数的值为1
过程mm
sub mm()
msgbox "mm"
end sub
调用过程
call mm
交错立体声 PCM 线性 Int16 大端音频是啥样的?
【中文标题】交错立体声 PCM 线性 Int16 大端音频是啥样的?【英文标题】:What does interleaved stereo PCM linear Int16 big endian audio look like?交错立体声 PCM 线性 Int16 大端音频是什么样的? 【发布时间】:2015-11-14 16:24:18 【问题描述】:我知道网上有很多资源解释如何解交织 PCM 数据。在我目前的项目过程中,我看过其中的大多数......但我没有音频处理方面的背景,我很难找到关于这种常见形式究竟如何的详细解释的音频被存储。
我知道我的音频将有两个通道,因此样本将以 [left][right][left][right] 格式存储... 我不明白这到底是什么意思。我还读到每个样本都以 [left MSB][left LSB][right MSB][right LSB] 格式存储。这是否意味着每个 16 位整数实际上编码了两个 8 位帧,或者每个 16 位整数是其自己的帧,用于左声道或右声道?
谢谢大家。任何帮助表示赞赏。
编辑:如果您选择给出示例,请参考以下内容。
方法上下文
具体来说,我要做的是将交错的 short[] 转换为两个 float[],每个代表左声道或右声道。我将在 Java 中实现它。
public static float[][] deinterleaveAudioData(short[] interleavedData)
//initialize the channel arrays
float[] left = new float[interleavedData.length / 2];
float[] right = new float[interleavedData.length / 2];
//iterate through the buffer
for (int i = 0; i < interleavedData.length; i++)
//THIS IS WHERE I DON'T KNOW WHAT TO DO
//return the separated left and right channels
return new float[][]left, right;
我当前的实现
我已尝试播放由此产生的音频。非常接近,接近到可以听懂一首歌的歌词,但显然仍然不是正确的方法。
public static float[][] deinterleaveAudioData(short[] interleavedData)
//initialize the channel arrays
float[] left = new float[interleavedData.length / 2];
float[] right = new float[interleavedData.length / 2];
//iterate through the buffer
for (int i = 0; i < left.length; i++)
left[i] = (float) interleavedData[2 * i];
right[i] = (float) interleavedData[2 * i + 1];
//return the separated left and right channels
return new float[][]left, right;
格式
如果有人想了解有关音频格式的更多信息,以下就是我所拥有的一切。
格式为 PCM 2 通道交错大端线性 int16 采样率为 44100 每个 short[] 缓冲区的短裤数量为 2048 每个 short[] 缓冲区的帧数为 1024 每个数据包的帧数为 1【问题讨论】:
您的实现看起来应该几乎完全正确 - 当您说您可以理解单词时,即使它们听起来是错误的,也可以确认这一点。您使用的输出格式的详细信息是什么?我的猜测是,short-to-float 转换需要缩放和/或偏移 - 使用 float 指定范围 [-32768, 32767] 会有点奇怪。 你是如何获得这个short[]
数组的?如果样本已经在两个字节整数中,则字节顺序无关紧要。来源是签名还是未签名?预期输出在什么范围内?
@Sbodd 是的,阅读我认为缩放可能是问题的答案。我现在正在实施一个规范化的流程。
@Banthar 这个短数组来自Spotify Android SDK。这就是为什么我只能访问这些小块的原因——因为我只有流媒体的权限。短裤已签名,并且它们的预期范围包括(基于我在调试器中看到的)几乎整个 -32768 到 32768 的短裤范围。
【参考方案1】:
我在对通过 Spotify Android SDK 的 onAudioDataDelivered().
传入的 short[] frames
进行去交错处理时遇到了类似的问题
onAudioDelivered
的文档在一年前写得不好。请参阅 Github issue。他们用更好的描述和更准确的参数名称更新了文档:
onAudioDataDelivered(short[] samples, int sampleCount, int sampleRate, int channels)
令人困惑的是samples.length
可以是4096。但是,它只包含sampleCount
有效样本。如果您正在接收立体声音频,并且sampleCount = 2048
在samples
数组中只有 1024 帧(每帧有两个样本)音频!
因此,您需要更新您的实现以确保您使用的是sampleCount
而不是samples.length
。
【讨论】:
【参考方案2】:实际上,您正在处理一个几乎典型的音频 CD 质量的 WAVE 文件,也就是说:
2 个频道 44100 kHz 的采样率 在 16 位有符号整数上量化的每个幅度样本我说几乎是因为大端序通常用于 AIFF 文件(Mac 世界),而不是 WAVE 文件(PC 世界)。而且我不知道如何在 Java 中处理字节序,所以我将这部分留给你。
关于样本的存储方式非常简单:
每个样本占用 16 位(从 -32768 到 +32767 的整数) 如果通道交错:(L,1),(R,1),(L,2),(R,2),...,(L,n),(R,n) 如果通道不是:(L,1),(L,2),...,(L,n),(R,1),(R,2),...,(R,n )然后再喂一个音频回调,通常需要提供32位浮点,范围从-1到+1。也许这就是您的 aglorithm 中可能缺少某些东西的地方。将您的整数除以 32768 (2^(16-1)) 应该会听起来像预期的那样。
【讨论】:
老实说,鉴于这些信息,我认为我可能有少量字节序数据,这可能是我的问题的一部分。这是一个很长的故事,但我认为我拥有大端序数据,因为我使用 Apple 的 AudioConverter Service 测试了来自同一发件人在 iPhone 上的音频。我的目的地确实需要大端数据。我也相信规范化数据会有所帮助,并且现在正在努力实施。【参考方案3】:让我们先了解一些术语
通道是单声道样本流。该术语不一定意味着样本在数据流中是连续的。 帧是一组同时发生的样本。对于立体声音频(例如 L 和 R 通道),一帧包含两个样本。 数据包是 1 个或多个帧,通常是系统一次可以处理的最小帧数。对于 PCM 音频,一个数据包通常包含 1 帧,但对于压缩音频,它会更大。 交错 是一个通常用于立体声音频的术语,其中数据流由连续的音频帧组成。因此流看起来像 L1R1L2R2L3R3......LnRn存在大端和小端音频格式,并且取决于用例。但是,在系统之间交换数据时,这通常是一个问题——在处理或与操作系统音频组件交互时,您将始终使用本机字节顺序。
你没有说你使用的是小端还是大端系统,但我怀疑它可能是前者。在这种情况下,您需要对样本进行字节反转。
虽然不是一成不变的,但在使用浮点数时,样本通常在-1.0<x<+1.0
的范围内,因此您希望将样本除以1<<15
。当使用 16 位线性类型时,它们通常是有符号的。
注意字节交换和格式转换:
int s = (int) interleavedData[2 * i];
short revS = (short) (((s & 0xff) << 8) | ((s >> 8) & 0xff))
left[i] = ((float) revS) / 32767.0f;
【讨论】:
有趣的是,您通过32767.0f
标准化。 @maxime.bochon 建议我应该除以 32768。我觉得我还听说对于多通道音频缓冲区,音量应该进一步除以通道数。如果不进行标准化,音频听起来会怎样?
这取决于是否认为 1.0f 的值被裁剪。使用1<<15
进行归一化肯定会更便宜地计算(除法是位移)。至于缺乏标准化:在您使用 DAC 等音频硬件之前,信号链没有任何区别。届时,您的信号将在两个方向上被严重削波。【参考方案4】:
我知道我的音频将有两个通道,因此样本将以 [left][right][left][right] 的格式存储......我不明白这到底是什么意思。
交错的 PCM 数据按通道顺序在每个通道存储一个样本,然后再继续下一个样本。 PCM 帧由每个通道的一组样本组成。如果您有左右声道的立体声音频,则每个样本中的一个样本一起构成一帧。
第 0 帧:[左样本][右样本] 第 1 帧:[左样本][右样本] 第 2 帧:[左样本][右样本] 第 3 帧:[左样本][右样本] 等等……每个样本都是瞬时压力的测量和数字量化。也就是说,如果每个样本有 8 位,则可以对压力进行 256 个可能的精度级别采样。知道声波是……波……有波峰和波谷,我们将希望能够测量到中心的距离。因此,我们可以将中心定义在 127 左右,然后从那里减去和加法(0 到 255,无符号),或者我们可以将这 8 位视为有符号(相同的值,只是对它们的不同解释)并从 -128 到 127。
对于单声道(单声道)音频,每个样本使用 8 位,我们每个样本使用一个字节,这意味着以 44.1kHz 采样的一秒音频恰好使用 44,100 字节的存储空间。
现在,让我们假设每个样本 8 位,但在 44.1.kHz 的立体声中。每隔一个字节都将用于左侧,每个其他字节都将用于 R。
LRLRLRLRLRLRLRLRLRLRLR...
将其放大到 16 位,每个样本有两个字节(样本设置有括号 [
和 ]
,空格表示帧边界)
[LL][RR] [LL][RR] [LL][RR] [LL][RR] [LL][RR] [LL][RR]...
我还读到每个样本都以 [left MSB][left LSB][right MSB][right LSB] 格式存储。
不一定。音频可以以任何字节顺序存储。小端是最常见的,但这不是一个神奇的规则。我确实认为所有频道总是按顺序排列,在大多数情况下,左前方将是频道 0。
这是否意味着每个 16 位整数实际上编码了两个 8 位帧,或者每个 16 位整数是其自己的帧,用于左声道或右声道?
每个值(在这种情况下为 16 位整数)都用于单个通道。永远不会有两个多字节值相互碰撞。
我希望这会有所帮助。我无法运行您的代码,但根据您的描述,我怀疑您遇到了字节序问题,并且您的示例不是真正的大字节序。
【讨论】:
以上是关于过程也可以被调用?为啥?啥样的是?的主要内容,如果未能解决你的问题,请参考以下文章
C语言的printf函数在windows平台的系统调用过程是啥样的?
非springboot的注解调用,请问通过啥样的注解可以决定接口的实现类加载顺序?