├── .github
└── workflows
│ └── tests.yml
├── .gitignore
├── Cookbook.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── Cookbook
├── Configuration
│ └── SampleCode.xcconfig
├── Cookbook.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Cookbook.xcscheme
├── Cookbook
│ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── AppIcon-1024px.png
│ │ │ ├── AppIcon-120px-40pt@3x.png
│ │ │ ├── AppIcon-120px-60pt@2x.png
│ │ │ ├── AppIcon-152px-76pt@2x.png
│ │ │ ├── AppIcon-167px-83.5pt@2x.png
│ │ │ ├── AppIcon-180px-60pt@3x.png
│ │ │ ├── AppIcon-20px-20pt@1x.png
│ │ │ ├── AppIcon-29px-29pt@1x.png
│ │ │ ├── AppIcon-40px-20pt@2x-1.png
│ │ │ ├── AppIcon-40px-20pt@2x.png
│ │ │ ├── AppIcon-40px-40pt@1x.png
│ │ │ ├── AppIcon-58px-29pt@2x-1.png
│ │ │ ├── AppIcon-58px-29pt@2x.png
│ │ │ ├── AppIcon-60px-20pt@3x.png
│ │ │ ├── AppIcon-76px-76pt@1x.png
│ │ │ ├── AppIcon-80px-40pt@2x-1.png
│ │ │ ├── AppIcon-80px-40pt@2x.png
│ │ │ ├── AppIcon-87px-29pt@3x.png
│ │ │ └── Contents.json
│ │ ├── Contents.json
│ │ ├── audiokit-icon.imageset
│ │ │ ├── Contents.json
│ │ │ ├── audiokit-icon.png
│ │ │ ├── audiokit-icon2x.png
│ │ │ └── audiokit-icon@3x.png
│ │ └── audiokit-logo.imageset
│ │ │ ├── Contents.json
│ │ │ └── audiokit-logo.png
│ ├── Base.lproj
│ │ └── LaunchScreen.storyboard
│ ├── Cookbook.entitlements
│ ├── CookbookApp.swift
│ ├── Info.plist
│ └── audio3D.scnassets
│ │ └── audio3DTest.scn
├── CookbookCommon
│ ├── .swiftpm
│ │ └── xcode
│ │ │ └── package.xcworkspace
│ │ │ └── contents.xcworkspacedata
│ ├── Package.resolved
│ ├── Package.swift
│ ├── README.md
│ ├── Sources
│ │ └── CookbookCommon
│ │ │ ├── About AudioKit
│ │ │ ├── AboutAudioKitContentView.swift
│ │ │ └── AudioKitInfoView.swift
│ │ │ ├── Assets.xcassets
│ │ │ ├── AppIcon.appiconset
│ │ │ │ ├── AppIcon-1024px.png
│ │ │ │ ├── AppIcon-120px-40pt@3x.png
│ │ │ │ ├── AppIcon-120px-60pt@2x.png
│ │ │ │ ├── AppIcon-152px-76pt@2x.png
│ │ │ │ ├── AppIcon-167px-83.5pt@2x.png
│ │ │ │ ├── AppIcon-180px-60pt@3x.png
│ │ │ │ ├── AppIcon-20px-20pt@1x.png
│ │ │ │ ├── AppIcon-29px-29pt@1x.png
│ │ │ │ ├── AppIcon-40px-20pt@2x-1.png
│ │ │ │ ├── AppIcon-40px-20pt@2x.png
│ │ │ │ ├── AppIcon-40px-40pt@1x.png
│ │ │ │ ├── AppIcon-58px-29pt@2x-1.png
│ │ │ │ ├── AppIcon-58px-29pt@2x.png
│ │ │ │ ├── AppIcon-60px-20pt@3x.png
│ │ │ │ ├── AppIcon-76px-76pt@1x.png
│ │ │ │ ├── AppIcon-80px-40pt@2x-1.png
│ │ │ │ ├── AppIcon-80px-40pt@2x.png
│ │ │ │ ├── AppIcon-87px-29pt@3x.png
│ │ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ ├── audiokit-icon.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ ├── audiokit-icon.png
│ │ │ │ ├── audiokit-icon2x.png
│ │ │ │ └── audiokit-icon@3x.png
│ │ │ └── audiokit-logo.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── audiokit-logo.png
│ │ │ ├── Colors.xcassets
│ │ │ ├── AccentColor.colorset
│ │ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ └── FontColor.colorset
│ │ │ │ └── Contents.json
│ │ │ ├── ContentView.swift
│ │ │ ├── CookbookCommon.swift
│ │ │ ├── Impulse Responses
│ │ │ ├── dish.wav
│ │ │ └── stairwell.wav
│ │ │ ├── MIDI Files
│ │ │ ├── 4tracks.mid
│ │ │ └── Demo.mid
│ │ │ ├── Preview Content
│ │ │ └── Preview Assets.xcassets
│ │ │ │ └── Contents.json
│ │ │ ├── Recipes
│ │ │ ├── AdditionalPackages
│ │ │ │ ├── ControlsView.swift
│ │ │ │ ├── FlowView.swift
│ │ │ │ ├── KeyboardView.swift
│ │ │ │ ├── PianoRollView.swift
│ │ │ │ ├── STKView.swift
│ │ │ │ └── WaveformView.swift
│ │ │ ├── AudioPlayer
│ │ │ │ ├── AudioPlayerCompletionHandler.swift
│ │ │ │ ├── MultiSegmentPlayerView.swift
│ │ │ │ └── Playlist.swift
│ │ │ ├── Distortion
│ │ │ │ ├── BitCrusher.swift
│ │ │ │ ├── Clipper.swift
│ │ │ │ ├── Decimator.swift
│ │ │ │ ├── DistortionPresets.swift
│ │ │ │ ├── RingModulator.swift
│ │ │ │ └── TanhDistortion.swift
│ │ │ ├── Effects
│ │ │ │ ├── AutoPanner.swift
│ │ │ │ ├── AutoWah.swift
│ │ │ │ ├── Balancer.swift
│ │ │ │ ├── Chorus.swift
│ │ │ │ ├── Compressor.swift
│ │ │ │ ├── Convolution.swift
│ │ │ │ ├── Delay.swift
│ │ │ │ ├── DynamicRangeCompressor.swift
│ │ │ │ ├── Expander.swift
│ │ │ │ ├── Flanger.swift
│ │ │ │ ├── MultiTapDelay.swift
│ │ │ │ ├── Panner.swift
│ │ │ │ ├── PeakLimiter.swift
│ │ │ │ ├── PhaseLockedVocoder.swift
│ │ │ │ ├── Phaser.swift
│ │ │ │ ├── PitchShifter.swift
│ │ │ │ ├── PlaybackSpeed.swift
│ │ │ │ ├── StereoDelay.swift
│ │ │ │ ├── StringResonator.swift
│ │ │ │ ├── Talkbox.swift
│ │ │ │ ├── TimePitch.swift
│ │ │ │ ├── TransientShaper.swift
│ │ │ │ ├── Tremolo.swift
│ │ │ │ ├── VariableDelay.swift
│ │ │ │ └── Vocoder.swift
│ │ │ ├── Filters
│ │ │ │ ├── BandPassButterworthFilter.swift
│ │ │ │ ├── BandRejectButterworthFilter.swift
│ │ │ │ ├── CombFilterReverb.swift
│ │ │ │ ├── EqualizerFilter.swift
│ │ │ │ ├── FormantFilter.swift
│ │ │ │ ├── HighPassButterworthFilter.swift
│ │ │ │ ├── HighPassFilter.swift
│ │ │ │ ├── HighShelfFilter.swift
│ │ │ │ ├── HighShelfParametricEqualizerFilter.swift
│ │ │ │ ├── KorgLowPassFilter.swift
│ │ │ │ ├── LowPassButterworthFilter.swift
│ │ │ │ ├── LowPassFilter.swift
│ │ │ │ ├── LowShelfFilter.swift
│ │ │ │ ├── LowShelfParametricEqualizerFilter.swift
│ │ │ │ ├── ModalResonanceFilter.swift
│ │ │ │ ├── MoogLadder.swift
│ │ │ │ ├── PeakingParametricEqualizerFilter.swift
│ │ │ │ ├── ResonantFilter.swift
│ │ │ │ ├── ThreePoleLowpassFilter.swift
│ │ │ │ ├── ToneComplementFilter.swift
│ │ │ │ └── ToneFilter.swift
│ │ │ ├── MiniApps
│ │ │ │ ├── Arpeggiator.swift
│ │ │ │ ├── Audio3D.swift
│ │ │ │ ├── DrumSequencer.swift
│ │ │ │ ├── DrumSynthesizers.swift
│ │ │ │ ├── Drums.swift
│ │ │ │ ├── GraphicEqualizer.swift
│ │ │ │ ├── InstrumentEXS.swift
│ │ │ │ ├── InstrumentSFZ.swift
│ │ │ │ ├── MIDIMonitor.swift
│ │ │ │ ├── MIDITrack.swift
│ │ │ │ ├── MusicToy.swift
│ │ │ │ ├── NoiseGenerators.swift
│ │ │ │ ├── Recorder.swift
│ │ │ │ ├── SpriteKitAudio.swift
│ │ │ │ ├── Telephone.swift
│ │ │ │ ├── Tuner.swift
│ │ │ │ └── VocalTract.swift
│ │ │ ├── Operations
│ │ │ │ ├── CrossingSignal.swift
│ │ │ │ ├── DroneOperation.swift
│ │ │ │ ├── InstrumentOperation.swift
│ │ │ │ ├── LFOOperation.swift
│ │ │ │ ├── PhasorOperation.swift
│ │ │ │ ├── PitchShfitOperation.swift
│ │ │ │ ├── SegmentOperation.swift
│ │ │ │ ├── SmoothDelayOperation.swift
│ │ │ │ ├── StereoDelayOperation.swift
│ │ │ │ ├── StereoOperation.swift
│ │ │ │ ├── VariableDelayOperation.swift
│ │ │ │ └── VocalTractOperation.swift
│ │ │ ├── Oscillators
│ │ │ │ ├── AmplitudeEnvelope.swift
│ │ │ │ ├── DynamicOscillator.swift
│ │ │ │ ├── FMOscillator.swift
│ │ │ │ ├── MorphingOscillator.swift
│ │ │ │ ├── Oscillator.swift
│ │ │ │ ├── PWMOscillator.swift
│ │ │ │ └── PhaseDistortionOscillator.swift
│ │ │ ├── PhysicalModels
│ │ │ │ └── PluckedString.swift
│ │ │ ├── Reverbs
│ │ │ │ ├── ChowningReverb.swift
│ │ │ │ ├── CostelloReverb.swift
│ │ │ │ ├── FlatFrequencyResponseReverb.swift
│ │ │ │ ├── Reverb.swift
│ │ │ │ └── ZitaReverb.swift
│ │ │ ├── UncategorizedDemos
│ │ │ │ ├── AudioFileView.swift
│ │ │ │ ├── CallbackInstrument.swift
│ │ │ │ └── Table.swift
│ │ │ └── WIP
│ │ │ │ ├── BaseTapDemo.swift
│ │ │ │ ├── ChannelDeviceRouting.swift
│ │ │ │ ├── DunneSynth.swift
│ │ │ │ ├── InputDeviceDemo.swift
│ │ │ │ ├── MIDIPortTest.swift
│ │ │ │ ├── MIDIPortTestConductor.swift
│ │ │ │ ├── PolyphonicOscillator.swift
│ │ │ │ ├── PolyphonicSTK+MIDIKit.swift
│ │ │ │ └── RolandTB303Filter.swift
│ │ │ ├── Reusable Components
│ │ │ ├── CallbackLoop.swift
│ │ │ ├── Cookbook.swift
│ │ │ ├── CookbookKeyboard.swift
│ │ │ ├── CookbookKnob.swift
│ │ │ ├── NavigationHelpers.swift
│ │ │ ├── ParameterRow.swift
│ │ │ └── PlayerControls.swift
│ │ │ ├── Samples
│ │ │ ├── Bass Synth.mp3
│ │ │ ├── Counting.mp3
│ │ │ ├── Guitar.mp3
│ │ │ ├── Piano.mp3
│ │ │ ├── Strings.mp3
│ │ │ ├── Synth.mp3
│ │ │ ├── alphabet.mp3
│ │ │ ├── bass_drum_C1.wav
│ │ │ ├── beat.aiff
│ │ │ ├── clap_D#1.wav
│ │ │ ├── closed_hi_hat_F#1.wav
│ │ │ ├── hi_tom_D2.wav
│ │ │ ├── lo_tom_F1.wav
│ │ │ ├── mid_tom_B1.wav
│ │ │ ├── open_hi_hat_A#1.wav
│ │ │ └── snare_D1.wav
│ │ │ └── TestAudioURLs.swift
│ └── Tests
│ │ └── CookbookCommonTests
│ │ └── CookbookCommonTests.swift
└── Sounds
│ ├── Sampler Instruments
│ ├── drumSimp.exs
│ ├── funkyWow.exs
│ ├── nes-syn1.exs
│ ├── noisyRez.exs
│ ├── sawPad1.exs
│ ├── sawPiano1.exs
│ └── sqrTone1.exs
│ ├── basicSamples
│ ├── noise-wht2.wav
│ ├── saw220-ana1.wav
│ ├── saw220.wav
│ └── sqr220.wav
│ ├── cheeb-bd.wav
│ ├── cheeb-ch.wav
│ ├── cheeb-hat.wav
│ ├── cheeb-snr.wav
│ ├── cheeb-stick.wav
│ ├── closed_hi_hat_F#1.wav
│ └── sqr.SFZ
├── LICENSE
├── README.md
├── Xcode-config
├── DEVELOPMENT_TEAM.template.xcconfig
└── Shared.xcconfig
└── images
├── Cookbook.png
├── Cookbook2.png
└── CookbookMac.png
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | # GitHub Actions for AudioKit Cookbook
2 | name: CI
3 |
4 | on: [push, pull_request]
5 | env:
6 | XCODE_VER: 14.2
7 |
8 | jobs:
9 | build:
10 | strategy:
11 | matrix:
12 | xcode_version: ['14.2']
13 | runs-on: macos-12
14 | env:
15 | DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode_version }}.app
16 | steps:
17 | - name: Check out AudioKit Cookbook
18 | uses: actions/checkout@v2
19 | - name: Build AudioKit Cookbook
20 | run: |
21 | set -euo pipefail
22 | xcodebuild -project Cookbook/Cookbook.xcodeproj -sdk iphonesimulator -scheme Cookbook -arch x86_64 ONLY_ACTIVE_ARCH=YES CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY="" clean build | xcpretty -c
23 |
24 | # Send notification to Discord on failure.
25 | send_notification:
26 | name: Send Notification
27 | uses: AudioKit/ci/.github/workflows/send_notification.yml@main
28 | needs: [build]
29 | if: ${{ failure() && github.ref == 'refs/heads/main' }}
30 | secrets: inherit
31 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## User settings
6 | xcuserdata/
7 |
8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
9 | *.xcscmblueprint
10 | *.xccheckout
11 |
12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
13 | build/
14 | DerivedData/
15 | *.moved-aside
16 | *.pbxuser
17 | !default.pbxuser
18 | *.mode1v3
19 | !default.mode1v3
20 | *.mode2v3
21 | !default.mode2v3
22 | *.perspectivev3
23 | !default.perspectivev3
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 |
28 | ## App packaging
29 | *.ipa
30 | *.dSYM.zip
31 | *.dSYM
32 |
33 | ## Playgrounds
34 | timeline.xctimeline
35 | playground.xcworkspace
36 |
37 | # Swift Package Manager
38 | #
39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
40 | # Packages/
41 | # Package.pins
42 | # Package.resolved
43 | # *.xcodeproj
44 | #
45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
46 | # hence it is not needed unless you have added a package configuration file to your project
47 | # .swiftpm
48 |
49 | .build/
50 |
51 | # CocoaPods
52 | #
53 | # We recommend against adding the Pods directory to your .gitignore. However
54 | # you should judge for yourself, the pros and cons are mentioned at:
55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
56 | #
57 | # Pods/
58 | #
59 | # Add this line if you want to avoid checking in source code from the Xcode workspace
60 | # *.xcworkspace
61 |
62 | # Carthage
63 | #
64 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
65 | # Carthage/Checkouts
66 |
67 | Carthage/Build/
68 |
69 | # Accio dependency management
70 | Dependencies/
71 | .accio/
72 |
73 | # fastlane
74 | #
75 | # It is recommended to not store the screenshots in the git repo.
76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed.
77 | # For more information about the recommended setup visit:
78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
79 |
80 | fastlane/report.xml
81 | fastlane/Preview.html
82 | fastlane/screenshots/**/*.png
83 | fastlane/test_output
84 |
85 | # Code Injection
86 | #
87 | # After new code Injection tools there's a generated folder /iOSInjectionProject
88 | # https://github.com/johnno1962/injectionforxcode
89 |
90 | iOSInjectionProject/
91 |
92 | .DS_Store
93 |
94 | # User-specific xcconfig files
95 | Xcode-config/DEVELOPMENT_TEAM.xcconfig
96 |
97 | Package.resolved
--------------------------------------------------------------------------------
/Cookbook.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Cookbook.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Cookbook/Configuration/SampleCode.xcconfig:
--------------------------------------------------------------------------------
1 | // The `SAMPLE_CODE_DISAMBIGUATOR` configuration is to make it easier to build
2 | // and run a sample code project. Once you set your project's development team,
3 | // you'll have a unique bundle identifier. This is because the bundle identifier
4 | // is derived based on the 'SAMPLE_CODE_DISAMBIGUATOR' value. Do not use this
5 | // approach in your own projects—it's only useful for sample code projects because
6 | // they are frequently downloaded and don't have a development team set.
7 | SAMPLE_CODE_DISAMBIGUATOR=${DEVELOPMENT_TEAM}
8 |
--------------------------------------------------------------------------------
/Cookbook/Cookbook.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Cookbook/Cookbook.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-1024px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-1024px.png
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-120px-40pt@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-120px-40pt@3x.png
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-120px-60pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-120px-60pt@2x.png
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-152px-76pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-152px-76pt@2x.png
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-167px-83.5pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-167px-83.5pt@2x.png
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-180px-60pt@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-180px-60pt@3x.png
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-20px-20pt@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-20px-20pt@1x.png
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-29px-29pt@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-29px-29pt@1x.png
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-40px-20pt@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-40px-20pt@2x-1.png
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-40px-20pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-40px-20pt@2x.png
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-40px-40pt@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-40px-40pt@1x.png
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-58px-29pt@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-58px-29pt@2x-1.png
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-58px-29pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-58px-29pt@2x.png
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-60px-20pt@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-60px-20pt@3x.png
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-76px-76pt@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-76px-76pt@1x.png
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-80px-40pt@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-80px-40pt@2x-1.png
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-80px-40pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-80px-40pt@2x.png
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-87px-29pt@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Cookbook/Assets.xcassets/AppIcon.appiconset/AppIcon-87px-29pt@3x.png
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Assets.xcassets/audiokit-icon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "audiokit-icon.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "audiokit-icon2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "audiokit-icon@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Assets.xcassets/audiokit-icon.imageset/audiokit-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Cookbook/Assets.xcassets/audiokit-icon.imageset/audiokit-icon.png
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Assets.xcassets/audiokit-icon.imageset/audiokit-icon2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Cookbook/Assets.xcassets/audiokit-icon.imageset/audiokit-icon2x.png
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Assets.xcassets/audiokit-icon.imageset/audiokit-icon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Cookbook/Assets.xcassets/audiokit-icon.imageset/audiokit-icon@3x.png
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Assets.xcassets/audiokit-logo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "audiokit-logo.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Assets.xcassets/audiokit-logo.imageset/audiokit-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Cookbook/Assets.xcassets/audiokit-logo.imageset/audiokit-logo.png
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Cookbook.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.device.audio-input
8 |
9 | com.apple.security.files.user-selected.read-write
10 |
11 | com.apple.security.network.client
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Cookbook/Cookbook/CookbookApp.swift:
--------------------------------------------------------------------------------
1 | // Copyright AudioKit. All Rights Reserved.
2 |
3 | import AudioKit
4 | import AVFoundation
5 | import CookbookCommon
6 | import SwiftUI
7 |
8 | @main
9 | struct CookbookApp: App {
10 | init() {
11 | #if os(iOS)
12 | do {
13 | Settings.bufferLength = .short
14 |
15 | // Settings.sampleRate default is 44_100
16 | if #available(iOS 18.0, *) {
17 | if !ProcessInfo.processInfo.isMacCatalystApp && !ProcessInfo.processInfo.isiOSAppOnMac {
18 | // Set samplerRate for iOS 18 and newer
19 | Settings.sampleRate = 48_000
20 | }
21 | }
22 |
23 | try AVAudioSession.sharedInstance().setPreferredIOBufferDuration(Settings.bufferLength.duration)
24 | try AVAudioSession.sharedInstance().setCategory(.playAndRecord,
25 | options: [.defaultToSpeaker, .mixWithOthers, .allowBluetoothA2DP])
26 | try AVAudioSession.sharedInstance().setActive(true)
27 | } catch let err {
28 | print(err)
29 | }
30 | #endif
31 | }
32 |
33 | var body: some Scene {
34 | WindowGroup {
35 | ContentView()
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Cookbook/Cookbook/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSSpeechRecognitionUsageDescription
6 | We use Speech Recognition to demonstrate BaseTap capabilities.
7 | CFBundleDevelopmentRegion
8 | $(DEVELOPMENT_LANGUAGE)
9 | CFBundleDisplayName
10 | AudioKit
11 | CFBundleExecutable
12 | $(EXECUTABLE_NAME)
13 | CFBundleIdentifier
14 | $(PRODUCT_BUNDLE_IDENTIFIER)
15 | CFBundleInfoDictionaryVersion
16 | 6.0
17 | CFBundleName
18 | $(PRODUCT_NAME)
19 | CFBundlePackageType
20 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
21 | CFBundleShortVersionString
22 | 1.0
23 | CFBundleVersion
24 | 1
25 | LSRequiresIPhoneOS
26 |
27 | NSMicrophoneUsageDescription
28 | We use the microphone to demonstrate processing input.
29 | UIApplicationSceneManifest
30 |
31 | UIApplicationSupportsMultipleScenes
32 |
33 |
34 | UIApplicationSupportsIndirectInputEvents
35 |
36 | UIBackgroundModes
37 |
38 | audio
39 |
40 | UILaunchStoryboardName
41 | LaunchScreen
42 | UIRequiredDeviceCapabilities
43 |
44 | armv7
45 |
46 | UISupportedInterfaceOrientations
47 |
48 | UIInterfaceOrientationPortrait
49 | UIInterfaceOrientationLandscapeLeft
50 | UIInterfaceOrientationLandscapeRight
51 |
52 | UISupportedInterfaceOrientations~ipad
53 |
54 | UIInterfaceOrientationPortrait
55 | UIInterfaceOrientationPortraitUpsideDown
56 | UIInterfaceOrientationLandscapeLeft
57 | UIInterfaceOrientationLandscapeRight
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/Cookbook/Cookbook/audio3D.scnassets/audio3DTest.scn:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Cookbook/audio3D.scnassets/audio3DTest.scn
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.7
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "CookbookCommon",
7 | platforms: [.macOS(.v12), .iOS(.v16), .tvOS(.v15)],
8 | products: [.library(name: "CookbookCommon", targets: ["CookbookCommon"])],
9 | dependencies: [
10 | .package(url: "https://github.com/AudioKit/AudioKit", from: "5.6.4"),
11 | .package(url: "https://github.com/AudioKit/AudioKitUI", branch: "visionos"),
12 | .package(url: "https://github.com/AudioKit/AudioKitEX", from: "5.6.0"),
13 | .package(url: "https://github.com/AudioKit/Controls", from: "1.0.0"),
14 | .package(url: "https://github.com/AudioKit/DunneAudioKit", from: "5.6.0"),
15 | .package(url: "https://github.com/AudioKit/Keyboard", from: "1.3.0"),
16 | .package(url: "https://github.com/AudioKit/SoundpipeAudioKit", from: "5.7.1"),
17 | .package(url: "https://github.com/AudioKit/SporthAudioKit", from: "5.5.0"),
18 | .package(url: "https://github.com/AudioKit/STKAudioKit", from: "5.5.0"),
19 | .package(url: "https://github.com/AudioKit/Tonic", from: "1.0.0"),
20 | .package(url: "https://github.com/AudioKit/Waveform", branch: "visionos"),
21 | .package(url: "https://github.com/AudioKit/Flow", from: "1.0.0"),
22 | .package(url: "https://github.com/AudioKit/PianoRoll", from: "1.0.0"),
23 | .package(url: "https://github.com/orchetect/MIDIKit", from: "0.9.7"),
24 | ],
25 | targets: [
26 | .target(
27 | name: "CookbookCommon",
28 | dependencies: ["AudioKit", "AudioKitUI", "AudioKitEX", "Keyboard", "SoundpipeAudioKit",
29 | "SporthAudioKit", "STKAudioKit", "DunneAudioKit", "Tonic", "Controls", "Waveform", "Flow", "PianoRoll", "MIDIKit"],
30 | resources: [
31 | .copy("MIDI Files"),
32 | .copy("Samples"),
33 | .copy("Impulse Responses"),
34 | ]
35 | ),
36 | .testTarget(name: "CookbookCommonTests", dependencies: ["CookbookCommon"]),
37 | ]
38 | )
39 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/README.md:
--------------------------------------------------------------------------------
1 | # CookbookCommon
2 |
3 | This contains the recipes so that operating system-specific wrapper applications can be made.
4 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/About AudioKit/AboutAudioKitContentView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | struct AboutAudioKitContentView: View {
4 | private let maxWidth: CGFloat = 200
5 | var stackSpacing: CGFloat
6 |
7 | var body: some View {
8 | audioKitArtwork
9 | audioKitText
10 | }
11 |
12 | private var audioKitArtwork: some View {
13 | return VStack(spacing: stackSpacing) {
14 | Image("audiokit-icon")
15 | .resizable()
16 | .aspectRatio(contentMode: .fit)
17 | .frame(maxWidth: maxWidth)
18 | Image("audiokit-logo")
19 | .resizable()
20 | .aspectRatio(contentMode: .fit)
21 | .frame(maxWidth: maxWidth)
22 | }
23 | }
24 |
25 | private var audioKitText: some View {
26 | Text("AudioKit is an audio synthesis, processing, and analysis platform for iOS, macOS, and tvOS.\n\nMost of the examples that were inside of AudioKit are now in this application.\n\nIn addition to the resources found here, there are various open-source example projects on GitHub and YouTube created by AudioKit contributors.")
27 | .padding()
28 | }
29 | }
30 |
31 | #Preview {
32 | AboutAudioKitContentView(stackSpacing: 25)
33 | }
34 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/About AudioKit/AudioKitInfoView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | struct AudioKitInfoView: View {
4 | @Environment(\.dismiss) var dismiss
5 | @Environment(\.verticalSizeClass) var verticalSizeClass
6 | @Environment(\.dynamicTypeSize) var dynamicTypeSize
7 | let stackSpacing: CGFloat = 25
8 | var body: some View {
9 | NavigationStack {
10 | ScrollView {
11 | if verticalSizeClass == .regular {
12 | VStack(spacing: stackSpacing) {
13 | AboutAudioKitContentView(stackSpacing: stackSpacing)
14 | }
15 | } else {
16 | HStack(spacing: stackSpacing) { AboutAudioKitContentView(stackSpacing: stackSpacing)
17 | }
18 | }
19 | }
20 | .toolbar {
21 | ToolbarItem(placement: .primaryAction) {
22 | Button {
23 | dismiss()
24 | } label: {
25 | Text("Done")
26 | .fontWeight(.semibold)
27 | }
28 | .accessibilityHint("Tap to close this screen.")
29 | }
30 | }
31 | }
32 | }
33 | }
34 |
35 | #Preview {
36 | AudioKitInfoView()
37 | }
38 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-1024px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-1024px.png
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-120px-40pt@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-120px-40pt@3x.png
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-120px-60pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-120px-60pt@2x.png
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-152px-76pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-152px-76pt@2x.png
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-167px-83.5pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-167px-83.5pt@2x.png
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-180px-60pt@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-180px-60pt@3x.png
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-20px-20pt@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-20px-20pt@1x.png
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-29px-29pt@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-29px-29pt@1x.png
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-40px-20pt@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-40px-20pt@2x-1.png
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-40px-20pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-40px-20pt@2x.png
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-40px-40pt@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-40px-40pt@1x.png
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-58px-29pt@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-58px-29pt@2x-1.png
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-58px-29pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-58px-29pt@2x.png
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-60px-20pt@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-60px-20pt@3x.png
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-76px-76pt@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-76px-76pt@1x.png
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-80px-40pt@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-80px-40pt@2x-1.png
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-80px-40pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-80px-40pt@2x.png
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-87px-29pt@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/AppIcon.appiconset/AppIcon-87px-29pt@3x.png
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/audiokit-icon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "audiokit-icon.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "audiokit-icon2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "audiokit-icon@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/audiokit-icon.imageset/audiokit-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/audiokit-icon.imageset/audiokit-icon.png
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/audiokit-icon.imageset/audiokit-icon2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/audiokit-icon.imageset/audiokit-icon2x.png
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/audiokit-icon.imageset/audiokit-icon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/audiokit-icon.imageset/audiokit-icon@3x.png
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/audiokit-logo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "audiokit-logo.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/audiokit-logo.imageset/audiokit-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Assets.xcassets/audiokit-logo.imageset/audiokit-logo.png
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Colors.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0.860",
9 | "green" : "0.500",
10 | "red" : "0.000"
11 | }
12 | },
13 | "idiom" : "universal"
14 | },
15 | {
16 | "appearances" : [
17 | {
18 | "appearance" : "luminosity",
19 | "value" : "dark"
20 | }
21 | ],
22 | "color" : {
23 | "color-space" : "srgb",
24 | "components" : {
25 | "alpha" : "1.000",
26 | "blue" : "1.000",
27 | "green" : "0.766",
28 | "red" : "0.249"
29 | }
30 | },
31 | "idiom" : "universal"
32 | }
33 | ],
34 | "info" : {
35 | "author" : "xcode",
36 | "version" : 1
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Colors.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Colors.xcassets/FontColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | },
6 | "colors" : [
7 | {
8 | "idiom" : "universal",
9 | "color" : {
10 | "color-space" : "srgb",
11 | "components" : {
12 | "red" : "1.000",
13 | "alpha" : "1.000",
14 | "blue" : "1.000",
15 | "green" : "1.000"
16 | }
17 | }
18 | },
19 | {
20 | "idiom" : "universal",
21 | "appearances" : [
22 | {
23 | "appearance" : "luminosity",
24 | "value" : "light"
25 | }
26 | ],
27 | "color" : {
28 | "color-space" : "srgb",
29 | "components" : {
30 | "red" : "1.000",
31 | "alpha" : "1.000",
32 | "blue" : "1.000",
33 | "green" : "1.000"
34 | }
35 | }
36 | },
37 | {
38 | "idiom" : "universal",
39 | "appearances" : [
40 | {
41 | "appearance" : "luminosity",
42 | "value" : "dark"
43 | }
44 | ],
45 | "color" : {
46 | "color-space" : "srgb",
47 | "components" : {
48 | "red" : "0.000",
49 | "alpha" : "1.000",
50 | "blue" : "0.000",
51 | "green" : "0.000"
52 | }
53 | }
54 | }
55 | ]
56 | }
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/CookbookCommon.swift:
--------------------------------------------------------------------------------
1 | public struct CookbookCommon {
2 | public private(set) var text = "Hello, World!"
3 |
4 | public init() {}
5 | }
6 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Impulse Responses/dish.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Impulse Responses/dish.wav
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Impulse Responses/stairwell.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Impulse Responses/stairwell.wav
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/MIDI Files/4tracks.mid:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/MIDI Files/4tracks.mid
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/MIDI Files/Demo.mid:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/MIDI Files/Demo.mid
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/AdditionalPackages/FlowView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 | import Flow
3 |
4 | func simplePatch() -> Patch {
5 | let generator = Node(name: "generator", titleBarColor: Color.cyan, outputs: ["out"])
6 | let processor = Node(name: "processor", titleBarColor: Color.red, inputs: ["in"], outputs: ["out"])
7 | let mixer = Node(name: "mixer", titleBarColor: Color.gray, inputs: ["in1", "in2"], outputs: ["out"])
8 | let output = Node(name: "output", titleBarColor: Color.purple, inputs: ["in"])
9 |
10 | let nodes = [generator, processor, generator, processor, mixer, output]
11 |
12 | let wires = Set([Wire(from: OutputID(0, 0), to: InputID(1, 0)),
13 | Wire(from: OutputID(1, 0), to: InputID(4, 0)),
14 | Wire(from: OutputID(2, 0), to: InputID(3, 0)),
15 | Wire(from: OutputID(3, 0), to: InputID(4, 1)),
16 | Wire(from: OutputID(4, 0), to: InputID(5, 0))])
17 |
18 | var patch = Patch(nodes: nodes, wires: wires)
19 | patch.recursiveLayout(nodeIndex: 5, at: CGPoint(x: 800, y: 50))
20 | return patch
21 | }
22 |
23 | /// Bit of a stress test to show how Flow performs with more nodes.
24 | func randomPatch() -> Patch {
25 | var randomNodes: [Node] = []
26 | for n in 0 ..< 50 {
27 | let randomPoint = CGPoint(x: 1000 * Double.random(in: 0 ... 1),
28 | y: 1000 * Double.random(in: 0 ... 1))
29 | randomNodes.append(Node(name: "node\(n)",
30 | position: randomPoint,
31 | inputs: ["In"],
32 | outputs: ["Out"]))
33 | }
34 |
35 | var randomWires: Set = []
36 | for n in 0 ..< 50 {
37 | randomWires.insert(Wire(from: OutputID(n, 0), to: InputID(Int.random(in: 0 ... 49), 0)))
38 | }
39 | return Patch(nodes: randomNodes, wires: randomWires)
40 | }
41 |
42 | struct FlowView: View {
43 | @State var patch = simplePatch()
44 | @State var selection = Set()
45 |
46 | var body: some View {
47 | NodeEditor(patch: $patch, selection: $selection)
48 | .navigationTitle("Flow Demo")
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/AdditionalPackages/PianoRollView.swift:
--------------------------------------------------------------------------------
1 | // Copyright AudioKit. All Rights Reserved. Revision History at http://github.com/AudioKit/AudioKitUI/
2 |
3 | import PianoRoll
4 | import SwiftUI
5 |
6 | public struct PianoRollView: View {
7 | public init() {}
8 |
9 | @State var model = PianoRollModel(notes: [
10 | PianoRollNote(start: 1, length: 2, pitch: 3),
11 | PianoRollNote(start: 5, length: 1, pitch: 4),
12 | ], length: 128, height: 128)
13 |
14 | public var body: some View {
15 | VStack(alignment: .leading) {
16 | Text("Tap inside of the scrolling grid to set a note.")
17 | .padding([.top, .horizontal])
18 | ScrollView([.horizontal, .vertical], showsIndicators: true) {
19 | PianoRoll(model: $model, noteColor: .cyan, gridColor: .primary, layout: .horizontal)
20 | }
21 | .padding()
22 | }
23 | .foregroundStyle(.primary)
24 | .navigationTitle("Piano Roll Demo")
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/AudioPlayer/AudioPlayerCompletionHandler.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AVFoundation
3 | import SwiftUI
4 |
5 | class CompletionHandlerConductor: ObservableObject, HasAudioEngine {
6 | let engine = AudioEngine()
7 | var player = AudioPlayer()
8 | var fileURL = [URL]()
9 | @Published var playDuration = 0.0
10 | var currentFileIndex = 0
11 |
12 | // Load the files to play
13 | func getPlayerFiles() {
14 | let files = ["Bass Synth.mp3", "Piano.mp3",
15 | "Synth.mp3", "Strings.mp3", "Guitar.mp3"]
16 | for filename in files {
17 | guard let url = Bundle.module.resourceURL?.appendingPathComponent(
18 | "Samples/\(filename)")
19 | else {
20 | Log("failed to load sample", filename)
21 | return
22 | }
23 | fileURL.append(url)
24 | }
25 | }
26 |
27 | /* Completion handler function:
28 | a function returning void */
29 | func playNextFile() {
30 | if currentFileIndex < 4 {
31 | currentFileIndex += 1
32 | } else {
33 | currentFileIndex = 0
34 | }
35 | startPlaying()
36 | }
37 |
38 | init() {
39 | getPlayerFiles()
40 | engine.output = player
41 |
42 | /* Assign the function
43 | to the completion handler */
44 | player.completionHandler = playNextFile
45 | }
46 |
47 | func startPlaying() {
48 | try? player.load(url: fileURL[currentFileIndex])
49 | player.play()
50 | if let duration = player.file?.duration {
51 | playDuration = duration
52 | }
53 | }
54 |
55 | }
56 |
57 | struct AudioPlayerCompletionHandler: View {
58 | @StateObject var conductor = CompletionHandlerConductor()
59 |
60 | var body: some View {
61 | Text("AudioPlayer Completion Handler")
62 | .padding()
63 | Text("This will play one file. Once it completes, it will play another.")
64 | Text("That's one thing a completion handler can do.")
65 | VStack {
66 | let playLabel = "Playing: " + conductor.fileURL[conductor.currentFileIndex]
67 | .deletingPathExtension().lastPathComponent
68 | let playTimeRange = Date()...Date().addingTimeInterval(conductor.playDuration)
69 | ProgressView(timerInterval: playTimeRange, countsDown: false) {
70 | Text(playLabel)
71 | }
72 | }
73 | .onAppear {
74 | conductor.start()
75 | conductor.startPlaying()
76 | }
77 | .onDisappear {
78 | conductor.stop()
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Distortion/BitCrusher.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class BitCrusherConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let bitcrusher: BitCrusher
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | bitcrusher = BitCrusher(player)
21 | dryWetMixer = DryWetMixer(player, bitcrusher)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct BitCrusherView: View {
27 | @StateObject var conductor = BitCrusherConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.bitcrusher.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.bitcrusher,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Bit Crusher")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Distortion/Clipper.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class ClipperConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let clipper: Clipper
12 | let amplifier: Fader
13 | let dryWetMixer: DryWetMixer
14 | let buffer: AVAudioPCMBuffer
15 |
16 | init() {
17 | buffer = Cookbook.sourceBuffer
18 | player.buffer = buffer
19 | player.isLooping = true
20 |
21 | clipper = Clipper(player)
22 | amplifier = Fader(clipper)
23 | dryWetMixer = DryWetMixer(player, amplifier)
24 | engine.output = dryWetMixer
25 | }
26 | }
27 |
28 | struct ClipperView: View {
29 | @StateObject var conductor = ClipperConductor()
30 |
31 | var body: some View {
32 | VStack {
33 | PlayerControls(conductor: conductor)
34 | HStack {
35 | ForEach(conductor.clipper.parameters) {
36 | ParameterRow(param: $0)
37 | }
38 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
39 | }
40 | DryWetMixView(dry: conductor.player,
41 | wet: conductor.clipper,
42 | mix: conductor.dryWetMixer)
43 | }
44 | .padding()
45 | .cookbookNavBarTitle("Clipper")
46 | .onAppear {
47 | conductor.start()
48 | }
49 | .onDisappear {
50 | conductor.stop()
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Distortion/Decimator.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | //: Decimation is a type of digital distortion like bit crushing,
9 | //: but instead of directly stating what bit depth and sample rate you want,
10 | //: it is done through setting "decimation" and "rounding" parameters.
11 |
12 | class DecimatorConductor: ObservableObject, ProcessesPlayerInput {
13 | let engine = AudioEngine()
14 | let player = AudioPlayer()
15 | let decimator: Decimator
16 | let dryWetMixer: DryWetMixer
17 | let buffer: AVAudioPCMBuffer
18 |
19 | init() {
20 | buffer = Cookbook.sourceBuffer
21 | player.buffer = buffer
22 | player.isLooping = true
23 |
24 | decimator = Decimator(player)
25 | decimator.finalMix = 100
26 | dryWetMixer = DryWetMixer(player, decimator)
27 | engine.output = dryWetMixer
28 | }
29 | }
30 |
31 | struct DecimatorView: View {
32 | @StateObject var conductor = DecimatorConductor()
33 |
34 | var body: some View {
35 | VStack {
36 | PlayerControls(conductor: conductor)
37 | HStack {
38 | ForEach(conductor.decimator.parameters) {
39 | ParameterRow(param: $0)
40 | }
41 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
42 | }
43 | DryWetMixView(dry: conductor.player,
44 | wet: conductor.decimator,
45 | mix: conductor.dryWetMixer)
46 | }
47 | .padding()
48 | .cookbookNavBarTitle("Decimator")
49 | .onAppear {
50 | conductor.start()
51 | }
52 | .onDisappear {
53 | conductor.stop()
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Distortion/RingModulator.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class RingModulatorConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let ringModulator: RingModulator
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | ringModulator = RingModulator(player)
21 | dryWetMixer = DryWetMixer(player, ringModulator)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct RingModulatorView: View {
27 | @StateObject var conductor = RingModulatorConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.ringModulator.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.ringModulator,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Ring Modulator")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Distortion/TanhDistortion.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class TanhDistortionConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let distortion: TanhDistortion
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | distortion = TanhDistortion(player)
21 | dryWetMixer = DryWetMixer(player, distortion)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct TanhDistortionView: View {
27 | @StateObject var conductor = TanhDistortionConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.distortion.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.distortion,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Tanh Distortion")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Effects/AutoPanner.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class AutoPannerConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let panner: AutoPanner
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | panner = AutoPanner(player)
21 | dryWetMixer = DryWetMixer(player, panner)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct AutoPannerView: View {
27 | @StateObject var conductor = AutoPannerConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.panner.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.panner,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Auto Panner")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Effects/AutoWah.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class AutoWahConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let autowah: AutoWah
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | autowah = AutoWah(player)
21 | dryWetMixer = DryWetMixer(player, autowah)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct AutoWahView: View {
27 | @StateObject var conductor = AutoWahConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.autowah.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.autowah,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Auto Wah")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Effects/Balancer.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import Controls
6 | import SoundpipeAudioKit
7 | import SwiftUI
8 |
9 | class BalancerConductor: ObservableObject, ProcessesPlayerInput {
10 | let engine = AudioEngine()
11 | let player = AudioPlayer()
12 | let buffer: AVAudioPCMBuffer
13 | let balancer: Balancer
14 | let variSpeed: VariSpeed
15 | let osc = Oscillator()
16 | let dryWetMixer: DryWetMixer
17 |
18 | @Published var frequency: AUValue = 440 {
19 | didSet {
20 | osc.$frequency.ramp(to: frequency, duration: 0.5)
21 | }
22 | }
23 |
24 | @Published var rate: AUValue = 1 {
25 | didSet {
26 | variSpeed.rate = rate
27 | }
28 | }
29 |
30 | @Published var balance: AUValue = 0.5 {
31 | didSet {
32 | dryWetMixer.balance = balance
33 | }
34 | }
35 |
36 | init() {
37 | buffer = Cookbook.sourceBuffer
38 | player.buffer = buffer
39 | player.isLooping = true
40 |
41 | osc.play()
42 | variSpeed = VariSpeed(player)
43 | let fader = Fader(variSpeed)
44 | balancer = Balancer(osc, comparator: fader)
45 | dryWetMixer = DryWetMixer(fader, balancer)
46 | engine.output = dryWetMixer
47 | }
48 | }
49 |
50 | struct BalancerView: View {
51 | @StateObject var conductor = BalancerConductor()
52 |
53 | var body: some View {
54 | VStack {
55 | PlayerControls(conductor: conductor)
56 | HStack {
57 | CookbookKnob(text: "Rate", parameter: $conductor.rate, range: 0.3125 ... 5)
58 | CookbookKnob(text: "Frequency", parameter: $conductor.frequency, range: 220 ... 880)
59 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
60 | }
61 | DryWetMixView(dry: conductor.player,
62 | wet: conductor.balancer,
63 | mix: conductor.dryWetMixer)
64 | }
65 | .padding()
66 | .cookbookNavBarTitle("Balancer")
67 | .onAppear {
68 | conductor.start()
69 | }
70 | .onDisappear {
71 | conductor.stop()
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Effects/Chorus.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import DunneAudioKit
6 | import SoundpipeAudioKit
7 | import SwiftUI
8 |
9 | class ChorusConductor: ObservableObject, ProcessesPlayerInput {
10 | let engine = AudioEngine()
11 | let player = AudioPlayer()
12 | let chorus: Chorus
13 | var dryWetMixer: DryWetMixer
14 | let buffer: AVAudioPCMBuffer
15 |
16 | init() {
17 | buffer = Cookbook.sourceBuffer
18 | player.buffer = buffer
19 | player.isLooping = true
20 |
21 | chorus = Chorus(player)
22 | dryWetMixer = DryWetMixer(player, chorus)
23 | engine.output = dryWetMixer
24 | }
25 | }
26 |
27 | struct ChorusView: View {
28 | @StateObject var conductor = ChorusConductor()
29 |
30 | var body: some View {
31 | VStack {
32 | PlayerControls(conductor: conductor)
33 | HStack {
34 | ForEach(conductor.chorus.parameters) {
35 | ParameterRow(param: $0)
36 | }
37 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
38 | }
39 | DryWetMixView(dry: conductor.player,
40 | wet: conductor.chorus,
41 | mix: conductor.dryWetMixer)
42 | }
43 | .padding()
44 | .cookbookNavBarTitle("Chorus")
45 | .onAppear {
46 | conductor.start()
47 | }
48 | .onDisappear {
49 | conductor.stop()
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Effects/Compressor.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class CompressorConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let compressor: Compressor
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | compressor = Compressor(player)
21 | dryWetMixer = DryWetMixer(player, compressor)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct CompressorView: View {
27 | @StateObject var conductor = CompressorConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.compressor.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player, wet: conductor.compressor, mix: conductor.dryWetMixer)
39 | }
40 | .padding()
41 | .cookbookNavBarTitle("Compressor")
42 | .onAppear {
43 | conductor.start()
44 | }
45 | .onDisappear {
46 | conductor.stop()
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Effects/Delay.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | // It's very common to mix exactly two inputs, one before processing occurs,
9 | // and one after, resulting in a combination of the two. This is so common
10 | // that many of the AudioKit nodes have a dry/wet mix parameter built in.
11 | // But, if you are building your own custom effects, or making a long chain
12 | // of effects, you can use DryWetMixer to blend your signals.
13 |
14 | class DelayConductor: ObservableObject, ProcessesPlayerInput {
15 | let engine = AudioEngine()
16 | let player = AudioPlayer()
17 | let delay: Delay
18 | let dryWetMixer: DryWetMixer
19 | let buffer: AVAudioPCMBuffer
20 |
21 | init() {
22 | buffer = Cookbook.sourceBuffer
23 | player.buffer = buffer
24 | player.isLooping = true
25 |
26 | delay = Delay(player)
27 | delay.feedback = 0.9
28 | delay.time = 0.01
29 |
30 | // We're not using delay's built in dry wet mix because
31 | // we are tapping the wet result so it can be plotted.
32 | delay.dryWetMix = 100
33 | dryWetMixer = DryWetMixer(player, delay)
34 | engine.output = dryWetMixer
35 | }
36 | }
37 |
38 | struct DelayView: View {
39 | @StateObject var conductor = DelayConductor()
40 |
41 | var body: some View {
42 | VStack {
43 | PlayerControls(conductor: conductor)
44 | HStack {
45 | ForEach(conductor.delay.parameters) {
46 | ParameterRow(param: $0)
47 | }
48 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
49 | }
50 | DryWetMixView(dry: conductor.player,
51 | wet: conductor.delay,
52 | mix: conductor.dryWetMixer)
53 | }
54 | .padding()
55 | .cookbookNavBarTitle("Delay")
56 | .onAppear {
57 | conductor.start()
58 | }
59 | .onDisappear {
60 | conductor.stop()
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Effects/DynamicRangeCompressor.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class DynamicRangeCompressorConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let compressor: DynamicRangeCompressor
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | compressor = DynamicRangeCompressor(player)
21 | dryWetMixer = DryWetMixer(player, compressor)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct DynamicRangeCompressorView: View {
27 | @StateObject var conductor = DynamicRangeCompressorConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.compressor.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.compressor,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Dynamic Range Compressor")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Effects/Expander.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class ExpanderConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let expander: Expander
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | expander = Expander(player)
21 | dryWetMixer = DryWetMixer(player, expander)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct ExpanderView: View {
27 | @StateObject var conductor = ExpanderConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.expander.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.expander,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Expander")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Effects/Flanger.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import DunneAudioKit
6 | import SoundpipeAudioKit
7 | import SwiftUI
8 |
9 | class FlangerConductor: ObservableObject, ProcessesPlayerInput {
10 | let engine = AudioEngine()
11 | let player = AudioPlayer()
12 | let flanger: Flanger
13 | let dryWetMixer: DryWetMixer
14 | let buffer: AVAudioPCMBuffer
15 |
16 | init() {
17 | buffer = Cookbook.sourceBuffer
18 | player.buffer = buffer
19 | player.isLooping = true
20 |
21 | flanger = Flanger(player)
22 | dryWetMixer = DryWetMixer(player, flanger)
23 | engine.output = dryWetMixer
24 | }
25 | }
26 |
27 | struct FlangerView: View {
28 | @StateObject var conductor = FlangerConductor()
29 |
30 | var body: some View {
31 | VStack {
32 | PlayerControls(conductor: conductor)
33 | HStack {
34 | ForEach(conductor.flanger.parameters) {
35 | ParameterRow(param: $0)
36 | }
37 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
38 | }
39 | DryWetMixView(dry: conductor.player,
40 | wet: conductor.flanger,
41 | mix: conductor.dryWetMixer)
42 | }
43 | .padding()
44 | .cookbookNavBarTitle("Flanger")
45 | .onAppear {
46 | conductor.start()
47 | }
48 | .onDisappear {
49 | conductor.stop()
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Effects/MultiTapDelay.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | //: ## Multi-tap Delay
9 | //: A multi-tap delay is a delay line where multiple 'taps' or outputs are
10 | //: taken from a delay buffer at different points, and the taps are then
11 | //: summed with the original. Multi-tap delays are great for creating
12 | //: rhythmic delay patterns, but they can also be used to create sound
13 | //: fields of such density that they start to take on some of the qualities
14 | //: we'd more usually associate with reverb. - Geoff Smith, Sound on Sound
15 |
16 | class MultiTapDelayConductor: ObservableObject, ProcessesPlayerInput {
17 | let engine = AudioEngine()
18 | let player = AudioPlayer()
19 | let buffer: AVAudioPCMBuffer
20 |
21 | init() {
22 | buffer = Cookbook.sourceBuffer
23 | player.buffer = buffer
24 | player.isLooping = true
25 |
26 | var delays = [VariableDelay]()
27 |
28 | func multitapDelay(_ input: Node, times: [AUValue], gains: [AUValue]) -> Mixer {
29 | let mix = Mixer(input)
30 | var counter = 0
31 | zip(times, gains).forEach { time, gain in
32 | delays.append(VariableDelay(input, time: time))
33 | mix.addInput(Fader(delays[counter], gain: gain))
34 | counter += 1
35 | }
36 | return mix
37 | }
38 |
39 | engine.output = multitapDelay(player, times: [0.1, 0.2, 0.4], gains: [0.5, 2.0, 0.5])
40 | }
41 | }
42 |
43 | struct MultiTapDelayView: View {
44 | @StateObject var conductor = MultiTapDelayConductor()
45 |
46 | var body: some View {
47 | VStack(spacing: 20) {
48 | Text("""
49 | A multi-tap delay is a delay line where multiple 'taps' or outputs are taken from a delay buffer at different points, and the taps are then summed with the original. Multi-tap delays are great for creating rhythmic delay patterns, but they can also be used to create sound fields of such density that they start to take on some of the qualities we'd more usually associate with reverb.
50 |
51 | - Geoff Smith, Sound on Sound
52 | """)
53 | PlayerControls(conductor: conductor)
54 | }
55 | .padding()
56 | .cookbookNavBarTitle("MultiTap Delay Operation")
57 | .onAppear {
58 | conductor.start()
59 | }
60 | .onDisappear {
61 | conductor.stop()
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Effects/Panner.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class PannerConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let panner: Panner
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | panner = Panner(player)
21 | dryWetMixer = DryWetMixer(player, panner)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct PannerView: View {
27 | @StateObject var conductor = PannerConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.panner.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.panner,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Panner")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Effects/PeakLimiter.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | //: A peak limiter will set a hard limit on the amplitude of an audio signal.
9 | //: They're especially useful for any type of live input processing, when you
10 | //: may not be in total control of the audio signal you're recording or processing.
11 |
12 | class PeakLimiterConductor: ObservableObject, ProcessesPlayerInput {
13 | let engine = AudioEngine()
14 | let player = AudioPlayer()
15 | let peakLimiter: PeakLimiter
16 | let dryWetMixer: DryWetMixer
17 | let buffer: AVAudioPCMBuffer
18 |
19 | init() {
20 | buffer = Cookbook.sourceBuffer
21 | player.buffer = buffer
22 | player.isLooping = true
23 |
24 | peakLimiter = PeakLimiter(player)
25 | dryWetMixer = DryWetMixer(player, peakLimiter)
26 | engine.output = dryWetMixer
27 | }
28 | }
29 |
30 | struct PeakLimiterView: View {
31 | @StateObject var conductor = PeakLimiterConductor()
32 |
33 | var body: some View {
34 | VStack {
35 | PlayerControls(conductor: conductor)
36 | HStack {
37 | ForEach(conductor.peakLimiter.parameters) {
38 | ParameterRow(param: $0)
39 | }
40 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
41 | }
42 | DryWetMixView(dry: conductor.player,
43 | wet: conductor.peakLimiter,
44 | mix: conductor.dryWetMixer)
45 | }
46 | .padding()
47 | .cookbookNavBarTitle("PeakLimiter")
48 | .onAppear {
49 | conductor.start()
50 | }
51 | .onDisappear {
52 | conductor.stop()
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Effects/PhaseLockedVocoder.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import Controls
5 | import AVFoundation
6 | import SoundpipeAudioKit
7 | import SwiftUI
8 |
9 | class PhaseLockedVocoderConductor: ObservableObject, HasAudioEngine {
10 | @Published var position: Float = 0.0 {
11 | didSet {
12 | phaseLockedVocoder.position = position
13 | }
14 | }
15 |
16 | let engine = AudioEngine()
17 | var phaseLockedVocoder: PhaseLockedVocoder
18 |
19 | init() {
20 | let url = Bundle.module.resourceURL?.appendingPathComponent("Samples/beat.aiff")
21 | let file = try! AVAudioFile(forReading: url!)
22 | phaseLockedVocoder = PhaseLockedVocoder(file: file)
23 | phaseLockedVocoder.amplitude = 1
24 | phaseLockedVocoder.pitchRatio = 1
25 | phaseLockedVocoder.start()
26 | engine.output = phaseLockedVocoder
27 | }
28 | }
29 |
30 | struct PhaseLockedVocoderView: View {
31 | @StateObject var conductor = PhaseLockedVocoderConductor()
32 |
33 | var body: some View {
34 | VStack {
35 | Text("Position: \(conductor.position)")
36 | Ribbon(position: $conductor.position)
37 | .cornerRadius(10)
38 | .frame(height: 50)
39 | NodeOutputView(conductor.phaseLockedVocoder)
40 | }
41 | .padding()
42 | .cookbookNavBarTitle("Phase Locked Vocoder")
43 | .onAppear {
44 | conductor.start()
45 | }
46 | .onDisappear {
47 | conductor.stop()
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Effects/Phaser.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class PhaserConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let phaser: Phaser
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | phaser = Phaser(player)
21 | dryWetMixer = DryWetMixer(player, phaser)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct PhaserView: View {
27 | @StateObject var conductor = PhaserConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.phaser.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.phaser,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Phaser")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Effects/PitchShifter.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class PitchShifterConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let pitchshifter: PitchShifter
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | pitchshifter = PitchShifter(player)
21 | dryWetMixer = DryWetMixer(player, pitchshifter)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct PitchShifterView: View {
27 | @StateObject var conductor = PitchShifterConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.pitchshifter.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.pitchshifter,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Pitch Shifter")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Effects/PlaybackSpeed.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SwiftUI
6 |
7 | // This recipe uses the VariSpeed node to change the playback speed of a file (which also affects the pitch)
8 | class PlaybackSpeedConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let variSpeed: VariSpeed
12 | let buffer: AVAudioPCMBuffer
13 |
14 | init() {
15 | buffer = Cookbook.sourceBuffer
16 | player.buffer = buffer
17 | player.isLooping = true
18 |
19 | variSpeed = VariSpeed(player)
20 | variSpeed.rate = 2.0
21 | engine.output = variSpeed
22 | }
23 |
24 | @Published var rate: AUValue = 2.0 {
25 | didSet {
26 | variSpeed.rate = rate
27 | }
28 | }
29 | }
30 |
31 | struct PlaybackSpeedView: View {
32 | @StateObject var conductor = PlaybackSpeedConductor()
33 |
34 | var body: some View {
35 | VStack {
36 | PlayerControls(conductor: conductor)
37 | CookbookKnob(text: "Rate",
38 | parameter: $conductor.rate,
39 | range: 0.3125 ... 5,
40 | units: "Generic")
41 | NodeRollingView(conductor.variSpeed)
42 | }
43 | .padding()
44 | .cookbookNavBarTitle("Playback Speed")
45 | .onAppear {
46 | conductor.start()
47 | }
48 | .onDisappear {
49 | conductor.stop()
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Effects/StereoDelay.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import DunneAudioKit
6 | import SoundpipeAudioKit
7 | import SwiftUI
8 |
9 | class StereoDelayConductor: ObservableObject, ProcessesPlayerInput {
10 | let engine = AudioEngine()
11 | let player = AudioPlayer()
12 | let delay: StereoDelay
13 | var dryWetMixer: DryWetMixer
14 | let buffer: AVAudioPCMBuffer
15 |
16 | init() {
17 | buffer = Cookbook.sourceBuffer
18 | player.buffer = buffer
19 | player.isLooping = true
20 |
21 | delay = StereoDelay(player)
22 | dryWetMixer = DryWetMixer(player, delay)
23 | engine.output = dryWetMixer
24 | }
25 | }
26 |
27 | struct StereoDelayView: View {
28 | @StateObject var conductor = StereoDelayConductor()
29 |
30 | var body: some View {
31 | VStack {
32 | PlayerControls(conductor: conductor)
33 | HStack {
34 | ForEach(conductor.delay.parameters) {
35 | ParameterRow(param: $0)
36 | }
37 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
38 | }
39 | DryWetMixView(dry: conductor.player,
40 | wet: conductor.delay,
41 | mix: conductor.dryWetMixer)
42 | }
43 | .padding()
44 | .cookbookNavBarTitle("Stereo Delay")
45 | .onAppear {
46 | conductor.start()
47 | }
48 | .onDisappear {
49 | conductor.stop()
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Effects/StringResonator.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class StringResonatorConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let filter: StringResonator
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | filter = StringResonator(player)
21 | dryWetMixer = DryWetMixer(player, filter)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct StringResonatorView: View {
27 | @StateObject var conductor = StringResonatorConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.filter.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.filter,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("String Resonator")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Effects/Talkbox.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 | import Tonic
8 |
9 | class TalkboxConductor: ObservableObject, ProcessesPlayerInput {
10 | let engine = AudioEngine()
11 | let player = AudioPlayer()
12 | let talkbox: Talkbox
13 | let buffer: AVAudioPCMBuffer
14 | var osc = DynamicOscillator()
15 |
16 | func noteOn(pitch: Pitch, point _: CGPoint) {
17 | isPlaying = true
18 | osc.frequency = AUValue(pitch.midiNoteNumber).midiNoteToFrequency()
19 | }
20 |
21 | func noteOff(pitch _: Pitch) {
22 | isPlaying = false
23 | }
24 |
25 | @Published var isPlaying: Bool = false {
26 | didSet { isPlaying ? osc.start() : osc.stop() }
27 | }
28 |
29 | init() {
30 | buffer = Cookbook.sourceBuffer
31 | player.buffer = buffer
32 | player.isLooping = true
33 | osc.amplitude = 0.5
34 |
35 | talkbox = Talkbox(player, excitation: osc)
36 | engine.output = talkbox
37 | }
38 | }
39 |
40 | struct TalkboxView: View {
41 | @StateObject var conductor = TalkboxConductor()
42 | @Environment(\.colorScheme) var colorScheme
43 |
44 | var body: some View {
45 | VStack {
46 | PlayerControls(conductor: conductor)
47 | HStack {
48 | ForEach(conductor.talkbox.parameters) {
49 | ParameterRow(param: $0)
50 | }
51 | }
52 | NodeOutputView(conductor.player)
53 | CookbookKeyboard(noteOn: conductor.noteOn,
54 | noteOff: conductor.noteOff)
55 | }
56 | .padding()
57 | .cookbookNavBarTitle("Talkbox")
58 | .onAppear {
59 | conductor.start()
60 | }
61 | .onDisappear {
62 | conductor.stop()
63 | }
64 | .background(colorScheme == .dark ?
65 | Color.clear : Color(red: 0.9, green: 0.9, blue: 0.9))
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Effects/TimePitch.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SwiftUI
6 |
7 | // With TimePitch you can easily change the pitch and speed of a player-generated sound. It does not work on live input or generated signals.
8 |
9 | struct TimePitchData {
10 | var rate: AUValue = 2.0
11 | var pitch: AUValue = -400
12 | }
13 |
14 | class TimePitchConductor: ObservableObject, ProcessesPlayerInput {
15 | let engine = AudioEngine()
16 | let player = AudioPlayer()
17 | let timePitch: TimePitch
18 | let buffer: AVAudioPCMBuffer
19 |
20 | init() {
21 | buffer = Cookbook.sourceBuffer
22 | player.buffer = buffer
23 | player.isLooping = true
24 |
25 | timePitch = TimePitch(player)
26 | timePitch.rate = 2.0
27 | timePitch.pitch = -400.0
28 | engine.output = timePitch
29 | }
30 |
31 | @Published var data = TimePitchData() {
32 | didSet {
33 | // When AudioKit uses an Apple AVAudioUnit, like the case here, the values can't be ramped
34 | timePitch.rate = data.rate
35 | timePitch.pitch = data.pitch
36 | }
37 | }
38 |
39 | }
40 |
41 | struct TimePitchView: View {
42 | @StateObject var conductor = TimePitchConductor()
43 |
44 | var body: some View {
45 | VStack {
46 | PlayerControls(conductor: conductor)
47 |
48 | HStack {
49 | CookbookKnob(text: "Rate",
50 | parameter: self.$conductor.data.rate,
51 | range: 0.3125 ... 5,
52 | units: "Generic")
53 | CookbookKnob(text: "Pitch",
54 | parameter: self.$conductor.data.pitch,
55 | range: -2400 ... 2400,
56 | units: "Cents")
57 | }
58 | NodeOutputView(conductor.timePitch)
59 | }
60 | .padding()
61 | .cookbookNavBarTitle("Time / Pitch")
62 | .onAppear {
63 | conductor.start()
64 | }
65 | .onDisappear {
66 | conductor.stop()
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Effects/TransientShaper.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import DunneAudioKit
6 | import SoundpipeAudioKit
7 | import SwiftUI
8 |
9 | class TransientShaperConductor: ObservableObject, ProcessesPlayerInput {
10 | let engine = AudioEngine()
11 | let player = AudioPlayer()
12 | let transientshaper: TransientShaper
13 | let dryWetMixer: DryWetMixer
14 | let buffer: AVAudioPCMBuffer
15 |
16 | init() {
17 | buffer = Cookbook.sourceBuffer
18 | player.buffer = buffer
19 | player.isLooping = true
20 |
21 | transientshaper = TransientShaper(player)
22 | dryWetMixer = DryWetMixer(player, transientshaper)
23 | engine.output = dryWetMixer
24 | }
25 | }
26 |
27 | struct TransientShaperView: View {
28 | @StateObject var conductor = TransientShaperConductor()
29 |
30 | var body: some View {
31 | VStack {
32 | PlayerControls(conductor: conductor)
33 | HStack {
34 | ForEach(conductor.transientshaper.parameters) {
35 | ParameterRow(param: $0)
36 | }
37 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
38 | }
39 | DryWetMixView(dry: conductor.player,
40 | wet: conductor.transientshaper,
41 | mix: conductor.dryWetMixer)
42 | }
43 | .padding()
44 | .cookbookNavBarTitle("Transient Shaper")
45 | .onAppear {
46 | conductor.start()
47 | }
48 | .onDisappear {
49 | conductor.stop()
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Effects/Tremolo.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class TremoloConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let tremolo: Tremolo
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | tremolo = Tremolo(player)
21 | dryWetMixer = DryWetMixer(player, tremolo)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct TremoloView: View {
27 | @StateObject var conductor = TremoloConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.tremolo.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.tremolo,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Tremolo")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Effects/VariableDelay.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class VariableDelayConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let delay: VariableDelay
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | delay = VariableDelay(player)
21 | dryWetMixer = DryWetMixer(player, delay)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct VariableDelayView: View {
27 | @StateObject var conductor = VariableDelayConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.delay.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.delay,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Variable Delay")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Effects/Vocoder.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 | import Tonic
8 |
9 | class VocoderConductor: ObservableObject, ProcessesPlayerInput {
10 | let engine = AudioEngine()
11 | let player = AudioPlayer()
12 | let vocoder: Vocoder
13 | let buffer: AVAudioPCMBuffer
14 | var osc = MorphingOscillator(index: 2.5)
15 |
16 | func noteOn(pitch: Pitch, point _: CGPoint) {
17 | isPlaying = true
18 | osc.frequency = AUValue(pitch.midiNoteNumber).midiNoteToFrequency()
19 | }
20 |
21 | func noteOff(pitch _: Pitch) {
22 | isPlaying = false
23 | }
24 |
25 | @Published var isPlaying: Bool = false {
26 | didSet { isPlaying ? osc.start() : osc.stop() }
27 | }
28 |
29 | init() {
30 | buffer = Cookbook.sourceBuffer
31 | player.buffer = buffer
32 | player.isLooping = true
33 | osc.amplitude = 0.5
34 |
35 | vocoder = Vocoder(player, excitation: osc)
36 | engine.output = vocoder
37 |
38 | vocoder.attackTime = 0.001
39 | vocoder.releaseTime = 0.02
40 | vocoder.bandwidthRatio = 0.1
41 | }
42 | }
43 |
44 | struct VocoderView: View {
45 | @StateObject var conductor = VocoderConductor()
46 | @Environment(\.colorScheme) var colorScheme
47 |
48 | var body: some View {
49 | VStack {
50 | PlayerControls(conductor: conductor)
51 | HStack {
52 | ForEach(conductor.vocoder.parameters) {
53 | ParameterRow(param: $0)
54 | }
55 | }
56 | NodeOutputView(conductor.player)
57 | CookbookKeyboard(noteOn: conductor.noteOn,
58 | noteOff: conductor.noteOff)
59 | }
60 | .padding()
61 | .cookbookNavBarTitle("Vocoder")
62 | .onAppear {
63 | conductor.start()
64 | }
65 | .onDisappear {
66 | conductor.stop()
67 | }
68 | .background(colorScheme == .dark ?
69 | Color.clear : Color(red: 0.9, green: 0.9, blue: 0.9))
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Filters/BandPassButterworthFilter.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | //: Band-pass filters allow audio above a specified frequency range and
9 | //: bandwidth to pass through to an output. The center frequency is the starting point
10 | //: from where the frequency limit is set. Adjusting the bandwidth sets how far out
11 | //: above and below the center frequency the frequency band should be.
12 | //: Anything above that band should pass through.
13 |
14 | class BandPassButterworthFilterConductor: ObservableObject, ProcessesPlayerInput {
15 | let engine = AudioEngine()
16 | let player = AudioPlayer()
17 | let filter: BandPassButterworthFilter
18 | let dryWetMixer: DryWetMixer
19 | let buffer: AVAudioPCMBuffer
20 |
21 | init() {
22 | buffer = Cookbook.sourceBuffer
23 | player.buffer = buffer
24 | player.isLooping = true
25 |
26 | filter = BandPassButterworthFilter(player)
27 | dryWetMixer = DryWetMixer(player, filter)
28 | engine.output = dryWetMixer
29 | }
30 | }
31 |
32 | struct BandPassButterworthFilterView: View {
33 | @StateObject var conductor = BandPassButterworthFilterConductor()
34 |
35 | var body: some View {
36 | VStack {
37 | PlayerControls(conductor: conductor)
38 | HStack {
39 | ForEach(conductor.filter.parameters) {
40 | ParameterRow(param: $0)
41 | }
42 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
43 | }
44 | DryWetMixView(dry: conductor.player,
45 | wet: conductor.filter,
46 | mix: conductor.dryWetMixer)
47 | }
48 | .padding()
49 | .cookbookNavBarTitle("Band Pass Butterworth Filter")
50 | .onAppear {
51 | conductor.start()
52 | }
53 | .onDisappear {
54 | conductor.stop()
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Filters/BandRejectButterworthFilter.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class BandRejectButterworthFilterConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let filter: BandRejectButterworthFilter
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | filter = BandRejectButterworthFilter(player)
21 | dryWetMixer = DryWetMixer(player, filter)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct BandRejectButterworthFilterView: View {
27 | @StateObject var conductor = BandRejectButterworthFilterConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.filter.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.filter,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Band Reject Butterworth Filter")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Filters/CombFilterReverb.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class CombFilterReverbConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let filter: CombFilterReverb
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | filter = CombFilterReverb(player)
21 | dryWetMixer = DryWetMixer(player, filter)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct CombFilterReverbView: View {
27 | @StateObject var conductor = CombFilterReverbConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.filter.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.filter,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Comb Filter Reverb")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Filters/EqualizerFilter.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class EqualizerFilterConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let filter: EqualizerFilter
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | filter = EqualizerFilter(player)
21 | dryWetMixer = DryWetMixer(player, filter)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct EqualizerFilterView: View {
27 | @StateObject var conductor = EqualizerFilterConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.filter.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.filter,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Equalizer Filter")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Filters/FormantFilter.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class FormantFilterConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let filter: FormantFilter
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | filter = FormantFilter(player)
21 | dryWetMixer = DryWetMixer(player, filter)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct FormantFilterView: View {
27 | @StateObject var conductor = FormantFilterConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.filter.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.filter,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Formant Filter")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Filters/HighPassButterworthFilter.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | //: A high-pass filter takes an audio signal as an input, and cuts out the
9 | //: low-frequency components of the audio signal, allowing for the higher frequency
10 | //: components to "pass through" the filter.
11 |
12 | class HighPassButterworthFilterConductor: ObservableObject, ProcessesPlayerInput {
13 | let engine = AudioEngine()
14 | let player = AudioPlayer()
15 | let filter: HighPassButterworthFilter
16 | let dryWetMixer: DryWetMixer
17 | let buffer: AVAudioPCMBuffer
18 |
19 | init() {
20 | buffer = Cookbook.sourceBuffer
21 | player.buffer = buffer
22 | player.isLooping = true
23 |
24 | filter = HighPassButterworthFilter(player)
25 | dryWetMixer = DryWetMixer(player, filter)
26 | engine.output = dryWetMixer
27 | }
28 | }
29 |
30 | struct HighPassButterworthFilterView: View {
31 | @StateObject var conductor = HighPassButterworthFilterConductor()
32 |
33 | var body: some View {
34 | VStack {
35 | PlayerControls(conductor: conductor)
36 | HStack {
37 | ForEach(conductor.filter.parameters) {
38 | ParameterRow(param: $0)
39 | }
40 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
41 | }
42 | DryWetMixView(dry: conductor.player,
43 | wet: conductor.filter,
44 | mix: conductor.dryWetMixer)
45 | }
46 | .padding()
47 | .cookbookNavBarTitle("High Pass Butterworth Filter")
48 | .onAppear {
49 | conductor.start()
50 | }
51 | .onDisappear {
52 | conductor.stop()
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Filters/HighPassFilter.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class HighPassFilterConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let filter: HighPassFilter
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | filter = HighPassFilter(player)
21 | dryWetMixer = DryWetMixer(player, filter)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct HighPassFilterView: View {
27 | @StateObject var conductor = HighPassFilterConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.filter.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.filter,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("High Pass Filter")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Filters/HighShelfFilter.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class HighShelfFilterConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let filter: HighShelfFilter
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | filter = HighShelfFilter(player)
21 | dryWetMixer = DryWetMixer(player, filter)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct HighShelfFilterView: View {
27 | @StateObject var conductor = HighShelfFilterConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.filter.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.filter,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("High Shelf Filter")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Filters/HighShelfParametricEqualizerFilter.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class HighShelfParametricEqualizerFilterConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let equalizer: HighShelfParametricEqualizerFilter
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | equalizer = HighShelfParametricEqualizerFilter(player)
21 | dryWetMixer = DryWetMixer(player, equalizer)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct HighShelfParametricEqualizerFilterView: View {
27 | @StateObject var conductor = HighShelfParametricEqualizerFilterConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.equalizer.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.equalizer,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("High Shelf Parametric Equalizer Filter")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Filters/KorgLowPassFilter.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class KorgLowPassFilterConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let filter: KorgLowPassFilter
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | filter = KorgLowPassFilter(player)
21 | dryWetMixer = DryWetMixer(player, filter)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct KorgLowPassFilterView: View {
27 | @StateObject var conductor = KorgLowPassFilterConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.filter.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.filter,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Korg Low Pass Filter")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Filters/LowPassButterworthFilter.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | //: A low-pass filter takes an audio signal as an input, and cuts out the
9 | //: high-frequency components of the audio signal, allowing for the
10 | //: lower frequency components to "pass through" the filter.
11 |
12 | class LowPassButterworthFilterConductor: ObservableObject, ProcessesPlayerInput {
13 | let engine = AudioEngine()
14 | let player = AudioPlayer()
15 | let filter: LowPassButterworthFilter
16 | let dryWetMixer: DryWetMixer
17 | let buffer: AVAudioPCMBuffer
18 |
19 | init() {
20 | buffer = Cookbook.sourceBuffer
21 | player.buffer = buffer
22 | player.isLooping = true
23 |
24 | filter = LowPassButterworthFilter(player)
25 | dryWetMixer = DryWetMixer(player, filter)
26 | engine.output = dryWetMixer
27 | }
28 | }
29 |
30 | struct LowPassButterworthFilterView: View {
31 | @StateObject var conductor = LowPassButterworthFilterConductor()
32 |
33 | var body: some View {
34 | VStack {
35 | PlayerControls(conductor: conductor)
36 | HStack {
37 | ForEach(conductor.filter.parameters) {
38 | ParameterRow(param: $0)
39 | }
40 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
41 | }
42 | DryWetMixView(dry: conductor.player,
43 | wet: conductor.filter,
44 | mix: conductor.dryWetMixer)
45 | }
46 | .padding()
47 | .cookbookNavBarTitle("Low Pass Butterworth Filter")
48 | .onAppear {
49 | conductor.start()
50 | }
51 | .onDisappear {
52 | conductor.stop()
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Filters/LowPassFilter.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class LowPassFilterConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let filter: LowPassFilter
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | filter = LowPassFilter(player)
21 | dryWetMixer = DryWetMixer(player, filter)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct LowPassFilterView: View {
27 | @StateObject var conductor = LowPassFilterConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.filter.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.filter,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Low Pass Filter")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Filters/LowShelfFilter.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class LowShelfFilterConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let filter: LowShelfFilter
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | filter = LowShelfFilter(player)
21 | dryWetMixer = DryWetMixer(player, filter)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct LowShelfFilterView: View {
27 | @StateObject var conductor = LowShelfFilterConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.filter.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.filter,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Low Shelf Filter")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Filters/LowShelfParametricEqualizerFilter.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class LowShelfParametricEqualizerFilterConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let filter: LowShelfParametricEqualizerFilter
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | filter = LowShelfParametricEqualizerFilter(player)
21 | dryWetMixer = DryWetMixer(player, filter)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct LowShelfParametricEqualizerFilterView: View {
27 | @StateObject var conductor = LowShelfParametricEqualizerFilterConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.filter.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.filter,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Low Shelf Parametric Equalizer Filter")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Filters/ModalResonanceFilter.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class ModalResonanceFilterConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let filter: ModalResonanceFilter
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | filter = ModalResonanceFilter(player)
21 | dryWetMixer = DryWetMixer(player, filter)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct ModalResonanceFilterView: View {
27 | @StateObject var conductor = ModalResonanceFilterConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.filter.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.filter,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Modal Resonance Filter")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Filters/MoogLadder.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | //: One of the coolest filters available in AudioKit is the Moog Ladder.
9 | //: It's based off of Robert Moog's iconic ladder filter, which was the
10 | //: first implementation of a voltage - controlled filter used in an
11 | //: analog synthesizer. As such, it was the first filter that gave the
12 | //: ability to use voltage control to determine the cutoff frequency of the
13 | //: filter. As we're dealing with a software implementation, and not an
14 | //: analog synthesizer, we don't have to worry about dealing with
15 | //: voltage control directly. However, by using this node, you can
16 | //: emulate some of the sounds of classic analog synthesizers in your app.
17 |
18 | class MoogLadderConductor: ObservableObject, ProcessesPlayerInput {
19 | let engine = AudioEngine()
20 | let player = AudioPlayer()
21 | let filter: MoogLadder
22 | let dryWetMixer: DryWetMixer
23 | let buffer: AVAudioPCMBuffer
24 |
25 | init() {
26 | buffer = Cookbook.sourceBuffer
27 | player.buffer = buffer
28 | player.isLooping = true
29 |
30 | filter = MoogLadder(player)
31 | dryWetMixer = DryWetMixer(player, filter)
32 | engine.output = dryWetMixer
33 | }
34 | }
35 |
36 | struct MoogLadderView: View {
37 | @StateObject var conductor = MoogLadderConductor()
38 |
39 | var body: some View {
40 | VStack {
41 | PlayerControls(conductor: conductor)
42 | HStack {
43 | ForEach(conductor.filter.parameters) {
44 | ParameterRow(param: $0)
45 | }
46 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
47 | }
48 | DryWetMixView(dry: conductor.player,
49 | wet: conductor.filter,
50 | mix: conductor.dryWetMixer)
51 | }
52 | .padding()
53 | .cookbookNavBarTitle("Moog Ladder")
54 | .onAppear {
55 | conductor.start()
56 | }
57 | .onDisappear {
58 | conductor.stop()
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Filters/PeakingParametricEqualizerFilter.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class PeakingParametricEqualizerFilterConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let filter: PeakingParametricEqualizerFilter
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | filter = PeakingParametricEqualizerFilter(player)
21 | dryWetMixer = DryWetMixer(player, filter)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct PeakingParametricEqualizerFilterView: View {
27 | @StateObject var conductor = PeakingParametricEqualizerFilterConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.filter.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.filter,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Peaking Parametric Equalizer Filter")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Filters/ResonantFilter.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class ResonantFilterConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let filter: ResonantFilter
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | filter = ResonantFilter(player)
21 | dryWetMixer = DryWetMixer(player, filter)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct ResonantFilterView: View {
27 | @StateObject var conductor = ResonantFilterConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.filter.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.filter,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Resonant Filter")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Filters/ThreePoleLowpassFilter.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class ThreePoleLowpassFilterConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let filter: ThreePoleLowpassFilter
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | filter = ThreePoleLowpassFilter(player)
21 | dryWetMixer = DryWetMixer(player, filter)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct ThreePoleLowpassFilterView: View {
27 | @StateObject var conductor = ThreePoleLowpassFilterConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.filter.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.filter,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Three Pole Lowpass Filter")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Filters/ToneComplementFilter.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class ToneComplementFilterConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let filter: ToneComplementFilter
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | filter = ToneComplementFilter(player)
21 | dryWetMixer = DryWetMixer(player, filter)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct ToneComplementFilterView: View {
27 | @StateObject var conductor = ToneComplementFilterConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.filter.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.filter,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Tone Complement Filter")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Filters/ToneFilter.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class ToneFilterConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let filter: ToneFilter
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | filter = ToneFilter(player)
21 | dryWetMixer = DryWetMixer(player, filter)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct ToneFilterView: View {
27 | @StateObject var conductor = ToneFilterConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.filter.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.filter,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Tone Filter")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/MiniApps/DrumSynthesizers.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import SporthAudioKit
5 | import SwiftUI
6 |
7 | class DrumSynthesizersConductor: ObservableObject, HasAudioEngine {
8 | let engine = AudioEngine()
9 | let kick = SynthKick()
10 | let snare = SynthSnare(duration: 0.07)
11 | var reverb: Reverb
12 | var loop: CallbackLoop!
13 | var counter = 0
14 |
15 | @Published var isRunning = false {
16 | didSet {
17 | isRunning ? loop.start() : loop.stop()
18 | }
19 | }
20 |
21 | init() {
22 | let mix = Mixer(kick, snare)
23 | reverb = Reverb(mix)
24 | engine.output = reverb
25 |
26 | loop = CallbackLoop(frequency: 5) {
27 | let randomVelocity = MIDIVelocity(AUValue.random(in: 0 ... 127))
28 | let onFirstBeat = self.counter % 4 == 0
29 | let everyOtherBeat = self.counter % 4 == 2
30 | let randomHit = Array(0 ... 3).randomElement() == 0
31 |
32 | if onFirstBeat || randomHit {
33 | print("play kick")
34 | self.kick.play(noteNumber: 60, velocity: randomVelocity)
35 | self.kick.stop(noteNumber: 60)
36 | }
37 |
38 | if everyOtherBeat {
39 | print("play snare")
40 | let velocity = MIDIVelocity(Array(0 ... 100).randomElement()!)
41 | self.snare.play(noteNumber: 60, velocity: velocity, channel: 0)
42 | self.snare.stop(noteNumber: 60)
43 | }
44 | self.counter += 1
45 | }
46 | }
47 | }
48 |
49 | struct DrumSynthesizersView: View {
50 | @StateObject var conductor = DrumSynthesizersConductor()
51 |
52 | var body: some View {
53 | VStack {
54 | Text(conductor.isRunning ? "Stop" : "Start")
55 | .foregroundColor(.blue)
56 | .onTapGesture {
57 | conductor.isRunning.toggle()
58 | }
59 | NodeOutputView(conductor.reverb)
60 | }
61 | .padding()
62 | .cookbookNavBarTitle("Drum Synthesizers")
63 | .onAppear {
64 | conductor.start()
65 | }
66 | .onDisappear {
67 | conductor.isRunning = false
68 | conductor.stop()
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/MiniApps/InstrumentEXS.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import Keyboard
6 | import SoundpipeAudioKit
7 | import SwiftUI
8 | import Tonic
9 |
10 | class InstrumentEXSConductor: ObservableObject, HasAudioEngine {
11 | let engine = AudioEngine()
12 | var instrument = AppleSampler()
13 |
14 | func noteOn(pitch: Pitch, point _: CGPoint) {
15 | instrument.play(noteNumber: MIDINoteNumber(pitch.midiNoteNumber), velocity: 90, channel: 0)
16 | }
17 |
18 | func noteOff(pitch: Pitch) {
19 | instrument.stop(noteNumber: MIDINoteNumber(pitch.midiNoteNumber), channel: 0)
20 | }
21 |
22 | init() {
23 | engine.output = instrument
24 |
25 | // Load EXS file (you can also load SoundFonts and WAV files too using the AppleSampler Class)
26 | do {
27 | if let fileURL = Bundle.main.url(forResource: "Sounds/Sampler Instruments/sawPiano1", withExtension: "exs") {
28 | try instrument.loadInstrument(url: fileURL)
29 | } else {
30 | Log("Could not find file")
31 | }
32 | } catch {
33 | Log("Could not load instrument")
34 | }
35 | }
36 | }
37 |
38 | struct InstrumentEXSView: View {
39 | @StateObject var conductor = InstrumentEXSConductor()
40 | @Environment(\.colorScheme) var colorScheme
41 |
42 | var body: some View {
43 | NodeOutputView(conductor.instrument)
44 | CookbookKeyboard(noteOn: conductor.noteOn,
45 | noteOff: conductor.noteOff)
46 | .cookbookNavBarTitle("Instrument EXS")
47 | .onAppear {
48 | conductor.start()
49 | }
50 | .onDisappear {
51 | conductor.stop()
52 | }
53 | .background(colorScheme == .dark ?
54 | Color.clear : Color(red: 0.9, green: 0.9, blue: 0.9))
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/MiniApps/MIDITrack.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import SwiftUI
5 |
6 | struct MIDITrackDemo: View {
7 | @StateObject var viewModel = MIDITrackViewModel()
8 | @State var fileURL: URL? = Bundle.module.url(forResource: "MIDI Files/Demo", withExtension: "mid")
9 | @State var isPlaying = false
10 | public var body: some View {
11 | VStack {
12 | GeometryReader { geometry in
13 | ScrollView {
14 | if let fileURL = fileURL {
15 | ForEach(
16 | MIDIFile(url: fileURL).tracks.indices, id: \.self
17 | ) { number in
18 | MIDITrackView(fileURL: $fileURL,
19 | trackNumber: number,
20 | trackWidth: geometry.size.width,
21 | trackHeight: 200.0)
22 | .background(Color.primary)
23 | .cornerRadius(10.0)
24 | }
25 | }
26 | }
27 | }
28 | }
29 | .padding()
30 | .navigationBarTitle(Text("MIDI Track View"))
31 | .onTapGesture {
32 | isPlaying.toggle()
33 | }
34 | .onChange(of: isPlaying, perform: { newValue in
35 | if newValue == true {
36 | viewModel.play()
37 | } else {
38 | viewModel.stop()
39 | }
40 | })
41 | .onAppear(perform: {
42 | viewModel.startEngine()
43 | if let fileURL = Bundle.module.url(forResource: "MIDI Files/Demo", withExtension: "mid") {
44 | viewModel.loadSequencerFile(fileURL: fileURL)
45 | }
46 | })
47 | .onDisappear(perform: {
48 | viewModel.stop()
49 | viewModel.stopEngine()
50 | })
51 | .environmentObject(viewModel)
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/MiniApps/NoiseGenerators.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AudioToolbox
5 | import Controls
6 | import SoundpipeAudioKit
7 | import SwiftUI
8 |
9 | struct NoiseData {
10 | var brownianAmplitude: AUValue = 0.0
11 | var pinkAmplitude: AUValue = 0.0
12 | var whiteAmplitude: AUValue = 0.0
13 | }
14 |
15 | class NoiseGeneratorsConductor: ObservableObject, HasAudioEngine {
16 | let engine = AudioEngine()
17 | var brown = BrownianNoise()
18 | var pink = PinkNoise()
19 | var white = WhiteNoise()
20 | var mixer = Mixer()
21 |
22 | @Published var data = NoiseData() {
23 | didSet {
24 | brown.amplitude = data.brownianAmplitude
25 | pink.amplitude = data.pinkAmplitude
26 | white.amplitude = data.whiteAmplitude
27 | }
28 | }
29 |
30 | init() {
31 | mixer.addInput(brown)
32 | mixer.addInput(pink)
33 | mixer.addInput(white)
34 |
35 | brown.amplitude = data.brownianAmplitude
36 | pink.amplitude = data.pinkAmplitude
37 | white.amplitude = data.whiteAmplitude
38 | brown.start()
39 | pink.start()
40 | white.start()
41 |
42 | engine.output = mixer
43 | }
44 | }
45 |
46 | struct NoiseGeneratorsView: View {
47 | @StateObject var conductor = NoiseGeneratorsConductor()
48 |
49 | var body: some View {
50 | VStack {
51 | HStack {
52 | CookbookKnob(text: "Brownian", parameter: self.$conductor.data.brownianAmplitude, range: 0...1)
53 | CookbookKnob(text: "Pink", parameter: self.$conductor.data.pinkAmplitude, range: 0...1)
54 | CookbookKnob(text: "White", parameter: self.$conductor.data.whiteAmplitude, range: 0...1)
55 | }.padding(5)
56 | NodeOutputView(conductor.mixer)
57 | }.cookbookNavBarTitle("Noise Generators")
58 | .onAppear {
59 | conductor.start()
60 | }
61 | .onDisappear {
62 | conductor.stop()
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/MiniApps/Recorder.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SwiftUI
6 |
7 | struct RecorderData {
8 | var isRecording = false
9 | var isPlaying = false
10 | }
11 |
12 | class RecorderConductor: ObservableObject, HasAudioEngine {
13 | let engine = AudioEngine()
14 | var recorder: NodeRecorder?
15 | let player = AudioPlayer()
16 | var silencer: Fader?
17 | let mixer = Mixer()
18 |
19 | @Published var data = RecorderData() {
20 | didSet {
21 | if data.isRecording {
22 | do {
23 | try recorder?.record()
24 | } catch let err {
25 | print(err)
26 | }
27 | } else {
28 | recorder?.stop()
29 | }
30 |
31 | if data.isPlaying {
32 | if let file = recorder?.audioFile {
33 | try? player.load(file: file)
34 | player.play()
35 | }
36 | } else {
37 | player.stop()
38 | }
39 | }
40 | }
41 |
42 | init() {
43 | guard let input = engine.input else {
44 | fatalError()
45 | }
46 |
47 | do {
48 | recorder = try NodeRecorder(node: input)
49 | } catch let err {
50 | fatalError("\(err)")
51 | }
52 | let silencer = Fader(input, gain: 0)
53 | self.silencer = silencer
54 | mixer.addInput(silencer)
55 | mixer.addInput(player)
56 | engine.output = mixer
57 | }
58 | }
59 |
60 | struct RecorderView: View {
61 | @StateObject var conductor = RecorderConductor()
62 |
63 | var body: some View {
64 | VStack {
65 | Spacer()
66 | Text(conductor.data.isRecording ? "STOP RECORDING" : "RECORD")
67 | .foregroundColor(.blue)
68 | .onTapGesture {
69 | conductor.data.isRecording.toggle()
70 | }
71 | Spacer()
72 | Text(conductor.data.isPlaying ? "STOP" : "PLAY")
73 | .foregroundColor(.blue)
74 | .onTapGesture {
75 | conductor.data.isPlaying.toggle()
76 | }
77 | Spacer()
78 | }
79 |
80 | .padding()
81 | .cookbookNavBarTitle("Recorder")
82 | .onAppear {
83 | conductor.start()
84 | }
85 | .onDisappear {
86 | conductor.stop()
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/MiniApps/VocalTract.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AudioToolbox
5 | import Combine
6 | import SoundpipeAudioKit
7 | import SwiftUI
8 |
9 | class VocalTractConductor: ObservableObject, HasAudioEngine {
10 | let engine = AudioEngine()
11 |
12 | @Published var isPlaying: Bool = false {
13 | didSet { isPlaying ? voc.start() : voc.stop() }
14 | }
15 |
16 | var voc = VocalTract()
17 |
18 | init() {
19 | engine.output = voc
20 | }
21 | }
22 |
23 | struct Button2: View {
24 | var text: String
25 | var onTap: () -> Void
26 |
27 | var body: some View {
28 | ZStack {
29 | RoundedRectangle(cornerRadius: 10).foregroundColor(.gray)
30 | Text(text).onTapGesture {
31 | self.onTap()
32 | }
33 | }
34 | }
35 | }
36 |
37 | struct VocalTractView: View {
38 | @StateObject var conductor = VocalTractConductor()
39 |
40 | var body: some View {
41 | VStack {
42 | Text(conductor.isPlaying ? "STOP" : "START")
43 | .foregroundColor(.blue)
44 | .onTapGesture {
45 | conductor.isPlaying.toggle()
46 | }
47 |
48 | Button2(text: "Randomize") {
49 | conductor.voc.frequency = AUValue.random(in: 0 ... 2000)
50 | conductor.voc.tonguePosition = AUValue.random(in: 0 ... 1)
51 | conductor.voc.tongueDiameter = AUValue.random(in: 0 ... 1)
52 | conductor.voc.tenseness = AUValue.random(in: 0 ... 1)
53 | conductor.voc.nasality = AUValue.random(in: 0 ... 1)
54 | }
55 |
56 | HStack {
57 | ForEach(conductor.voc.parameters) {
58 | ParameterRow(param: $0)
59 | }
60 | }.frame(height: 150)
61 | NodeOutputView(conductor.voc)
62 | }.cookbookNavBarTitle("Vocal Tract")
63 | .padding()
64 | .onAppear {
65 | conductor.start()
66 | }
67 | .onDisappear {
68 | conductor.stop()
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Operations/CrossingSignal.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import SporthAudioKit
5 | import SwiftUI
6 |
7 | class CrossingSignalConductor: ObservableObject, HasAudioEngine {
8 | let engine = AudioEngine()
9 |
10 | @Published var isRunning = false {
11 | didSet {
12 | isRunning ? generator.start() : generator.stop()
13 | }
14 | }
15 |
16 | let generator = OperationGenerator {
17 | // Generate a sine wave at the right frequency
18 | let crossingSignalTone = Operation.sineWave(frequency: 2500)
19 |
20 | // Periodically trigger an envelope around that signal
21 | let crossingSignalTrigger = Operation.periodicTrigger(period: 0.2)
22 | let crossingSignal = crossingSignalTone.triggeredWithEnvelope(
23 | trigger: crossingSignalTrigger,
24 | attack: 0.01,
25 | hold: 0.1,
26 | release: 0.01
27 | )
28 |
29 | // scale the volume
30 | return crossingSignal * 0.2
31 | }
32 |
33 | init() {
34 | engine.output = generator
35 | }
36 | }
37 |
38 | struct CrossingSignalView: View {
39 | @StateObject var conductor = CrossingSignalConductor()
40 |
41 | var body: some View {
42 | VStack(spacing: 50) {
43 | Text("A British crossing signal implemented with AudioKit, an example from Andy Farnell's excellent book \"Designing Sound\"")
44 | Text(conductor.isRunning ? "Stop" : "Start")
45 | .foregroundColor(.blue)
46 | .onTapGesture {
47 | conductor.isRunning.toggle()
48 | }
49 | NodeOutputView(conductor.generator)
50 | }
51 | .padding()
52 | .cookbookNavBarTitle("Crossing Signal")
53 | .onAppear {
54 | conductor.start()
55 | }
56 | .onDisappear {
57 | conductor.stop()
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Operations/DroneOperation.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import SporthAudioKit
5 | import SwiftUI
6 |
7 | class DroneOperationConductor: ObservableObject, HasAudioEngine {
8 | let engine = AudioEngine()
9 |
10 | @Published var isRunning = false {
11 | didSet {
12 | isRunning ? generator.start() : generator.stop()
13 | }
14 | }
15 |
16 | let generator = OperationGenerator {
17 | func drone(frequency: Double, rate: Double) -> OperationParameter {
18 | let metro = Operation.metronome(frequency: rate)
19 | let tone = Operation.sineWave(frequency: frequency, amplitude: 0.2)
20 | return tone.triggeredWithEnvelope(trigger: metro, attack: 0.01, hold: 0.1, release: 0.1)
21 | }
22 |
23 | let drone1 = drone(frequency: 440, rate: 3)
24 | let drone2 = drone(frequency: 330, rate: 5)
25 | let drone3 = drone(frequency: 450, rate: 7)
26 |
27 | return (drone1 + drone2 + drone3) / 3
28 | }
29 |
30 | init() {
31 | engine.output = generator
32 | }
33 | }
34 |
35 | struct DroneOperationView: View {
36 | @StateObject var conductor = DroneOperationConductor()
37 |
38 | var body: some View {
39 | VStack(spacing: 50) {
40 | Text("Encapsualating functionality of operations into functions")
41 | Text(conductor.isRunning ? "Stop" : "Start")
42 | .foregroundColor(.blue)
43 | .onTapGesture {
44 | conductor.isRunning.toggle()
45 | }
46 | NodeOutputView(conductor.generator)
47 | }
48 | .padding()
49 | .cookbookNavBarTitle("Drone Operation")
50 | .onAppear {
51 | conductor.start()
52 | }
53 | .onDisappear {
54 | conductor.stop()
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Operations/InstrumentOperation.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import SporthAudioKit
5 | import SwiftUI
6 |
7 | class InstrumentOperationConductor: ObservableObject, HasAudioEngine {
8 | let engine = AudioEngine()
9 |
10 | @Published var isRunning = false {
11 | didSet {
12 | isRunning ? generator.start() : generator.stop()
13 | }
14 | }
15 |
16 | let generator = OperationGenerator {
17 | func instrument(noteNumber: MIDINoteNumber, rate: Double, amplitude: Double) -> OperationParameter {
18 | let metro = Operation.metronome(frequency: 82.0 / (60.0 * rate))
19 | let frequency = Double(noteNumber.midiNoteToFrequency())
20 | let fm = Operation.fmOscillator(baseFrequency: frequency, amplitude: amplitude)
21 |
22 | return fm.triggeredWithEnvelope(trigger: metro, attack: 0.5, hold: 1, release: 1)
23 | }
24 |
25 | let instrument1 = instrument(noteNumber: 60, rate: 4, amplitude: 0.5)
26 | let instrument2 = instrument(noteNumber: 62, rate: 5, amplitude: 0.4)
27 | let instrument3 = instrument(noteNumber: 65, rate: 7, amplitude: 1.3 / 4.0)
28 | let instrument4 = instrument(noteNumber: 67, rate: 7, amplitude: 0.125)
29 |
30 | let instruments = (instrument1 + instrument2 + instrument3 + instrument4) * 0.13
31 |
32 | let reverb = instruments.reverberateWithCostello(feedback: 0.9, cutoffFrequency: 10000).toMono()
33 |
34 | return mixer(instruments, reverb, balance: 0.4)
35 | }
36 |
37 | init() {
38 | engine.output = generator
39 | }
40 | }
41 |
42 | struct InstrumentOperationView: View {
43 | @StateObject var conductor = InstrumentOperationConductor()
44 |
45 | var body: some View {
46 | VStack(spacing: 50) {
47 | Text("Encapsualating functionality of operations into functions")
48 | Text(conductor.isRunning ? "Stop" : "Start")
49 | .foregroundColor(.blue)
50 | .onTapGesture {
51 | conductor.isRunning.toggle()
52 | }
53 | NodeOutputView(conductor.generator)
54 | }
55 | .padding()
56 | .cookbookNavBarTitle("Instrument Operation")
57 | .onAppear {
58 | conductor.start()
59 | }
60 | .onDisappear {
61 | conductor.stop()
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Operations/LFOOperation.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import SporthAudioKit
5 | import SwiftUI
6 |
7 | class LFOOperationConductor: ObservableObject, HasAudioEngine {
8 | let engine = AudioEngine()
9 |
10 | @Published var isRunning = false {
11 | didSet {
12 | isRunning ? generator.start() : generator.stop()
13 | }
14 | }
15 |
16 | let generator = OperationGenerator {
17 | let frequencyLFO = Operation.square(frequency: 1)
18 | .scale(minimum: 440, maximum: 880)
19 | let carrierLFO = Operation.triangle(frequency: 1)
20 | .scale(minimum: 1, maximum: 2)
21 | let modulatingMultiplierLFO = Operation.sawtooth(frequency: 1)
22 | .scale(minimum: 0.1, maximum: 2)
23 | let modulatingIndexLFO = Operation.reverseSawtooth(frequency: 1)
24 | .scale(minimum: 0.1, maximum: 20)
25 |
26 | return Operation.fmOscillator(
27 | baseFrequency: frequencyLFO,
28 | carrierMultiplier: carrierLFO,
29 | modulatingMultiplier: modulatingMultiplierLFO,
30 | modulationIndex: modulatingIndexLFO,
31 | amplitude: 0.2
32 | )
33 | }
34 |
35 | init() {
36 | engine.output = generator
37 | }
38 | }
39 |
40 | struct LFOOperationView: View {
41 | @StateObject var conductor = LFOOperationConductor()
42 |
43 | var body: some View {
44 | VStack(spacing: 50) {
45 | Text("Often we want rhythmic changing of parameters that varying in a standard way. This is traditionally done with Low-Frequency Oscillators, LFOs.")
46 | Text(conductor.isRunning ? "Stop" : "Start")
47 | .foregroundColor(.blue)
48 | .onTapGesture {
49 | conductor.isRunning.toggle()
50 | }
51 | NodeOutputView(conductor.generator)
52 | }
53 | .padding()
54 | .cookbookNavBarTitle("LFO Operation")
55 | .onAppear {
56 | conductor.start()
57 | }
58 | .onDisappear {
59 | conductor.stop()
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Operations/PhasorOperation.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import SporthAudioKit
5 | import SwiftUI
6 |
7 | class PhasorOperationConductor: ObservableObject, HasAudioEngine {
8 | let engine = AudioEngine()
9 |
10 | @Published var isRunning = false {
11 | didSet {
12 | isRunning ? generator.start() : generator.stop()
13 | }
14 | }
15 |
16 | let generator = OperationGenerator {
17 | let interval: Double = 2
18 | let noteCount: Double = 24
19 | let startingNote: Double = 48 // C
20 |
21 | let phasing = Operation.phasor(frequency: 0.5) * Operation.randomNumberPulse(minimum: 0.9, maximum: 2, updateFrequency: 0.5)
22 | let frequency = (floor(phasing * noteCount) * interval + startingNote)
23 | .midiNoteToFrequency()
24 |
25 | var amplitude = (phasing - 1).portamento() // prevents the click sound
26 |
27 | var oscillator = Operation.sineWave(frequency: frequency, amplitude: amplitude)
28 | let reverb = oscillator.reverberateWithChowning()
29 | return mixer(oscillator, reverb, balance: 0.6)
30 | }
31 |
32 | init() {
33 | engine.output = generator
34 | }
35 | }
36 |
37 | struct PhasorOperationView: View {
38 | @StateObject var conductor = PhasorOperationConductor()
39 |
40 | var body: some View {
41 | VStack(spacing: 50) {
42 | Text("Using the phasor to sweep amplitude and frequencies")
43 | Text(conductor.isRunning ? "Stop" : "Start")
44 | .foregroundColor(.blue)
45 | .onTapGesture {
46 | conductor.isRunning.toggle()
47 | }
48 | NodeOutputView(conductor.generator)
49 | }
50 | .padding()
51 | .cookbookNavBarTitle("Phasor Operation")
52 | .onAppear {
53 | conductor.start()
54 | }
55 | .onDisappear {
56 | conductor.stop()
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Operations/SegmentOperation.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import SporthAudioKit
5 | import SwiftUI
6 |
7 | class SegmentOperationConductor: ObservableObject, HasAudioEngine {
8 | let engine = AudioEngine()
9 |
10 | @Published var isRunning = false {
11 | didSet {
12 | isRunning ? generator.start() : generator.stop()
13 | }
14 | }
15 |
16 | let generator = OperationGenerator { parameters in
17 | let updateRate = parameters[0]
18 |
19 | // Vary the starting frequency and duration randomly
20 | let start = Operation.randomNumberPulse() * 2000 + 300
21 | let duration = Operation.randomNumberPulse()
22 | let frequency = Operation.lineSegment(trigger: Operation.metronome(frequency: updateRate),
23 | start: start,
24 | end: 0,
25 | duration: duration)
26 |
27 | // Decrease the amplitude exponentially
28 | let amplitude = Operation.exponentialSegment(trigger: Operation.metronome(frequency: updateRate),
29 | start: 0.3,
30 | end: 0.01,
31 | duration: 1.0 / updateRate)
32 | return Operation.sineWave(frequency: frequency, amplitude: amplitude)
33 | }
34 |
35 | init() {
36 | let delay = Delay(generator)
37 | generator.parameter1 = 2.0
38 |
39 | //: Add some effects for good fun
40 | delay.time = 0.125
41 | delay.feedback = 0.8
42 | let reverb = Reverb(delay)
43 | reverb.loadFactoryPreset(.largeHall)
44 |
45 | engine.output = reverb
46 | }
47 | }
48 |
49 | struct SegmentOperationView: View {
50 | @StateObject var conductor = SegmentOperationConductor()
51 |
52 | var body: some View {
53 | VStack(spacing: 50) {
54 | Text("Creating segments that vary parameters in operations linearly or exponentially over a certain duration")
55 | Text(conductor.isRunning ? "Stop" : "Start")
56 | .foregroundColor(.blue)
57 | .onTapGesture {
58 | conductor.isRunning.toggle()
59 | }
60 | NodeOutputView(conductor.generator)
61 | }
62 | .padding()
63 | .cookbookNavBarTitle("Segment Operation")
64 | .onAppear {
65 | conductor.start()
66 | }
67 | .onDisappear {
68 | conductor.stop()
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Operations/SmoothDelayOperation.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SporthAudioKit
6 | import SwiftUI
7 |
8 | struct SmoothDelayOperationData {
9 | var time: AUValue = 0.1
10 | var feedback: AUValue = 0.7
11 | var rampDuration: AUValue = 0.1
12 | }
13 |
14 | class SmoothDelayOperationConductor: ObservableObject, ProcessesPlayerInput {
15 | let engine = AudioEngine()
16 | let player = AudioPlayer()
17 | let buffer: AVAudioPCMBuffer
18 | let effect: OperationEffect
19 |
20 | @Published var data = SmoothDelayOperationData() {
21 | didSet {
22 | effect.$parameter1.ramp(to: data.time, duration: data.rampDuration)
23 | effect.$parameter2.ramp(to: data.feedback, duration: data.rampDuration)
24 | }
25 | }
26 |
27 | init() {
28 | buffer = Cookbook.sourceBuffer
29 | player.buffer = buffer
30 | player.isLooping = true
31 |
32 | effect = OperationEffect(player) { player, parameters in
33 | let delayedPlayer = player.smoothDelay(
34 | time: parameters[0],
35 | feedback: parameters[1],
36 | samples: 1024,
37 | maximumDelayTime: 2.0
38 | )
39 | return mixer(player.toMono(), delayedPlayer)
40 | }
41 | effect.parameter1 = 0.1
42 | effect.parameter2 = 0.7
43 |
44 | engine.output = effect
45 | }
46 | }
47 |
48 | struct SmoothDelayOperationView: View {
49 | @StateObject var conductor = SmoothDelayOperationConductor()
50 |
51 | var body: some View {
52 | VStack(spacing: 20) {
53 | PlayerControls(conductor: conductor)
54 | HStack {
55 | CookbookKnob(text: "Time",
56 | parameter: $conductor.data.time,
57 | range: 0 ... 0.3,
58 | units: "Seconds")
59 | CookbookKnob(text: "Feedback",
60 | parameter: $conductor.data.feedback,
61 | range: 0 ... 1,
62 | units: "%")
63 | }
64 | NodeOutputView(conductor.effect)
65 | }
66 | .padding()
67 | .cookbookNavBarTitle("Smooth Delay Operation")
68 | .onAppear {
69 | conductor.start()
70 | }
71 | .onDisappear {
72 | conductor.stop()
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Operations/StereoOperation.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import SporthAudioKit
5 | import SwiftUI
6 |
7 | class StereoOperationConductor: ObservableObject, HasAudioEngine {
8 | let engine = AudioEngine()
9 |
10 | @Published var isRunning = false {
11 | didSet {
12 | isRunning ? generator.start() : generator.stop()
13 | }
14 | }
15 |
16 | let generator = OperationGenerator(channelCount: 2) { _ in
17 |
18 | let slowSine = round(Operation.sineWave(frequency: 1) * 12) / 12
19 | let vibrato = slowSine.scale(minimum: -1200, maximum: 1200)
20 |
21 | let fastSine = Operation.sineWave(frequency: 10)
22 | let volume = fastSine.scale(minimum: 0, maximum: 0.5)
23 |
24 | let leftOutput = Operation.sineWave(frequency: 440 + vibrato, amplitude: volume)
25 | let rightOutput = Operation.sineWave(frequency: 220 + vibrato, amplitude: volume)
26 |
27 | return [leftOutput, rightOutput]
28 | }
29 |
30 | init() {
31 | engine.output = generator
32 | }
33 | }
34 |
35 | struct StereoOperationView: View {
36 | @StateObject var conductor = StereoOperationConductor()
37 |
38 | var body: some View {
39 | VStack(spacing: 50) {
40 | Text("This is an example of building a stereo sound generator.")
41 | Text(conductor.isRunning ? "Stop" : "Start")
42 | .foregroundColor(.blue)
43 | .onTapGesture {
44 | conductor.isRunning.toggle()
45 | }
46 | NodeOutputView(conductor.generator)
47 | }
48 | .padding()
49 | .cookbookNavBarTitle("Stereo Operation")
50 | .onAppear {
51 | conductor.start()
52 | }
53 | .onDisappear {
54 | conductor.stop()
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Operations/VocalTractOperation.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AudioToolbox
5 | import SporthAudioKit
6 | import SwiftUI
7 |
8 | class VocalTractOperationConductor: ObservableObject, HasAudioEngine {
9 | @Published var isPlaying = false {
10 | didSet {
11 | isPlaying ? generator.start() : generator.stop()
12 | }
13 | }
14 |
15 | let engine = AudioEngine()
16 |
17 | let generator = OperationGenerator {
18 | let frequency = Operation.sineWave(frequency: 1).scale(minimum: 100, maximum: 300)
19 | let jitter = Operation.jitter(amplitude: 300, minimumFrequency: 1, maximumFrequency: 3)
20 | let position = Operation.sineWave(frequency: 0.1).scale()
21 | let diameter = Operation.sineWave(frequency: 0.2).scale()
22 | let tenseness = Operation.sineWave(frequency: 0.3).scale()
23 | let nasality = Operation.sineWave(frequency: 0.35).scale()
24 | return Operation.vocalTract(frequency: frequency + jitter,
25 | tonguePosition: position,
26 | tongueDiameter: diameter,
27 | tenseness: tenseness,
28 | nasality: nasality)
29 | }
30 |
31 | init() {
32 | engine.output = generator
33 | }
34 | }
35 |
36 | struct VocalTractOperationView: View {
37 | @StateObject var conductor = VocalTractOperationConductor()
38 |
39 | var body: some View {
40 | VStack(spacing: 50) {
41 | Text(conductor.isPlaying ? "Stop!" : "More!")
42 | .foregroundColor(.blue)
43 | .onTapGesture {
44 | conductor.isPlaying.toggle()
45 | }
46 | NodeOutputView(conductor.generator)
47 | }
48 | .cookbookNavBarTitle("Vocal Fun")
49 | .padding()
50 | .onAppear {
51 | conductor.start()
52 | }
53 | .onDisappear {
54 | conductor.stop()
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Oscillators/MorphingOscillator.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AudioToolbox
5 | import Keyboard
6 | import SoundpipeAudioKit
7 | import SwiftUI
8 | import Tonic
9 |
10 | class MorphingOscillatorConductor: ObservableObject, HasAudioEngine {
11 | var engine = AudioEngine()
12 | var osc = MorphingOscillator()
13 |
14 | func noteOn(pitch: Pitch, point _: CGPoint) {
15 | isPlaying = true
16 | osc.frequency = AUValue(pitch.midiNoteNumber).midiNoteToFrequency()
17 | }
18 |
19 | func noteOff(pitch _: Pitch) {
20 | isPlaying = false
21 | }
22 |
23 | @Published var isPlaying: Bool = false {
24 | didSet { isPlaying ? osc.start() : osc.stop() }
25 | }
26 |
27 | init() {
28 | osc.amplitude = 0.2
29 | engine.output = osc
30 | }
31 | }
32 |
33 | struct MorphingOscillatorView: View {
34 | @StateObject var conductor = MorphingOscillatorConductor()
35 | @Environment(\.colorScheme) var colorScheme
36 |
37 | var body: some View {
38 | VStack {
39 | Text(conductor.isPlaying ? "STOP" : "START")
40 | .foregroundColor(.blue)
41 | .onTapGesture {
42 | conductor.isPlaying.toggle()
43 | }
44 | HStack {
45 | ForEach(conductor.osc.parameters) {
46 | ParameterRow(param: $0)
47 | }
48 | }
49 |
50 | NodeOutputView(conductor.osc)
51 | CookbookKeyboard(noteOn: conductor.noteOn,
52 | noteOff: conductor.noteOff)
53 | }
54 | .padding()
55 | .cookbookNavBarTitle("Morphing Oscillator")
56 | .onAppear {
57 | conductor.start()
58 | }
59 | .onDisappear {
60 | conductor.stop()
61 | }
62 | .background(colorScheme == .dark ?
63 | Color.clear : Color(red: 0.9, green: 0.9, blue: 0.9))
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Oscillators/Oscillator.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AudioToolbox
5 | import Keyboard
6 | import SoundpipeAudioKit
7 | import SwiftUI
8 | import Tonic
9 |
10 | class OscillatorConductor: ObservableObject, HasAudioEngine {
11 | let engine = AudioEngine()
12 | var osc = Oscillator()
13 |
14 | func noteOn(pitch: Pitch, point _: CGPoint) {
15 | isPlaying = true
16 | osc.frequency = AUValue(pitch.midiNoteNumber).midiNoteToFrequency()
17 | }
18 |
19 | func noteOff(pitch _: Pitch) {
20 | isPlaying = false
21 | }
22 |
23 | @Published var isPlaying: Bool = false {
24 | didSet { isPlaying ? osc.start() : osc.stop() }
25 | }
26 |
27 | init() {
28 | osc.amplitude = 0.2
29 | engine.output = osc
30 | }
31 | }
32 |
33 | struct OscillatorView: View {
34 | @StateObject var conductor = OscillatorConductor()
35 | @Environment(\.colorScheme) var colorScheme
36 |
37 | var body: some View {
38 | VStack {
39 | Text(conductor.isPlaying ? "STOP" : "START")
40 | .foregroundColor(.blue)
41 | .onTapGesture {
42 | conductor.isPlaying.toggle()
43 | }
44 | HStack {
45 | ForEach(conductor.osc.parameters) {
46 | ParameterRow(param: $0)
47 | }
48 | }
49 | NodeOutputView(conductor.osc)
50 | CookbookKeyboard(noteOn: conductor.noteOn,
51 | noteOff: conductor.noteOff)
52 |
53 | }.cookbookNavBarTitle("Oscillator")
54 | .onAppear {
55 | conductor.start()
56 | }
57 | .onDisappear {
58 | conductor.stop()
59 | }
60 | .background(colorScheme == .dark ?
61 | Color.clear : Color(red: 0.9, green: 0.9, blue: 0.9))
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Oscillators/PWMOscillator.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AudioToolbox
5 | import Keyboard
6 | import SoundpipeAudioKit
7 | import SwiftUI
8 | import Tonic
9 |
10 | class PWMOscillatorConductor: ObservableObject, HasAudioEngine {
11 | let engine = AudioEngine()
12 | var osc = PWMOscillator()
13 |
14 | func noteOn(pitch: Pitch, point _: CGPoint) {
15 | isPlaying = true
16 | osc.frequency = AUValue(pitch.midiNoteNumber).midiNoteToFrequency()
17 | }
18 |
19 | func noteOff(pitch _: Pitch) {
20 | isPlaying = false
21 | }
22 |
23 | @Published var isPlaying: Bool = false {
24 | didSet { isPlaying ? osc.start() : osc.stop() }
25 | }
26 |
27 | init() {
28 | osc.amplitude = 0.2
29 | engine.output = osc
30 | }
31 | }
32 |
33 | struct PWMOscillatorView: View {
34 | @StateObject var conductor = PWMOscillatorConductor()
35 | @Environment(\.colorScheme) var colorScheme
36 |
37 | var body: some View {
38 | VStack {
39 | Text(conductor.isPlaying ? "STOP" : "START")
40 | .foregroundColor(.blue)
41 | .onTapGesture {
42 | conductor.isPlaying.toggle()
43 | }
44 | Spacer()
45 | HStack {
46 | ForEach(conductor.osc.parameters) {
47 | ParameterRow(param: $0)
48 | }
49 | }.padding(5)
50 | NodeOutputView(conductor.osc)
51 | CookbookKeyboard(noteOn: conductor.noteOn,
52 | noteOff: conductor.noteOff)
53 |
54 | }.cookbookNavBarTitle("PWM Oscillator")
55 | .onAppear {
56 | conductor.start()
57 | }
58 | .onDisappear {
59 | conductor.stop()
60 | }
61 | .background(colorScheme == .dark ?
62 | Color.clear : Color(red: 0.9, green: 0.9, blue: 0.9))
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Oscillators/PhaseDistortionOscillator.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AudioToolbox
5 | import Keyboard
6 | import SoundpipeAudioKit
7 | import SwiftUI
8 | import Tonic
9 |
10 | class PhaseDistortionOscillatorConductor: ObservableObject, HasAudioEngine {
11 | let engine = AudioEngine()
12 | var osc = PhaseDistortionOscillator()
13 |
14 | func noteOn(pitch: Pitch, point _: CGPoint) {
15 | isPlaying = true
16 | osc.frequency = AUValue(pitch.midiNoteNumber).midiNoteToFrequency()
17 | }
18 |
19 | func noteOff(pitch _: Pitch) {
20 | isPlaying = false
21 | }
22 |
23 | @Published var isPlaying: Bool = false {
24 | didSet { isPlaying ? osc.start() : osc.stop() }
25 | }
26 |
27 | init() {
28 | osc.amplitude = 0.2
29 | engine.output = osc
30 | }
31 | }
32 |
33 | struct PhaseDistortionOscillatorView: View {
34 | @StateObject var conductor = PhaseDistortionOscillatorConductor()
35 | @Environment(\.colorScheme) var colorScheme
36 |
37 | var body: some View {
38 | VStack {
39 | Text(conductor.isPlaying ? "STOP" : "START")
40 | .foregroundColor(.blue)
41 | .onTapGesture {
42 | conductor.isPlaying.toggle()
43 | }
44 | HStack {
45 | ForEach(conductor.osc.parameters) {
46 | ParameterRow(param: $0)
47 | }
48 | }
49 |
50 | NodeOutputView(conductor.osc)
51 | CookbookKeyboard(noteOn: conductor.noteOn,
52 | noteOff: conductor.noteOff)
53 |
54 | }.cookbookNavBarTitle("Phase Distortion Oscillator")
55 | .onAppear {
56 | conductor.start()
57 | }
58 | .onDisappear {
59 | conductor.stop()
60 | }
61 | .background(colorScheme == .dark ?
62 | Color.clear : Color(red: 0.9, green: 0.9, blue: 0.9))
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Reverbs/ChowningReverb.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class ChowningReverbConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let reverb: ChowningReverb
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | reverb = ChowningReverb(player)
21 | dryWetMixer = DryWetMixer(player, reverb)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct ChowningReverbView: View {
27 | @StateObject var conductor = ChowningReverbConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
33 | DryWetMixView(dry: conductor.player,
34 | wet: conductor.reverb,
35 | mix: conductor.dryWetMixer)
36 | }
37 | .padding()
38 | .cookbookNavBarTitle("Chowning Reverb")
39 | .onAppear {
40 | conductor.start()
41 | }
42 | .onDisappear {
43 | conductor.stop()
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Reverbs/CostelloReverb.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class CostelloReverbConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let reverb: CostelloReverb
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | reverb = CostelloReverb(player)
21 | dryWetMixer = DryWetMixer(player, reverb)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct CostelloReverbView: View {
27 | @StateObject var conductor = CostelloReverbConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.reverb.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.reverb,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Costello Reverb")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Reverbs/FlatFrequencyResponseReverb.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class FlatFrequencyResponseReverbConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let reverb: FlatFrequencyResponseReverb
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | reverb = FlatFrequencyResponseReverb(player)
21 | dryWetMixer = DryWetMixer(player, reverb)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct FlatFrequencyResponseReverbView: View {
27 | @StateObject var conductor = FlatFrequencyResponseReverbConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.reverb.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.reverb,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Flat Frequency Response Reverb")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/Reverbs/ZitaReverb.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class ZitaReverbConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let reverb: ZitaReverb
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | let url = Bundle.module.resourceURL?.appendingPathComponent("Samples/beat.aiff")
17 | do {
18 | let file = try AVAudioFile(forReading: url!)
19 | buffer = try AVAudioPCMBuffer(file: file)!
20 | } catch {
21 | fatalError()
22 | }
23 | reverb = ZitaReverb(player)
24 | dryWetMixer = DryWetMixer(player, reverb)
25 | engine.output = dryWetMixer
26 | }
27 | }
28 |
29 | struct ZitaReverbView: View {
30 | @StateObject var conductor = ZitaReverbConductor()
31 |
32 | var body: some View {
33 | VStack {
34 | PlayerControls(conductor: conductor)
35 | HStack {
36 | ForEach(0..<6) {
37 | ParameterRow(param: conductor.reverb.parameters[$0])
38 | }
39 | }
40 | HStack {
41 | ForEach(6..<10) {
42 | ParameterRow(param: conductor.reverb.parameters[$0])
43 | }
44 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
45 | }
46 | DryWetMixView(dry: conductor.player,
47 | wet: conductor.reverb,
48 | mix: conductor.dryWetMixer)
49 | }
50 | .padding()
51 | .cookbookNavBarTitle("Zita Reverb")
52 | .onAppear {
53 | conductor.start()
54 | }
55 | .onDisappear {
56 | conductor.stop()
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/UncategorizedDemos/AudioFileView.swift:
--------------------------------------------------------------------------------
1 | import AudioKitUI
2 | import SwiftUI
3 |
4 | struct AudioFileRecipeView: View {
5 | var body: some View {
6 | VStack {
7 | ForEach(TestAudioURLs.allCases, id: \.self) { testURL in
8 | Text(testURL.rawValue)
9 | if let url = testURL.url() {
10 | AudioFileWaveform(url: url)
11 | .background(Color.black)
12 | }
13 | }
14 | }
15 | .padding()
16 | #if os(iOS)
17 | .navigationBarTitle(Text("Audio Files"))
18 | #endif
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/UncategorizedDemos/Table.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SwiftUI
6 |
7 | class TableConductor {
8 | let square: AudioKit.Table
9 | let triangle: AudioKit.Table
10 | let sine: AudioKit.Table
11 | let sineHarmonic: AudioKit.Table
12 | let fileTable: AudioKit.Table
13 | let custom: AudioKit.Table
14 |
15 | init() {
16 | square = Table(.square, count: 128)
17 | triangle = Table(.triangle, count: 128)
18 | sine = Table(.sine, count: 256)
19 | let url = Bundle.module.resourceURL?.appendingPathComponent("Samples/beat.aiff")
20 | let file = try! AVAudioFile(forReading: url!)
21 | fileTable = Table(file: file)!
22 | let harmonicOvertoneAmplitudes: [Float] = [0.0, 0.0, 0.016, 0.301]
23 | sineHarmonic = Table(.harmonic(harmonicOvertoneAmplitudes), phase: 0.75)
24 | custom = Table(.sine, count: 256)
25 | for i in custom.indices {
26 | custom[i] += Float.random(in: -0.3 ... 0.3) + Float(i) / 2048.0
27 | }
28 | }
29 | }
30 |
31 | struct TableRecipeView: View {
32 | var conductor = TableConductor()
33 |
34 | var body: some View {
35 | VStack {
36 | Text("Square")
37 | TableDataView(view: TableView(conductor.square))
38 | Text("Triangle")
39 | TableDataView(view: TableView(conductor.triangle))
40 | Text("Sine")
41 | TableDataView(view: TableView(conductor.sine))
42 | Text("Sine Harmonic")
43 | TableDataView(view: TableView(conductor.sineHarmonic))
44 | Text("File")
45 | TableDataView(view: TableView(conductor.fileTable))
46 | Text("Custom Data")
47 | TableDataView(view: TableView(conductor.custom))
48 | }
49 | .padding()
50 | .cookbookNavBarTitle("Tables")
51 | }
52 | }
53 |
54 | struct TableDataView: UIViewRepresentable {
55 | typealias UIViewType = TableView
56 | var view: TableView
57 |
58 | func makeUIView(context _: Context) -> TableView {
59 | view.backgroundColor = UIColor.black
60 | return view
61 | }
62 |
63 | func updateUIView(_: TableView, context _: Context) {
64 | //
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/WIP/DunneSynth.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import DunneAudioKit
3 | import AudioKitEX
4 | import AudioKitUI
5 | import AVFAudio
6 | import Keyboard
7 | import SwiftUI
8 | import Controls
9 | import Tonic
10 |
11 | class DunneSynthConductor: ObservableObject, HasAudioEngine {
12 | let engine = AudioEngine()
13 | var instrument = Synth()
14 |
15 | func noteOn(pitch: Pitch, point _: CGPoint) {
16 | instrument.play(noteNumber: MIDINoteNumber(pitch.midiNoteNumber), velocity: 120, channel: 0)
17 | }
18 |
19 | func noteOff(pitch: Pitch) {
20 | instrument.stop(noteNumber: MIDINoteNumber(pitch.midiNoteNumber), channel: 0)
21 | }
22 |
23 | init() {
24 | engine.output = PeakLimiter(instrument, attackTime: 0.001, decayTime: 0.001, preGain: 0)
25 |
26 | //Remove pops
27 | instrument.releaseDuration = 0.01
28 | instrument.filterReleaseDuration = 10.0
29 | instrument.filterStrength = 40.0
30 | }
31 | }
32 |
33 | struct DunneSynthView: View {
34 | @StateObject var conductor = DunneSynthConductor()
35 | @Environment(\.colorScheme) var colorScheme
36 |
37 | var body: some View {
38 | NodeOutputView(conductor.instrument)
39 | HStack {
40 | ForEach(0...6, id: \.self){
41 | ParameterRow(param: conductor.instrument.parameters[$0])
42 | }
43 | }.padding(5)
44 | HStack {
45 | ForEach(7...13, id: \.self){
46 | ParameterRow(param: conductor.instrument.parameters[$0])
47 | }
48 | }.padding(5)
49 | CookbookKeyboard(noteOn: conductor.noteOn,
50 | noteOff: conductor.noteOff)
51 | .cookbookNavBarTitle("Dunne Synth")
52 | .onAppear {
53 | conductor.start()
54 | }
55 | .onDisappear {
56 | conductor.stop()
57 | }
58 | .background(colorScheme == .dark ?
59 | Color.clear : Color(red: 0.9, green: 0.9, blue: 0.9))
60 | }
61 | }
62 |
63 |
64 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/WIP/PolyphonicOscillator.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AudioToolbox
5 | import Keyboard
6 | import SoundpipeAudioKit
7 | import SwiftUI
8 | import Tonic
9 |
10 | class PolyphonicOscillatorConductor: ObservableObject, HasAudioEngine {
11 | let engine = AudioEngine()
12 | var notes = Array(repeating: 0, count: 11)
13 | var osc = [Oscillator(), Oscillator(), Oscillator(), Oscillator(), Oscillator(),
14 | Oscillator(), Oscillator(), Oscillator(), Oscillator(), Oscillator(), Oscillator()]
15 |
16 | func noteOn(pitch: Pitch, point _: CGPoint) {
17 | for num in 0 ... 10 {
18 | if notes[num] == 0 {
19 | osc[num].frequency = AUValue(pitch.midiNoteNumber).midiNoteToFrequency()
20 | osc[num].$amplitude.ramp(to: 0.2, duration: 0.005)
21 | notes[num] = pitch.intValue
22 | break
23 | }
24 | }
25 | }
26 |
27 | func noteOff(pitch: Pitch) {
28 | for num in 0 ... 10 {
29 | if notes[num] == pitch.intValue {
30 | osc[num].$amplitude.ramp(to: 0, duration: 0.005)
31 | notes[num] = 0
32 | break
33 | }
34 | }
35 | }
36 |
37 | init() {
38 | for num in 0 ... 10 {
39 | osc[num].amplitude = 0.0
40 | osc[num].start()
41 | }
42 | engine.output = Mixer(osc[0], osc[1], osc[2], osc[3], osc[4], osc[5],
43 | osc[6], osc[7], osc[8], osc[9], osc[10])
44 | }
45 | }
46 |
47 | struct PolyphonicOscillatorView: View {
48 | @StateObject var conductor = PolyphonicOscillatorConductor()
49 | @Environment(\.colorScheme) var colorScheme
50 |
51 | var body: some View {
52 | if conductor.engine.output != nil {
53 | NodeOutputView(conductor.engine.output!)
54 | }
55 | CookbookKeyboard(noteOn: conductor.noteOn,
56 | noteOff: conductor.noteOff)
57 | .cookbookNavBarTitle("Polyphonic Oscillator")
58 | .onAppear {
59 | conductor.start()
60 | }
61 | .onDisappear {
62 | conductor.stop()
63 | }
64 | .background(colorScheme == .dark ?
65 | Color.clear : Color(red: 0.9, green: 0.9, blue: 0.9))
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/WIP/RolandTB303Filter.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SoundpipeAudioKit
6 | import SwiftUI
7 |
8 | class RolandTB303FilterConductor: ObservableObject, ProcessesPlayerInput {
9 | let engine = AudioEngine()
10 | let player = AudioPlayer()
11 | let filter: RolandTB303Filter
12 | let dryWetMixer: DryWetMixer
13 | let buffer: AVAudioPCMBuffer
14 |
15 | init() {
16 | buffer = Cookbook.sourceBuffer
17 | player.buffer = buffer
18 | player.isLooping = true
19 |
20 | filter = RolandTB303Filter(player)
21 | dryWetMixer = DryWetMixer(player, filter)
22 | engine.output = dryWetMixer
23 | }
24 | }
25 |
26 | struct RolandTB303FilterView: View {
27 | @StateObject var conductor = RolandTB303FilterConductor()
28 |
29 | var body: some View {
30 | VStack {
31 | PlayerControls(conductor: conductor)
32 | HStack {
33 | ForEach(conductor.filter.parameters) {
34 | ParameterRow(param: $0)
35 | }
36 | ParameterRow(param: conductor.dryWetMixer.parameters[0])
37 | }
38 | DryWetMixView(dry: conductor.player,
39 | wet: conductor.filter,
40 | mix: conductor.dryWetMixer)
41 | }
42 | .padding()
43 | .cookbookNavBarTitle("Roland Tb303 Filter")
44 | .onAppear {
45 | conductor.start()
46 | }
47 | .onDisappear {
48 | conductor.stop()
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Reusable Components/CallbackLoop.swift:
--------------------------------------------------------------------------------
1 | // Copyright AudioKit. All Rights Reserved. Revision History at http://github.com/AudioKit/AudioKit/
2 | import Foundation
3 |
4 | /// Class to handle an updating loop
5 | public class CallbackLoop: NSObject {
6 | private var internalHandler: () -> Void = {}
7 |
8 | /// Period of loop in seconds
9 | public var duration = 1.0
10 |
11 | /// Frequency of callbacks in Hertz
12 | public var frequency: Double {
13 | get {
14 | 1.0 / duration
15 | }
16 | set {
17 | duration = 1.0 / newValue
18 | }
19 | }
20 |
21 | private var isRunning = false
22 |
23 | /// Repeat this loop at a given period with a code block
24 | ///
25 | /// - parameter period: Interval between block executions
26 | /// - parameter handler: Code block to execute
27 | ///
28 | public init(every period: Double, handler: @escaping () -> Void) {
29 | duration = period
30 | internalHandler = handler
31 | super.init()
32 | update()
33 | }
34 |
35 | /// Repeat this loop at a given frequency with a code block
36 | ///
37 | /// - parameter frequency: Frequency of block executions in Hz
38 | /// - parameter handler: Code block to execute
39 | ///
40 | public init(frequency: Double, handler: @escaping () -> Void) {
41 | duration = 1.0 / frequency
42 | internalHandler = handler
43 | super.init()
44 | update()
45 | }
46 |
47 | /// Start the loop
48 | public func start() {
49 | isRunning = true
50 | update()
51 | }
52 |
53 | /// Stop the loop
54 | public func stop() {
55 | isRunning = false
56 | }
57 |
58 | /// Callback function
59 | @objc func update() {
60 | if isRunning {
61 | if !Thread.isMainThread {
62 | DispatchQueue.main.async { [self] in
63 | self.updateInternal()
64 | }
65 | } else {
66 | updateInternal()
67 | }
68 | }
69 | }
70 |
71 | /// Call the callback function.
72 | /// self.perform only works when executed on the main thread. Called from self.update()
73 | @objc internal func updateInternal() {
74 | if isRunning {
75 | internalHandler()
76 | perform(#selector(updateInternal),
77 | with: nil,
78 | afterDelay: duration,
79 | inModes: [.common])
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Reusable Components/Cookbook.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import AudioKitEX
3 | import AudioKitUI
4 | import AVFoundation
5 | import SwiftUI
6 |
7 | // Helper functions
8 | class Cookbook {
9 | static var sourceBuffer: AVAudioPCMBuffer {
10 | let url = Bundle.module.resourceURL?.appendingPathComponent("Samples/beat.aiff")
11 | let file = try! AVAudioFile(forReading: url!)
12 | return try! AVAudioPCMBuffer(file: file)!
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Reusable Components/CookbookKeyboard.swift:
--------------------------------------------------------------------------------
1 | import AudioKit
2 | import SwiftUI
3 | import Keyboard
4 | import Tonic
5 |
6 | struct CookbookKeyboard: View {
7 | var noteOn: (Pitch, CGPoint) -> Void = { _, _ in }
8 | var noteOff: (Pitch) -> Void
9 | var body: some View {
10 | Keyboard(layout: .piano(pitchRange: Pitch(48) ... Pitch(64)),
11 | noteOn: noteOn, noteOff: noteOff)
12 | }
13 | }
14 |
15 | struct MIDIKitKeyboard: View {
16 | var noteOn: (Pitch, CGPoint) -> Void = { _, _ in }
17 | var noteOff: (Pitch) -> Void
18 | var body: some View {
19 | Keyboard(layout: .piano(pitchRange: Pitch(48) ... Pitch(64)),
20 | noteOn: noteOn, noteOff: noteOff){ pitch, isActivated in
21 | MIDIKitKeyboardKey(pitch: pitch,
22 | isActivated: isActivated, color: .red)
23 | }.cornerRadius(5)
24 | }
25 | }
26 |
27 | struct MIDIKitKeyboardKey: View {
28 | @State var MIDIKeyPressed = [Bool](repeating: false, count: 128)
29 | var pitch : Pitch
30 | var isActivated : Bool
31 | var color: Color
32 |
33 | var body: some View {
34 | VStack{
35 | KeyboardKey(pitch: pitch,
36 | isActivated: isActivated,
37 | text: "",
38 | whiteKeyColor: .white,
39 | blackKeyColor: .black,
40 | pressedColor: color,
41 | flatTop: true,
42 | isActivatedExternally: MIDIKeyPressed[pitch.intValue])
43 | }.onReceive(NotificationCenter.default.publisher(for: .MIDIKey), perform: { obj in
44 | if let userInfo = obj.userInfo, let info = userInfo["info"] as? UInt8, let val = userInfo["bool"] as? Bool {
45 | self.MIDIKeyPressed[Int(info)] = val
46 | }
47 | })
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Reusable Components/CookbookKnob.swift:
--------------------------------------------------------------------------------
1 | import AVFoundation
2 | import Controls
3 | import SwiftUI
4 |
5 | public struct CookbookKnob: View {
6 | var text: String
7 | @Binding var parameter: AUValue
8 | var range: ClosedRange
9 | var format: String = "%0.2f"
10 | var units: String = ""
11 |
12 | public init(text: String,
13 | parameter: Binding,
14 | range: ClosedRange,
15 | units: String = "") {
16 | _parameter = parameter
17 | self.text = text
18 | self.range = range
19 | self.units = units
20 | }
21 |
22 | public var body: some View {
23 | VStack {
24 | VStack {
25 | Text(text)
26 | .minimumScaleFactor(0.2)
27 | .lineLimit(2)
28 | .multilineTextAlignment(.center)
29 | if units == "" || units == "Generic" {
30 | Text("\(parameter, specifier: format)")
31 | .lineLimit(1)
32 | } else if units == "%" || units == "Percent" {
33 | Text("\(parameter * 100, specifier: "%0.f")%")
34 | .lineLimit(1)
35 | } else if units == "Percent-0-100" { // for audio units that use 0-100 instead of 0-1
36 | Text("\(parameter, specifier: "%0.f")%")
37 | .lineLimit(1)
38 | } else if units == "Hertz" {
39 | Text("\(parameter, specifier: "%0.2f") Hz")
40 | .lineLimit(1)
41 | } else {
42 | Text("\(parameter, specifier: format) \(units)")
43 | .lineLimit(1)
44 | }
45 | }
46 | .frame(height: 50)
47 | SmallKnob(value: $parameter, range: range)
48 | }.frame(maxWidth: 150, maxHeight: 200).frame(minHeight: 100)
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Reusable Components/NavigationHelpers.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | struct CookbookNavBarTitle: ViewModifier {
4 | var text: String
5 | func body(content: Content) -> some View {
6 | content
7 | #if !os(macOS)
8 | .navigationBarTitle(Text(text))
9 | #endif
10 | }
11 | }
12 |
13 | extension View {
14 | func cookbookNavBarTitle(_ text: String) -> some View {
15 | modifier(CookbookNavBarTitle(text: text))
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/Bass Synth.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/Bass Synth.mp3
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/Counting.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/Counting.mp3
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/Guitar.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/Guitar.mp3
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/Piano.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/Piano.mp3
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/Strings.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/Strings.mp3
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/Synth.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/Synth.mp3
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/alphabet.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/alphabet.mp3
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/bass_drum_C1.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/bass_drum_C1.wav
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/beat.aiff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/beat.aiff
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/clap_D#1.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/clap_D#1.wav
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/closed_hi_hat_F#1.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/closed_hi_hat_F#1.wav
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/hi_tom_D2.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/hi_tom_D2.wav
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/lo_tom_F1.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/lo_tom_F1.wav
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/mid_tom_B1.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/mid_tom_B1.wav
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/open_hi_hat_A#1.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/open_hi_hat_A#1.wav
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/snare_D1.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/CookbookCommon/Sources/CookbookCommon/Samples/snare_D1.wav
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Sources/CookbookCommon/TestAudioURLs.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | enum TestAudioURLs: String, CaseIterable {
4 | case beat = "beat.aiff",
5 | counting = "Counting.mp3",
6 | guitar = "Guitar.mp3",
7 | bassDrum = "bass_drum_C1.wav",
8 | clap = "clap_D#1.wav",
9 | snare = "snare_D1.wav",
10 | lowTom = "lo_tom_F1.wav",
11 | midTom = "mid_tom_B1.wav",
12 | highTom = "hi_tom_D2.wav"
13 |
14 | func url() -> URL? {
15 | return Bundle.module.url(forResource: "Samples/\(rawValue)", withExtension: "")
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Cookbook/CookbookCommon/Tests/CookbookCommonTests/CookbookCommonTests.swift:
--------------------------------------------------------------------------------
1 | @testable import CookbookCommon
2 | import XCTest
3 |
4 | final class CookbookCommonTests: XCTestCase {
5 | func testExample() throws {
6 | // This is an example of a functional test case.
7 | // Use XCTAssert and related functions to verify your tests produce the correct
8 | // results.
9 | XCTAssertEqual(CookbookCommon().text, "Hello, World!")
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Cookbook/Sounds/Sampler Instruments/drumSimp.exs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Sounds/Sampler Instruments/drumSimp.exs
--------------------------------------------------------------------------------
/Cookbook/Sounds/Sampler Instruments/funkyWow.exs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Sounds/Sampler Instruments/funkyWow.exs
--------------------------------------------------------------------------------
/Cookbook/Sounds/Sampler Instruments/nes-syn1.exs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Sounds/Sampler Instruments/nes-syn1.exs
--------------------------------------------------------------------------------
/Cookbook/Sounds/Sampler Instruments/noisyRez.exs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Sounds/Sampler Instruments/noisyRez.exs
--------------------------------------------------------------------------------
/Cookbook/Sounds/Sampler Instruments/sawPad1.exs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Sounds/Sampler Instruments/sawPad1.exs
--------------------------------------------------------------------------------
/Cookbook/Sounds/Sampler Instruments/sawPiano1.exs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Sounds/Sampler Instruments/sawPiano1.exs
--------------------------------------------------------------------------------
/Cookbook/Sounds/Sampler Instruments/sqrTone1.exs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Sounds/Sampler Instruments/sqrTone1.exs
--------------------------------------------------------------------------------
/Cookbook/Sounds/basicSamples/noise-wht2.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Sounds/basicSamples/noise-wht2.wav
--------------------------------------------------------------------------------
/Cookbook/Sounds/basicSamples/saw220-ana1.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Sounds/basicSamples/saw220-ana1.wav
--------------------------------------------------------------------------------
/Cookbook/Sounds/basicSamples/saw220.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Sounds/basicSamples/saw220.wav
--------------------------------------------------------------------------------
/Cookbook/Sounds/basicSamples/sqr220.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Sounds/basicSamples/sqr220.wav
--------------------------------------------------------------------------------
/Cookbook/Sounds/cheeb-bd.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Sounds/cheeb-bd.wav
--------------------------------------------------------------------------------
/Cookbook/Sounds/cheeb-ch.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Sounds/cheeb-ch.wav
--------------------------------------------------------------------------------
/Cookbook/Sounds/cheeb-hat.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Sounds/cheeb-hat.wav
--------------------------------------------------------------------------------
/Cookbook/Sounds/cheeb-snr.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Sounds/cheeb-snr.wav
--------------------------------------------------------------------------------
/Cookbook/Sounds/cheeb-stick.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Sounds/cheeb-stick.wav
--------------------------------------------------------------------------------
/Cookbook/Sounds/closed_hi_hat_F#1.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/Cookbook/Sounds/closed_hi_hat_F#1.wav
--------------------------------------------------------------------------------
/Cookbook/Sounds/sqr.SFZ:
--------------------------------------------------------------------------------
1 | lokey=0 hikey=127 pitch_keycenter=57 pitch_keytrack=100
2 | lovel=000 hivel=127 amp_velcurve_127=1 loop_mode=loop_continuous loop_start=0 loop_end=220 sample=basicSamples/saw220.wav
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Aurelius Prochazka
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # AudioKit Cookbook for iOS and macOS (via Catalyst)
4 |
5 | [](https://github.com/AudioKit/Cookbook/actions?query=workflow%3ACI)
6 | [](https://github.com/AudioKit/AudioKit/blob/v5-main/LICENSE)
7 | [](https://github.com/AudioKit/AudioKit/)
8 | [](https://houndci.com)
9 | [](http://twitter.com/AudioKitPro)
10 |
11 | ## Canonical Examples for Using the AudioKit 5 Swift Package
12 |
13 | Most of the examples that were inside of [AudioKit](https://github.com/AudioKit/AudioKit/) are now in this single iOS / macOS Catalyst application.
14 |
15 | ## Top Level Overview
16 |
17 | * `ContentView.swift` contains the menu screen.
18 | * `Recipes/` contain all of the one-screen demos.
19 | * `Resources/`, `Samples`, and `Sounds` contain shared audio and MIDI content.
20 | * `Reusable Components/` contains the code widgets that are shared between recipes.
21 |
22 | ## Recipes
23 |
24 | Each recipe is one file that contains a few related objects:
25 |
26 | * `Conductor` sets up all the AudioKit signal processing.
27 | * `Data` is a structure that holds the state of the demo. It is used by both the view and the conductor.
28 | * `View` creates the SwiftUI user interface for the recipe.
29 |
30 | ## On-going development
31 |
32 | Since this is the primary example for AudioKit, it will continue to evolve as AudioKit does. There are plenty of opportunities to help out.
33 | Check out [Github Issues](https://github.com/AudioKit/Cookbook/issues) for some specific requests.
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/Xcode-config/DEVELOPMENT_TEAM.template.xcconfig:
--------------------------------------------------------------------------------
1 | DEVELOPMENT_TEAM = AB1234C5DE
2 |
--------------------------------------------------------------------------------
/Xcode-config/Shared.xcconfig:
--------------------------------------------------------------------------------
1 | DEVELOPMENT_TEAM = 9W69ZP8S5F
2 |
3 | #include? "DEVELOPMENT_TEAM.xcconfig"
4 |
5 | // Create the file DEVELOPMENT_TEAM.xcconfig
6 | // in the "Xcode-config" directory within the project directory
7 | // with the following build setting:
8 | // DEVELOPMENT_TEAM = [Your TeamID]
9 |
10 | // One way to find your Team ID is to set the “Development Team”
11 | // build setting (Xcode key: "DEVELOPMENT_TEAM") and have a look
12 | // at the “Source Control” changes (menu item “Commit…”/⌥⌘C).
13 | // Just make sure that this change doesn’t actually get committed.
14 |
15 | // You can also find your Team ID by logging into your Apple Developer account
16 | // and going to
17 | // https://developer.apple.com/account/#/membership
18 | // It should be listed under “Team ID”.
19 |
20 | // To set this system up for your own project,
21 | // copy the "Xcode-config" directory there,
22 | // add it to your Xcode project,
23 | // navigate to your project settings
24 | // (root icon in the Xcode Project Navigator)
25 | // click on the project icon there,
26 | // click on the “Info” tab
27 | // under “Configurations”
28 | // open the “Debug”, “Release”,
29 | // and any other build configurations you might have.
30 | // There you can set the pull-down menus in the
31 | // “Based on Configuration File” column to “Shared”.
32 | // Your work in Xcode is done.
33 |
34 | // Don’t forget to add the DEVELOPMENT_TEAM.xcconfig file to your .gitignore:
35 | // # User-specific xcconfig files
36 | // Xcode-config/DEVELOPMENT_TEAM.xcconfig
37 | // The two lines above are an example.
38 | // Please don’t copy the comment slashes over though.
39 |
40 | // You can and should now replace the “DevelopmentTeam = AB1234C5DE;” entries in
41 | // .xcodeproj/project.pbxproj
42 | // with “DevelopmentTeam = "";”
43 | // They would otherwise override the Team ID set via this config file and its include.
44 | // Please note that .pbxproj files use straight quotes.
45 |
46 | // When you commit changes to the Xcode project file
47 | // after changing settings in “Signing & Capabilities”
48 | // Entries like these may appear in your file changes/commit diff preview:
49 | // CODE_SIGN_IDENTITY = …;
50 | // CODE_SIGN_STYLE = Manual/Automatic;
51 | // Please make sure not to commit them to source control.
52 |
--------------------------------------------------------------------------------
/images/Cookbook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/images/Cookbook.png
--------------------------------------------------------------------------------
/images/Cookbook2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/images/Cookbook2.png
--------------------------------------------------------------------------------
/images/CookbookMac.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AudioKit/Cookbook/86f829c14f3bd8b672513b86a612128dd4154e8a/images/CookbookMac.png
--------------------------------------------------------------------------------