getPitchFromAudioData method

Future<double> getPitchFromAudioData(
  1. Uint8List audioData
)

Implementation

Future<double> getPitchFromAudioData(Uint8List audioData) async {
  // Web browsers may deliver stereo (2-ch interleaved int16) even when mono
  // is requested. Down-mix to mono so the pitch detector sees the correct
  // period — otherwise every other sample belongs to a different channel,
  // which halves the apparent frequency (one octave down).
  if (kIsWeb) {
    _accumulatedData.addAll(_stereoToMono(audioData));
  } else {
    _accumulatedData.addAll(audioData);
  }

  const int bytesPerSample = 2;
  double pitch = 0;
  int neededBytes = NeomGeneratorConstants.neededSamples * bytesPerSample;

  // On web, use the auto-detected sample rate from _calibrateWebSampleRate().
  // On mobile, use the requested rate (OS respects it).
  final double effectiveSampleRate = kIsWeb
      ? _webSampleRate
      : NeomGeneratorConstants.sampleRate.toDouble();

  while (_accumulatedData.length >= neededBytes) {
    final chunk = _accumulatedData.sublist(0, neededBytes);
    _accumulatedData.removeRange(0, neededBytes);

    final pitchDetectorDart = PitchDetector(
      audioSampleRate: effectiveSampleRate,
      bufferSize: NeomGeneratorConstants.neededSamples,
    );

    try {
      final chunkAsUint8List = Uint8List.fromList(chunk);

      PitchDetectorResult pitchResult = await pitchDetectorDart.getPitchFromIntBuffer(chunkAsUint8List);
      pitch = pitchResult.pitch.roundToDouble();
    } catch (e, st) {
      NeomErrorLogger.recordError(e, st, module: 'neom_generator', operation: 'getPitchFromAudioData');
    }
  }

  return pitch;
}