Skip to content

Conversation

@SimonBaars
Copy link

@SimonBaars SimonBaars commented Nov 2, 2025

Type of change(s)

  • Bug fix
  • Feature / enhancement
  • Infrastructure / tooling (CI, build, deps, tests)
  • Documentation

What changed and why

  • Support high quality wav recording as requested in several issues

Tests performed

  • Tested recording on different sample rates

Before & after preview

ignoreImageMinify ignoreImageMinify ignoreImageMinify

Closes the following issue(s)

Checklist

  • I read the contribution guidelines.
  • I manually tested my changes on device/emulator (if applicable).
  • I updated the "Unreleased" section in CHANGELOG.md (if applicable).
  • I have self-reviewed my pull request (no typos, formatting errors, etc.).
  • All checks are passing.

Sorry, something went wrong.

Copilot AI review requested due to automatic review settings November 2, 2025 01:18
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds support for WAV (lossless) audio recording format to the voice recorder application. Users can now select WAV as an output format in addition to the existing M4A, MP3, and OGG options.

Key changes:

  • Implemented a new WavRecorder class that records audio in WAV format using AudioRecord and writes PCM data with proper WAV headers
  • Added WAV as a new extension option with appropriate UI strings and format selection logic
  • Hidden the bitrate setting when WAV format is selected, as it's a lossless format

Reviewed Changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
app/src/main/res/values/donottranslate.xml Added string resources for WAV format display
app/src/main/kotlin/org/fossify/voicerecorder/recorder/WavRecorder.kt New recorder implementation for WAV format with PCM audio capture and header generation
app/src/main/kotlin/org/fossify/voicerecorder/services/RecorderService.kt Updated recorder initialization logic to use WavRecorder when WAV format is selected
app/src/main/kotlin/org/fossify/voicerecorder/helpers/Constants.kt Added WAV extension constant and sampling rate configuration
app/src/main/kotlin/org/fossify/voicerecorder/helpers/Config.kt Added WAV format support in extension text getters and helper function
app/src/main/kotlin/org/fossify/voicerecorder/activities/SettingsActivity.kt Updated settings UI to include WAV option and hide bitrate setting for lossless formats

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


if (fos != null) {
writeEmptyHeader(fos)
var chunksCount = 0
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable chunksCount is declared but never used. Consider removing it to improve code clarity.

Copilot uses AI. Check for mistakes.
Comment on lines +142 to +148
while (i < bufferSize) {
shortBuffer.put(data[i])
shortBuffer.put(data[i + 1])
sum += abs(shortBuffer.getShort(0).toInt())
shortBuffer.clear()
i += 2
}
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential ArrayIndexOutOfBoundsException when bufferSize is odd. The loop accesses data[i + 1] which will fail if i equals bufferSize - 1. Add a check to ensure i + 1 < bufferSize or ensure bufferSize is always even.

Copilot uses AI. Check for mistakes.
Comment on lines +142 to +149
while (i < bufferSize) {
shortBuffer.put(data[i])
shortBuffer.put(data[i + 1])
sum += abs(shortBuffer.getShort(0).toInt())
shortBuffer.clear()
i += 2
}
amplitude.set((sum / (bufferSize / 16)).toInt())
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The amplitude calculation loop iterates over bufferSize bytes, but should iterate over read bytes instead. When audioRecord?.read() returns fewer bytes than bufferSize, this will process uninitialized or stale data from the data array. Change the condition to while (i < read).

Suggested change
while (i < bufferSize) {
shortBuffer.put(data[i])
shortBuffer.put(data[i + 1])
sum += abs(shortBuffer.getShort(0).toInt())
shortBuffer.clear()
i += 2
}
amplitude.set((sum / (bufferSize / 16)).toInt())
while (i < read) {
shortBuffer.put(data[i])
shortBuffer.put(data[i + 1])
sum += abs(shortBuffer.getShort(0).toInt())
shortBuffer.clear()
i += 2
}
amplitude.set((sum / (read / 16)).toInt())

Copilot uses AI. Check for mistakes.
Comment on lines +221 to +237
private fun setWaveFileHeader(file: File, channels: Int) {
val fileSize = file.length() - 44
val totalSize = fileSize + 36
val sampleRate = context.config.samplingRate.toLong()
val byteRate = sampleRate * channels * (RECORDER_BPP / 8)

try {
val wavFile = RandomAccessFile(file, "rw")
wavFile.seek(0)
wavFile.write(generateHeader(fileSize, totalSize, sampleRate, channels, byteRate))
wavFile.close()
} catch (e: FileNotFoundException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}
}
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method setWaveFileHeader is never called anywhere in the codebase and duplicates logic already present in writeAudioDataToFile at lines 187-198. Consider removing this unused method.

Suggested change
private fun setWaveFileHeader(file: File, channels: Int) {
val fileSize = file.length() - 44
val totalSize = fileSize + 36
val sampleRate = context.config.samplingRate.toLong()
val byteRate = sampleRate * channels * (RECORDER_BPP / 8)
try {
val wavFile = RandomAccessFile(file, "rw")
wavFile.seek(0)
wavFile.write(generateHeader(fileSize, totalSize, sampleRate, channels, byteRate))
wavFile.close()
} catch (e: FileNotFoundException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}
}

Copilot uses AI. Check for mistakes.
Comment on lines +45 to +47
fun setOutputFilePath(path: String) {
recordFile = File(path)
}
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The methods setOutputFile(path: String) and setOutputFilePath(path: String) have identical implementations. The redundant setOutputFilePath method should be removed, and callers should use the interface method setOutputFile(path: String) instead. Update RecorderService.kt lines 122 and 133 to call setOutputFile(recordingFile) directly.

Suggested change
fun setOutputFilePath(path: String) {
recordFile = File(path)
}

Copilot uses AI. Check for mistakes.
Comment on lines +118 to +124
.use {
recorder?.setOutputFile(it)
// For WavRecorder, also set the file path so it can update the header
if (recorder is WavRecorder) {
(recorder as WavRecorder).setOutputFilePath(recordingFile)
}
}
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cast (recorder as WavRecorder) is redundant since the if check already confirms the type. Use a smart cast by storing the result: val wavRecorder = recorder as? WavRecorder and then call wavRecorder?.setOutputFilePath(recordingFile), or better yet, eliminate this special case by refactoring WavRecorder's API design.

Copilot uses AI. Check for mistakes.

private fun getSamplingRatesArray(): ArrayList<Int> {
val baseRates = SAMPLING_RATES[config.extension]!!
// WAV doesn't have bitrate limits, return all available rates
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The comment should clarify that WAV doesn't have bitrate-related sampling rate limits, not that it lacks bitrate limits entirely. Consider: 'WAV is lossless and doesn't have bitrate-related sampling rate limits'.

Suggested change
// WAV doesn't have bitrate limits, return all available rates
// WAV is lossless and doesn't have bitrate-related sampling rate limits, return all available rates

Copilot uses AI. Check for mistakes.
@naveensingh
Copy link
Member

Thanks, but AI-generated PRs aren't accepted as of now.

@naveensingh naveensingh closed this Nov 2, 2025
@SimonBaars
Copy link
Author

SimonBaars commented Nov 2, 2025

@naveensingh Although AI was used in the development, everything was checked and tested by hand. This is good code implementing features me and other users have been looking for in this app. Could you clarify why this is being rejected without even being properly looked at?

@naveensingh
Copy link
Member

This is mentioned in the contribution guidelines: https://github.com/FossifyOrg/General-Discussion?tab=readme-ov-file#contributing-code

There's no stance against AI here, but the current coding models aren't good enough for this project and lead to wasted review time. This may change in the future, but as of now, nearly all AI-generated PRs will be rejected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WAV support

2 participants