{"version":3,"file":"audioProcessing.766ca76c.mjs","names":[],"sources":["../../src/components/ReactFileUtilities/utils.ts","../../src/components/MediaRecorder/transcode/audioProcessing.ts"],"sourcesContent":["import type { FileLike, RecordedMediaType } from './types';\nimport type { ChangeEvent } from 'react';\nimport { useCallback } from 'react';\n\nexport const useHandleFileChangeWrapper = (\n  resetOnChange = false,\n  handler?: (files: Array<File>) => void,\n) =>\n  useCallback(\n    ({ currentTarget }: ChangeEvent<HTMLInputElement>) => {\n      const { files } = currentTarget;\n\n      if (!files) return;\n\n      try {\n        handler?.(Array.from(files));\n      } catch (error) {\n        console.error(error);\n      }\n\n      if (resetOnChange) currentTarget.value = '';\n    },\n    [handler, resetOnChange],\n  );\n\nexport function dataTransferItemsHaveFiles(items?: DataTransferItem[]): boolean {\n  if (!items || !items.length) {\n    return false;\n  }\n  for (const item of items) {\n    if (item.kind === 'file' || item.type === 'text/html') {\n      return true;\n    }\n  }\n  return false;\n}\n\nexport async function dataTransferItemsToFiles(\n  items?: DataTransferItem[],\n): Promise<FileLike[]> {\n  if (!items || !items.length) {\n    return [];\n  }\n\n  // If there are files inside the DataTransferItem prefer those\n  const fileLikes = getFileLikes(items);\n  if (fileLikes.length) {\n    return fileLikes;\n  }\n\n  // Otherwise extract images from html\n  const blobPromises = [];\n  for (const item of items) {\n    if (item.type === 'text/html') {\n      blobPromises.push(\n        new Promise<void>((accept) => {\n          item.getAsString(async (s) => {\n            const imagePromises = extractImageSources(s).map((src) =>\n              getImageSource(fileLikes, src),\n            );\n\n            await Promise.all(imagePromises);\n            accept();\n          });\n        }),\n      );\n    }\n  }\n  await Promise.all(blobPromises);\n  return fileLikes;\n}\n\nfunction getFileLikes(items: DataTransferItem[]) {\n  const fileLikes = [];\n  for (const item of items) {\n    if (item.kind === 'file') {\n      const file = item.getAsFile();\n      if (file) {\n        fileLikes.push(file);\n      }\n    }\n  }\n  return fileLikes;\n}\n\nasync function getImageSource(fileLikes: FileLike[], src: string) {\n  let res;\n  try {\n    res = await fetch(src);\n  } catch (e) {\n    return;\n  }\n  const contentType = res.headers.get('Content-type') || 'application/octet-stream';\n  const buf = await res.arrayBuffer();\n  const blob = new Blob([buf], { type: contentType });\n  fileLikes.push(blob);\n}\n\nconst extractImageSources = (s: string) => {\n  const imageTags = new DOMParser()\n    .parseFromString(s, 'text/html')\n    .getElementsByTagName('img');\n  return Array.from(imageTags, (tag) => tag.src).filter((tag) => tag);\n};\n\nexport const isBlobButNotFile = (obj: unknown): obj is Blob =>\n  obj instanceof Blob && !(obj instanceof File);\n\nexport const createFileFromBlobs = ({\n  blobsArray,\n  fileName,\n  mimeType,\n}: {\n  blobsArray: Blob[];\n  fileName: string;\n  mimeType: string;\n}) => {\n  const concatenatedBlob = new Blob(blobsArray, { type: mimeType });\n  return new File([concatenatedBlob], fileName, { type: concatenatedBlob.type });\n};\n\nexport const getExtensionFromMimeType = (mimeType: string) => {\n  const match = mimeType.match(/\\/([^/;]+)/);\n  return match && match[1];\n};\n\nexport const getRecordedMediaTypeFromMimeType = (\n  mimeType: string,\n): RecordedMediaType | null => {\n  const match = mimeType.match(/^(audio|video)\\/.*$/);\n  return match && (match[1] as RecordedMediaType);\n};\n\nexport const readFileAsArrayBuffer = (file: File): Promise<ArrayBuffer> =>\n  new Promise((resolve, reject) => {\n    const fileReader = new FileReader();\n    fileReader.onload = () => {\n      resolve(fileReader.result as ArrayBuffer);\n    };\n\n    fileReader.onerror = () => {\n      reject(fileReader.error);\n    };\n\n    fileReader.readAsArrayBuffer(file);\n  });\n\nexport const generateFileName = (mimeType: string) =>\n  `file_${new Date().toISOString()}.${getExtensionFromMimeType(mimeType)}`;\n","import { readFileAsArrayBuffer } from '../../ReactFileUtilities';\n\n/**\n * In the context of resampling audio data, AudioContext is used to decode the input audio file into an AudioBuffer,\n * which is a fundamental data structure representing audio data.\n * @param file\n */\nexport const toAudioBuffer = async (file: File) => {\n  const audioCtx = new AudioContext();\n\n  const arrayBuffer = await readFileAsArrayBuffer(file);\n  const decodedData = await audioCtx.decodeAudioData(arrayBuffer);\n  if (audioCtx.state !== 'closed') await audioCtx.close();\n  return decodedData;\n};\n\n/**\n * OfflineAudioContext is a specialized type of AudioContext that does not render audio in real-time and is used for offline audio processing tasks.\n * It allows performing audio processing and rendering without actually playing the audio through speakers or outputting it to a destination.\n * In the context of resampling audio data, OfflineAudioContext is used to resample the decoded AudioBuffer from a file to the desired sample rate.\n * It provides more flexibility and control over audio processing, as it can operate at different sample rates and durations compared to real-time audio contexts.\n * @param audioBuffer\n * @param sampleRate\n */\nexport const renderAudio = async (audioBuffer: AudioBuffer, sampleRate: number) => {\n  const offlineAudioCtx = new OfflineAudioContext(\n    audioBuffer.numberOfChannels,\n    audioBuffer.duration * sampleRate,\n    sampleRate,\n  );\n  const source = offlineAudioCtx.createBufferSource();\n  source.buffer = audioBuffer;\n  source.connect(offlineAudioCtx.destination);\n  source.start();\n\n  return await offlineAudioCtx.startRendering();\n};\n"],"mappings":"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"}