Vowel Practice

May 6, 2026 ยท View on GitHub

macOS app / iOS app

Practice all the popular vowels: A, E, I, O, U and more! This app helps you with speech therapy and accent reduction.

Image Image

The main function of the app is you will speak individual vowel sounds (diphthongs) and the app will show you what we hear. And there is a configuration page to help get better results, this helps if you don't have professional recording gear.

Hopefully this project can help people with Val pronunciation and accent neutralization. It can be used by individuals and in a clinical setting.

Project scope

We are seeking contributions and improvements to this program. But at the moment we are limited to implementing monophthong vowel recognition.

We will consider changes to the algorithm. However, any consideration of this must be accompanied by published papers and test data that we can replicate. See our existing model folder, and test cases!

We are also happy to accept donations of test data. If you have a large corpus of labeled data, please email us and share your experience with using this app.

We want this app to work well for an individual or a clinical setting. If there is an opportunity for a major usability improvement in these settings, let's talk about it.

Test data

The has built-in test cases which replicate the Hillenbrand 1995 data set. Although you will need to supply those audio files and data files yourself. Instructions are in the test folder.

Research

Here are citations and research that this app is based on.

Releasing a new version

The release process uses fastlane.

One-time setup

  1. Install Ruby via rbenv (macOS system Ruby is too old for fastlane):

    brew install rbenv ruby-build
    rbenv init # follow the printed shell setup instructions, then restart your shell
    rbenv install   # installs the version from .ruby-version
    bundle install
    
  2. Create fastlane/api_key.json:

    {
      "key_id": "ABCD123456",
      "issuer_id": "00000000-0000-0000-0000-000000000000",
      "key_filepath": "/absolute/path/to/AuthKey_ABCD123456.p8"
    }
    

The pipeline has five stages.

flowchart LR
  bump_version --> b["beta (TestFlight)"] --> screenshots --> upload_screenshots --> r["release (App Store)"]

Execute the end-to-end flow with the combined command:

bundle exec fastlane ios full_release notes:"Rebuild"
bundle exec fastlane mac full_release notes:"Rebuild"

Or run individual stages:

  1. Bump the marketing version (CFBundleShortVersionString) and build number:

    bundle exec fastlane bump_version           # patch (default): 4.0.1 โ†’ 4.0.2
    bundle exec fastlane bump_version bump:minor
    bundle exec fastlane bump_version bump:major
    

    Commit the version bump.

  2. Build, sign, and ship to TestFlight. This bumps the build number, archives, exports, and uploads:

    bundle exec fastlane ios beta
    bundle exec fastlane mac beta
    

    Test the build on a real device via TestFlight.

  3. Capture screenshots when needed. The screenshot lanes support quick testing of one locale or one device:

    bundle exec fastlane ios screenshots
    bundle exec fastlane ios screenshots locales:en-US devices:"iPhone 17 Pro Max"
    
    bundle exec fastlane mac screenshots
    bundle exec fastlane mac screenshots locales:en-US devices:"Mac"
    
  4. Upload screenshots separately from submission:

    bundle exec fastlane ios upload_screenshots
    bundle exec fastlane mac upload_screenshots
    
  5. Submit to the App Store. The release lanes are submit-only and do not capture or upload screenshots:

    bundle exec fastlane ios release notes:"Rebuild"
    bundle exec fastlane mac release notes:"Rebuild"
    

:information_source: If a beta upload fails because the build number is behind App Store Connect, set the project build number once to remote highest + 1, commit, rerun, then continue local increments.

:information_source: The before_all hook in fastlane/Fastfile strips /opt/homebrew and /usr/local from PATH before xcodebuild -exportArchive runs. Without this, Xcode 26's IPA packaging step fails with Copy failed because /usr/bin/rsync (openrsync 2.6.9) and Homebrew's rsync 3.x interpret the -E flag differently. Sanitizing PATH ensures both ends use openrsync.