小米开发平台MiHaptic适配说明

小米开发平台MiHaptic适配说明

1.MiHaptic简介

MiHaptic是一套振动波形的生成框架,可以通过参数或者HE格式为你的线性马达机器定制出丰富的振动效果。

1.1.能力

MiHaptic支持接入不同的触感波形生成算法以驱动手机上的线性马达,目前支持小米自研算法和RichTap。

1.2.场景及案例

  • QQ音乐节奏实验室

QQ音乐节奏实验室4D振感,开启音乐随振,让听歌更有节奏感。

  • 和平精英高品质振动

和平精英高品质振动使用MiHaptic方案对不同枪械、载具、脚步声、玻璃破碎等场景提供拟真的触感反馈。

2.使用入门

2.1.开发环境

  • 安卓Studio 4.0 以上

2.2.开发准备

2.2.1.集成MiHaptic SDK

  • miui.os

DynamicEffect_0807_2

提供组合PrimitiveEffect的方式。

  • android.os

DynamicEffect_0128

提供HE文件振动方式。

2.2.2.增加振动权限

2.2.3.使用 MiHaptic SDK文档 中的接口。

DynamicEffect_ZH.docx

2.3.使用MiHaptic

  • 组合PrimitiveEffect的方式

DynamicEffect可组合Transient和Continuous类型的效果,如下图所示

DynamicEffect 数据结构实际上是对一组参数的描述,一个DynamicEffect由若干个PrimitiveEffect和若干Parameter所组成。

PrimitiveEffect 分为两种,一种是描述瞬时振动的Transient,例如哒哒哒的清脆效果;另一种为Continuous,这种振动效果的特点是持续时间长,例如嗡嗡嗡的效果。

对于每种PrimitiveEffect,有两个重要的参数,intensity和sharpness,分别描述它们的强度与锐度。

Parameter与PrimitiveEffect的两个重要属性对应,用来控制PrimitiveEffect的强度或者锐度。

Parameter 可以添加到整个DynamicEffect里,那么它可以控制所有时间范围内的PrimitiveEffect。

Parameter 也可以添加在Continuous效果中,用来作渐变。

例如,下图所示的是一个由两个Continuous与一个Transient所组合成的效果:

DynamicEffect effect = DynamicEffect.startCompose(); 
 
DynamicEffect.PrimitiveEffect continuous1 = DynamicEffect.createContinuous(0.5, 1.0, 3.0); 
DynamicEffect.Parameter param1 = DynamicEffect.createParameter(DynamicEffect.INTENSITY,  
                                                                  new float[]{0.5, 1, 2} , new float[] {0.6 , 0.3, 0.2); 
continuous1.addParameter(1, param1); 
 
DynamicEffect.PrimitiveEffect transient = DynamicEffect.createTransient(0.8, 1.0); 
 
DynamicEffect.PrimitiveEffect continuous2 = DynamicEffect.createContinuous(0.3, 1.0, 6.0); 
DynamicEffect.Parameter param2 = DynamicEffect.createParameter(DynamicEffect.INTENSITY,  
                                                                  new float[]{1.0, 2.0} , new float[] {0.3, 1.0); 
continuous1.addParameter(2, param2); 
 
effect.addPrimitive(0, continuous1); 
effect.addPrimitive(3.5, transient); 
effect.addPrimitive(4, continuous2); 
 
DynamicEffect.Parameter global = DynamicEffect.createParameter(DynamicEffect.INTENSITY,  
                                                                  new float[]{0, 8.0} , new float[] {0.2, 1.0); 
 
effect.addParameter(2.5); 

HapticPlayer player = new HapticPlayer(effect);
player.start();

上图描述了一个DynamicEffect以及intensity属性的渐变示意图。DynamicEffect中包含了两个Continuous和一个Transient。

生成波形的强度在0时刻的强度为0.5,它是由第一个Continuous创建时所指定的。 在第0.5S时强度为0.6,该变化是由Continuous被自己的Parameter所控制引起。第2.5S时,Continuous的强度渐变到了0.04,该变化由于Global参数对其产生了影响,对于强度而言,global参数与PrimtiveEffect参数的强度作乘积,因此变为0.2*0.2=0.04 。而后该Continuous的Intensity无自身Parameter影响,但由于globalParameter存在,从2.5到第3S改变到0.05。

在第3.5S时开始播放Transient,强度为初始值0.8与当前时刻的global参数0.3相乘为0.24。(global起始时间为2.5S,因此在3.5S时参数的值渐变为0.3)。

第二个Continusou起始时间为第4S,从第4s-第6S强度递增,因为当前依旧属于global参数的作用时间,第4S强度为=0.3*0.35 = 0.105,后面的计算方式同理。

  • 使用HE文件
{
 "Metadata": {
 "Version": 1, // 版本号,整形
 "Created": "2020-07-08", // 创建时间,String类型
 "Description": "game haptic" // 震动效果描述,String类型
 },
 "Pattern": 
 [
 {
 "Event": {
 "Type": "continuous", // 事件类型: continuous->持续震动。transient->简短震动
 "RelativeTime": 0, // 相对开始时间, 整形, 单位ms
 "Duration": 300, // 持续震动类型参数:持续时间。整形, 单位ms
 "Parameters": {
 "Intensity": 80, // 震动强度, 整形, [0,100]。0->平台支持的最小值, 100->平台支持的最大值。
 "Frequency": 50, // 震动频率, 整形, [0,100]。0->平台支持的最小值, 100->平台支持的最大值。
 "Curve": [ // 持续震动类型参数:曲线。实现上保证平滑过渡效果
 {"Time": 0, "Intensity": 0, "Frequency": 25}, // 起始点,必须。time为RelativeTime,Intensity必须取值为0。
 {"Time": 100, "Intensity": 0.7, "Frequency": -30}, 
 {"Time": 200, "Intensity": 0.75, "Frequency": 90},
 {"Time": 300, "Intensity": 0, "Frequency": 50} // 结束点,必须。time为Duration,Intensity必须取值为0。
 ]
 }
 }
 },
 {
 "Event": {
 "Type": "transient", // 事件类型: continuous->持续震动, transient->简短震动
 "RelativeTime": 400, // 相对开始时间, 整形, 单位ms
 "Parameters": {
 "Intensity": 80, // 震动强度, 整形, [0,100]。0->平台支持的最小值, 100->平台支持的最大值。
 "Frequency": 40 // 震动频率, 整形, [0,100]。0->平台支持的最小值, 100->平台支持的最大值。
 }
 }
 }
 ]
}

HE文件描述如上面的JSON格式所示,可以将描述文件放在项目中,使用DynamicEffect.create(string)接口创建效果。

InputStream is = getResources().openRawResource(R.raw.demo_he);
try {
    int size = is.available();
    byte[] buffer = new byte[size];
    is.read(buffer);
    is.close();
    str = new String(buffer);
} catch (Exception e){}
effect = DynamicEffect.create(str);
player = new HapticPlayer(effect);
player.start();

注:使用HE文件创建出的DynamicEffect不可再用于添加PrimitiveEffect,HE文件当前仅支持16个以内的event。