|
/************************************************************************************
|
|
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
|
|
|
|
Licensed under the Oculus Utilities SDK License Version 1.31 (the "License"); you may not use
|
|
the Utilities SDK except in compliance with the License, which is provided at the time of installation
|
|
or download, or which otherwise accompanies this software in either electronic or hard copy form.
|
|
|
|
You may obtain a copy of the License at
|
|
https://developer.oculus.com/licenses/utilities-1.31
|
|
|
|
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
|
|
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
|
ANY KIND, either express or implied. See the License for the specific language governing
|
|
permissions and limitations under the License.
|
|
************************************************************************************/
|
|
|
|
using UnityEngine;
|
|
using System.Collections;
|
|
|
|
/// <summary>
|
|
/// A PCM buffer of data for a haptics effect.
|
|
/// </summary>
|
|
public class OVRHapticsClip
|
|
{
|
|
/// <summary>
|
|
/// The current number of samples in the clip.
|
|
/// </summary>
|
|
public int Count { get; private set; }
|
|
|
|
/// <summary>
|
|
/// The maximum number of samples the clip can store.
|
|
/// </summary>
|
|
public int Capacity { get; private set; }
|
|
|
|
/// <summary>
|
|
/// The raw haptics data.
|
|
/// </summary>
|
|
public byte[] Samples { get; private set; }
|
|
|
|
public OVRHapticsClip()
|
|
{
|
|
Capacity = OVRHaptics.Config.MaximumBufferSamplesCount;
|
|
Samples = new byte[Capacity * OVRHaptics.Config.SampleSizeInBytes];
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a clip with the specified capacity.
|
|
/// </summary>
|
|
public OVRHapticsClip(int capacity)
|
|
{
|
|
Capacity = (capacity >= 0) ? capacity : 0;
|
|
Samples = new byte[Capacity * OVRHaptics.Config.SampleSizeInBytes];
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a clip with the specified data.
|
|
/// </summary>
|
|
public OVRHapticsClip(byte[] samples, int samplesCount)
|
|
{
|
|
Samples = samples;
|
|
Capacity = Samples.Length / OVRHaptics.Config.SampleSizeInBytes;
|
|
Count = (samplesCount >= 0) ? samplesCount : 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a clip by mixing the specified clips.
|
|
/// </summary>
|
|
public OVRHapticsClip(OVRHapticsClip a, OVRHapticsClip b)
|
|
{
|
|
int maxCount = a.Count;
|
|
if (b.Count > maxCount)
|
|
maxCount = b.Count;
|
|
|
|
Capacity = maxCount;
|
|
Samples = new byte[Capacity * OVRHaptics.Config.SampleSizeInBytes];
|
|
|
|
for (int i = 0; i < a.Count || i < b.Count; i++)
|
|
{
|
|
if (OVRHaptics.Config.SampleSizeInBytes == 1)
|
|
{
|
|
byte sample = 0; // TODO support multi-byte samples
|
|
if ((i < a.Count) && (i < b.Count))
|
|
sample = (byte)(Mathf.Clamp(a.Samples[i] + b.Samples[i], 0, System.Byte.MaxValue)); // TODO support multi-byte samples
|
|
else if (i < a.Count)
|
|
sample = a.Samples[i]; // TODO support multi-byte samples
|
|
else if (i < b.Count)
|
|
sample = b.Samples[i]; // TODO support multi-byte samples
|
|
|
|
WriteSample(sample); // TODO support multi-byte samples
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a haptics clip from the specified audio clip.
|
|
/// </summary>
|
|
public OVRHapticsClip(AudioClip audioClip, int channel = 0)
|
|
{
|
|
float[] audioData = new float[audioClip.samples * audioClip.channels];
|
|
audioClip.GetData(audioData, 0);
|
|
|
|
InitializeFromAudioFloatTrack(audioData, audioClip.frequency, audioClip.channels, channel);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds the specified sample to the end of the clip.
|
|
/// </summary>
|
|
public void WriteSample(byte sample) // TODO support multi-byte samples
|
|
{
|
|
if (Count >= Capacity)
|
|
{
|
|
//Debug.LogError("Attempted to write OVRHapticsClip sample out of range - Count:" + Count + " Capacity:" + Capacity);
|
|
return;
|
|
}
|
|
|
|
if (OVRHaptics.Config.SampleSizeInBytes == 1)
|
|
{
|
|
Samples[Count * OVRHaptics.Config.SampleSizeInBytes] = sample; // TODO support multi-byte samples
|
|
}
|
|
|
|
Count++;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clears the clip and resets its size to 0.
|
|
/// </summary>
|
|
public void Reset()
|
|
{
|
|
Count = 0;
|
|
}
|
|
|
|
private void InitializeFromAudioFloatTrack(float[] sourceData, double sourceFrequency, int sourceChannelCount, int sourceChannel)
|
|
{
|
|
double stepSizePrecise = (sourceFrequency + 1e-6) / OVRHaptics.Config.SampleRateHz;
|
|
|
|
if (stepSizePrecise < 1.0)
|
|
return;
|
|
|
|
int stepSize = (int)stepSizePrecise;
|
|
double stepSizeError = stepSizePrecise - stepSize;
|
|
double accumulatedStepSizeError = 0.0f;
|
|
int length = sourceData.Length;
|
|
|
|
Count = 0;
|
|
Capacity = length / sourceChannelCount / stepSize + 1;
|
|
Samples = new byte[Capacity * OVRHaptics.Config.SampleSizeInBytes];
|
|
|
|
int i = sourceChannel % sourceChannelCount;
|
|
while (i < length)
|
|
{
|
|
if (OVRHaptics.Config.SampleSizeInBytes == 1)
|
|
{
|
|
WriteSample((byte)(Mathf.Clamp01(Mathf.Abs(sourceData[i])) * System.Byte.MaxValue)); // TODO support multi-byte samples
|
|
}
|
|
i+= stepSize * sourceChannelCount;
|
|
accumulatedStepSizeError += stepSizeError;
|
|
if ((int)accumulatedStepSizeError > 0)
|
|
{
|
|
i+= (int)accumulatedStepSizeError * sourceChannelCount;
|
|
accumulatedStepSizeError = accumulatedStepSizeError - (int)accumulatedStepSizeError;
|
|
}
|
|
}
|
|
}
|
|
}
|