/// <summary> /// If the default device is recording, ends the recording session and trims the default audio clip produced. /// </summary> public void StopRecording() { if (Microphone.IsRecording(null)) { m_ForcedStopRecording = true; Microphone.End(null); float recordingLengthInSeconds = Time.time - m_RecordingStartTime; SmartLogger.Log(DebugFlags.AudioRecordingManager, "Unity mic recording length: " + recordingLengthInSeconds + " seconds"); // Trim the default audio clip produced by UnityEngine.Microphone to fit the actual recording length. var samples = new float[Mathf.CeilToInt(m_RecordedAudio.frequency * recordingLengthInSeconds)]; m_RecordedAudio.GetData(samples, 0); m_RecordedAudio = AudioClip.Create("TrimmedAudio", samples.Length, m_RecordedAudio.channels, m_RecordedAudio.frequency, false); m_RecordedAudio.SetData(samples, 0); } }
/// <summary> /// Computes the Levenshtein Distance between two strings. /// This is an altered version of a script which can be found here: http://www.dotnetperls.com/levenshtein /// <param name="firstString">First string to compare</param> /// <param name="secondString">Second string to compare</param> /// <param name="caseSensitive">Whether the algorithm should preserve the casing of the two strings</param> /// </summary> public static int LevenshteinDistance(string firstString, string secondString, bool caseSensitive = false) { SmartLogger.Log(DebugFlags.StringUtilities, "\"" + firstString + "\" : \"" + secondString + "\""); int firstStringLength = firstString.Length; int secondStringLength = secondString.Length; // Initialize a 2D array of distances, where distances[i, j] is the Levenshtein Distance between the substring of // the first i characters of firstString and the substring of the first j characters of secondString. // Trivially then, distances[i, 0] = i and distances[0, j] = j. var distances = new int[firstStringLength + 1, secondStringLength + 1]; for (int i = 0; i <= firstStringLength; ++i) { distances[i, 0] = i; } for (int j = 0; j <= secondStringLength; ++j) { distances[0, j] = j; } if (!caseSensitive) { firstString = firstString.ToLower(); secondString = secondString.ToLower(); } for (int i = 1; i <= firstStringLength; ++i) { for (int j = 1; j <= secondStringLength; ++j) { // Either align the two current characters and take a cost of 0 if they are the same // and 1 if they are different, or skip one of the characters and take a cost of 1. int cost = (secondString[j - 1] == firstString[i - 1]) ? 0 : 1; distances[i, j] = Math.Min( Math.Min(distances[i - 1, j] + 1, distances[i, j - 1] + 1), distances[i - 1, j - 1] + cost); } } return(distances[firstStringLength, secondStringLength]); }
/// <summary> /// Creates and returns a specific chunk of audio from the current recording. /// </summary> /// <param name="offsetInSeconds">Number of seconds from the start of the recording at which the chunk begins</param> /// <param name="chunkLengthInSeconds">Maximum number of seconds the audio chunk should be</param> /// <returns>The audio chunk, or null if the chunk length is less than or equal to 0 or if /// the offset is greater than or equal to the recorded audio length</returns> public AudioClip GetChunkOfRecordedAudio(float offsetInSeconds, float chunkLengthInSeconds) { // Check for nonsense parameters. if (chunkLengthInSeconds <= 0) { SmartLogger.LogError(DebugFlags.AudioRecordingManager, "Audio chunk length cannot be less than or equal to 0."); return(null); } if (offsetInSeconds >= m_RecordedAudio.length) { SmartLogger.LogError(DebugFlags.AudioRecordingManager, "Offset cannot be greater than or equal to the recorded audio length."); return(null); } // Check for parameters that can be clamped. if (offsetInSeconds < 0) { SmartLogger.LogWarning(DebugFlags.AudioRecordingManager, "Chunk offset is less than 0. Clamping to 0."); offsetInSeconds = 0; } if (offsetInSeconds + chunkLengthInSeconds > m_RecordedAudio.length) { SmartLogger.LogWarning(DebugFlags.AudioRecordingManager, "Chunk offset + length is greater than the recorded audio length. Clamping chunk length."); chunkLengthInSeconds = m_RecordedAudio.length - offsetInSeconds; } // The audio chunk will have a number of samples equal to [chunk length] * [audio frequency (samples-per-second)]. var samples = new float[Mathf.CeilToInt(m_RecordedAudio.frequency * chunkLengthInSeconds)]; // Grab samples from the recorded audio starting from the appropriate offset. m_RecordedAudio.GetData(samples, Mathf.FloorToInt(m_RecordedAudio.frequency * offsetInSeconds)); // Create a new AudioClip with these samples. AudioClip audioChunk = AudioClip.Create("AudioChunk", samples.Length, m_RecordedAudio.channels, m_RecordedAudio.frequency, false); audioChunk.SetData(samples, 0); return(audioChunk); }
/// <summary> /// Writes the given text to a line in the log file if m_ShouldLogToFile is true. /// </summary> /// <param name="text">Text to write to the file</param> public void WriteTextToFileIfShouldLog(string text) { if (m_ShouldLogToFile) { lock (m_FileLockHandle) { SmartLogger.Log(DebugFlags.LogFileManager, "log to file"); if (!File.Exists(m_LogFilePath)) { FileStream file = File.Create(m_LogFilePath); file.Close(); } using (var fileStream = new FileStream(m_LogFilePath, FileMode.Append, FileAccess.Write)) { using (var streamWriter = new StreamWriter(fileStream)) { streamWriter.WriteLine(text); } fileStream.Close(); } } } }
/// <summary> /// Takes an input string and removes from it any special formatting the caller specifies. /// </summary> /// <param name="input">String to modify</param> /// <param name="charsToRemove">Set of individual characters to remove</param> /// <param name="leadingCharsForWordsToRemove">Set of leading characters for words to remove</param> /// <param name="surroundingCharsForTextToRemove">Dictionary of surrounding characters for text to remove, /// where the leading character is the key and the ending character is the value</param> /// <param name="removeAllNonAlphanumericOrWhitespaceChars">Whether all characters that are not alphanumeric /// and not whitespace should be removed</param> /// <param name="removeExtraWhitespace">Whether whitespace should be trimmed to a single character /// of whitespace and surrounding whitespace should be removed</param> /// <returns>The input string stripped of any specified special formatting</returns> public static string TrimSpecialFormatting(string input, HashSet <char> charsToRemove, HashSet <char> leadingCharsForWordsToRemove, Dictionary <char, char> surroundingCharsForTextToRemove, bool removeAllNonAlphanumericOrWhitespaceChars = true, bool removeExtraWhitespace = true) { string output = ""; if (input.Length > 0) { int startIndex = 0; int endIndex = input.Length - 1; if (removeExtraWhitespace) { // Skip whitespace at the beginning and end. while (startIndex < input.Length && char.IsWhiteSpace(input[startIndex])) { startIndex++; } while (endIndex >= 0 && char.IsWhiteSpace(input[endIndex])) { endIndex--; } } bool currentlyIgnoringWhitespace = false; bool currentlyInWordToRemove = false; const char wordSeparatorChar = ' '; char lastAddedChar = wordSeparatorChar; bool currentlyInTextToRemove = false; char endCharForCurrentTextToRemove = '\0'; for (int i = startIndex; i <= endIndex; ++i) { // Ignore all characters as long as we are still within text to remove. if (currentlyInTextToRemove) { if (input[i] == endCharForCurrentTextToRemove) { currentlyInTextToRemove = false; } } // Otherwise we might still add this character. else { // If we were within a word to remove and the current character is a word separator character, // then we are no longer within a word to remove. if (currentlyInWordToRemove && input[i] == wordSeparatorChar) { currentlyInWordToRemove = false; } // If we are not within a word to remove and either we are not ignoring whitespace // or this character is not whitespace, we might still add this character. if (!currentlyInWordToRemove && (!currentlyIgnoringWhitespace || !char.IsWhiteSpace(input[i]))) { // If this character is the leading character for text to remove, then we are now within text to remove. if (surroundingCharsForTextToRemove.ContainsKey(input[i])) { currentlyInTextToRemove = true; endCharForCurrentTextToRemove = surroundingCharsForTextToRemove[input[i]]; } // If this character is both the first character in a word and the leading character // for a word to remove, then we are now within a word to remove. else if (leadingCharsForWordsToRemove.Contains(input[i]) && (i == 0 || lastAddedChar == wordSeparatorChar)) { currentlyInWordToRemove = true; } // If this character isn't one of the given characters to remove, we might still add this character. else if (!charsToRemove.Contains(input[i]) && (!removeAllNonAlphanumericOrWhitespaceChars || char.IsLetterOrDigit(input[i]) || char.IsWhiteSpace(input[i]))) { // If we are not ignoring whitespace or this character is not whitespace, add this character. if (!currentlyIgnoringWhitespace || !char.IsWhiteSpace(input[i])) { output += input[i]; lastAddedChar = input[i]; } // Determine if we should start ignoring whitespace or stop ignoring whitespace. if (!currentlyIgnoringWhitespace && char.IsWhiteSpace(input[i]) && removeExtraWhitespace) { currentlyIgnoringWhitespace = true; } else if (currentlyIgnoringWhitespace && !char.IsWhiteSpace(input[i])) { currentlyIgnoringWhitespace = false; } } } } } } SmartLogger.Log(DebugFlags.StringUtilities, "Original String: " + input); SmartLogger.Log(DebugFlags.StringUtilities, "Trimmed String: " + output); return(output); }