{
  "version": 3,
  "sources": ["../../../src/plugins/encoders/mp3.ts", "../../../src/components/ReactFileUtilities/utils.ts", "../../../src/components/MediaRecorder/transcode/audioProcessing.ts"],
  "sourcesContent": ["import {\n  renderAudio,\n  toAudioBuffer,\n} from '../../components/MediaRecorder/transcode/audioProcessing';\n\nconst ENCODING_BIT_RATE = 128; // kbps;\nconst COUNT_SAMPLES_PER_ENCODED_BLOCK = 1152;\n\nconst float32ArrayToInt16Array = (float32Arr: Float32Array) => {\n  const int16Arr = new Int16Array(float32Arr.length);\n  for (let i = 0; i < float32Arr.length; i++) {\n    const float32Value = float32Arr[i];\n    // Clamp the float value between -1 and 1\n    const clampedValue = Math.max(-1, Math.min(1, float32Value));\n    // Convert the float value to a signed 16-bit integer\n    int16Arr[i] = Math.round(clampedValue * 32767);\n  }\n  return int16Arr;\n};\n\nconst splitDataByChannel = (audioBuffer: AudioBuffer) =>\n  Array.from({ length: audioBuffer.numberOfChannels }, (_, i) =>\n    audioBuffer.getChannelData(i),\n  ).map(float32ArrayToInt16Array);\n\nexport async function encodeToMp3(file: File, sampleRate: number) {\n  const lameJs = await import('@breezystack/lamejs');\n  const audioBuffer = await renderAudio(await toAudioBuffer(file), sampleRate);\n  const channelCount = audioBuffer.numberOfChannels;\n  const dataByChannel = splitDataByChannel(audioBuffer);\n  const mp3Encoder = new lameJs.Mp3Encoder(channelCount, sampleRate, ENCODING_BIT_RATE);\n\n  const dataBuffer: Int8Array[] = [];\n  let remaining = dataByChannel[0].length;\n  for (\n    let i = 0;\n    remaining >= COUNT_SAMPLES_PER_ENCODED_BLOCK;\n    i += COUNT_SAMPLES_PER_ENCODED_BLOCK\n  ) {\n    const [leftChannelBlock, rightChannelBlock] = dataByChannel.map((channel) =>\n      channel.subarray(i, i + COUNT_SAMPLES_PER_ENCODED_BLOCK),\n    );\n    dataBuffer.push(\n      new Int8Array(mp3Encoder.encodeBuffer(leftChannelBlock, rightChannelBlock)),\n    );\n    remaining -= COUNT_SAMPLES_PER_ENCODED_BLOCK;\n  }\n\n  const lastBlock = mp3Encoder.flush();\n  if (lastBlock.length) dataBuffer.push(new Int8Array(lastBlock));\n  return new Blob(dataBuffer, { type: 'audio/mp3;sbu_type=voice' });\n}\n", "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": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEA,mBAA4B;AAmIrB,IAAM,wBAAwB,CAAC,SACpC,IAAI,QAAQ,CAAC,SAAS,WAAW;AAC/B,QAAM,aAAa,IAAI,WAAW;AAClC,aAAW,SAAS,MAAM;AACxB,YAAQ,WAAW,MAAqB;AAAA,EAC1C;AAEA,aAAW,UAAU,MAAM;AACzB,WAAO,WAAW,KAAK;AAAA,EACzB;AAEA,aAAW,kBAAkB,IAAI;AACnC,CAAC;;;AC1II,IAAM,gBAAgB,OAAO,SAAe;AACjD,QAAM,WAAW,IAAI,aAAa;AAElC,QAAM,cAAc,MAAM,sBAAsB,IAAI;AACpD,QAAM,cAAc,MAAM,SAAS,gBAAgB,WAAW;AAC9D,MAAI,SAAS,UAAU,SAAU,OAAM,SAAS,MAAM;AACtD,SAAO;AACT;AAUO,IAAM,cAAc,OAAO,aAA0B,eAAuB;AACjF,QAAM,kBAAkB,IAAI;AAAA,IAC1B,YAAY;AAAA,IACZ,YAAY,WAAW;AAAA,IACvB;AAAA,EACF;AACA,QAAM,SAAS,gBAAgB,mBAAmB;AAClD,SAAO,SAAS;AAChB,SAAO,QAAQ,gBAAgB,WAAW;AAC1C,SAAO,MAAM;AAEb,SAAO,MAAM,gBAAgB,eAAe;AAC9C;;;AF/BA,IAAM,oBAAoB;AAC1B,IAAM,kCAAkC;AAExC,IAAM,2BAA2B,CAAC,eAA6B;AAC7D,QAAM,WAAW,IAAI,WAAW,WAAW,MAAM;AACjD,WAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK;AAC1C,UAAM,eAAe,WAAW,CAAC;AAEjC,UAAM,eAAe,KAAK,IAAI,IAAI,KAAK,IAAI,GAAG,YAAY,CAAC;AAE3D,aAAS,CAAC,IAAI,KAAK,MAAM,eAAe,KAAK;AAAA,EAC/C;AACA,SAAO;AACT;AAEA,IAAM,qBAAqB,CAAC,gBAC1B,MAAM;AAAA,EAAK,EAAE,QAAQ,YAAY,iBAAiB;AAAA,EAAG,CAAC,GAAG,MACvD,YAAY,eAAe,CAAC;AAC9B,EAAE,IAAI,wBAAwB;AAEhC,eAAsB,YAAY,MAAY,YAAoB;AAChE,QAAM,SAAS,MAAM,OAAO,qBAAqB;AACjD,QAAM,cAAc,MAAM,YAAY,MAAM,cAAc,IAAI,GAAG,UAAU;AAC3E,QAAM,eAAe,YAAY;AACjC,QAAM,gBAAgB,mBAAmB,WAAW;AACpD,QAAM,aAAa,IAAI,OAAO,WAAW,cAAc,YAAY,iBAAiB;AAEpF,QAAM,aAA0B,CAAC;AACjC,MAAI,YAAY,cAAc,CAAC,EAAE;AACjC,WACM,IAAI,GACR,aAAa,iCACb,KAAK,iCACL;AACA,UAAM,CAAC,kBAAkB,iBAAiB,IAAI,cAAc;AAAA,MAAI,CAAC,YAC/D,QAAQ,SAAS,GAAG,IAAI,+BAA+B;AAAA,IACzD;AACA,eAAW;AAAA,MACT,IAAI,UAAU,WAAW,aAAa,kBAAkB,iBAAiB,CAAC;AAAA,IAC5E;AACA,iBAAa;AAAA,EACf;AAEA,QAAM,YAAY,WAAW,MAAM;AACnC,MAAI,UAAU,OAAQ,YAAW,KAAK,IAAI,UAAU,SAAS,CAAC;AAC9D,SAAO,IAAI,KAAK,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAClE;",
  "names": []
}
