├── AnalogSynthX ├── Assets.xcassets │ ├── Contents.json │ ├── AppIcon.appiconset │ │ ├── Icon-29.png │ │ ├── Icon-40.png │ │ ├── Icon-76.png │ │ ├── Icon-29@2x.png │ │ ├── Icon-40@2x.png │ │ ├── Icon-76@2x.png │ │ ├── Icon-83.5@2x.png │ │ ├── iTunesArtwork3_1024.png │ │ └── Contents.json │ ├── blackkey.imageset │ │ ├── blackkey.png │ │ ├── blackkey@2x.png │ │ └── Contents.json │ ├── wave_saw.imageset │ │ ├── wave_saw.png │ │ ├── wave_saw@2x.png │ │ └── Contents.json │ ├── whitekey.imageset │ │ ├── whitekey.png │ │ ├── whitekey@2x.png │ │ └── Contents.json │ ├── button_on.imageset │ │ ├── button_on.png │ │ ├── button_on@2x.png │ │ └── Contents.json │ ├── switch_on.imageset │ │ ├── switch_on.png │ │ ├── switch_on@2x.png │ │ └── Contents.json │ ├── wave_sine.imageset │ │ ├── wave_sine.png │ │ ├── wave_sine@2x.png │ │ └── Contents.json │ ├── button_off.imageset │ │ ├── button_off.png │ │ ├── button_off@2x.png │ │ └── Contents.json │ ├── slider_top.imageset │ │ ├── slider_top.png │ │ ├── slider_top@2x.png │ │ └── Contents.json │ ├── switch_off.imageset │ │ ├── switch_off.png │ │ ├── switch_off@2x.png │ │ └── Contents.json │ ├── wave_upSaw.imageset │ │ ├── wave_upSaw.png │ │ ├── wave_upSaw@2x.png │ │ └── Contents.json │ ├── button_left.imageset │ │ ├── button_left.png │ │ ├── button_left@2x.png │ │ └── Contents.json │ ├── button_right.imageset │ │ ├── button_right.png │ │ ├── button_right@2x.png │ │ └── Contents.json │ ├── roundbtn_off.imageset │ │ ├── roundbtn_off.png │ │ ├── roundbtn_off@2x.png │ │ └── Contents.json │ ├── roundbtn_on.imageset │ │ ├── roundbtn_on.png │ │ ├── roundbtn_on@2x.png │ │ └── Contents.json │ ├── slider_track.imageset │ │ ├── slider_track.png │ │ ├── slider_track@2x.png │ │ └── Contents.json │ ├── wave_downSaw.imageset │ │ ├── wave_downSaw.png │ │ ├── wave_downSaw@2x.png │ │ └── Contents.json │ ├── wave_pulse.imageset │ │ ├── wave_pulse@2x.png │ │ └── Contents.json │ ├── wave_square.imageset │ │ ├── wave_square.png │ │ ├── wave_square@2x.png │ │ └── Contents.json │ ├── Brand Assets.launchimage │ │ ├── launchimage.png │ │ ├── launchimage@2x.png │ │ └── Contents.json │ ├── UpperKeyPanel.imageset │ │ ├── UpperKeyPanel.png │ │ ├── UpperKeyPanel@2x.png │ │ └── Contents.json │ ├── wave_triangle.imageset │ │ ├── wave_triangle.png │ │ ├── wave_triangle@2x.png │ │ └── Contents.json │ ├── controls_guide.imageset │ │ ├── controls_guide.png │ │ ├── controls_guide@2x.png │ │ └── Contents.json │ ├── blackkey_pressed.imageset │ │ ├── blackkey_pressed.png │ │ ├── blackkey_pressed@2x.png │ │ └── Contents.json │ ├── blackkey_selected.imageset │ │ ├── blackkey_selected.png │ │ ├── blackkey_selected@2x.png │ │ └── Contents.json │ ├── wave_saw_selected.imageset │ │ ├── wave_saw_selected.png │ │ ├── wave_saw_selected@2x.png │ │ └── Contents.json │ ├── whitekey_pressed.imageset │ │ ├── whitekey_pressed.png │ │ ├── whitekey_pressed@2x.png │ │ └── Contents.json │ ├── whitekey_selected.imageset │ │ ├── whitekey_selected.png │ │ ├── whitekey_selected@2x.png │ │ └── Contents.json │ ├── wave_sine_selected.imageset │ │ ├── wave_sine_selected.png │ │ ├── wave_sine_selected@2x.png │ │ └── Contents.json │ ├── wave_upSaw_selected.imageset │ │ ├── wave_upSaw_selected.png │ │ ├── wave_upSaw_selected@2x.png │ │ └── Contents.json │ ├── wave_pulse_selected.imageset │ │ ├── wave_pulse_selected@2x.png │ │ └── Contents.json │ ├── wave_square_selected.imageset │ │ ├── wave_square_selected.png │ │ ├── wave_square_selected@2x.png │ │ └── Contents.json │ ├── button_left_highlight.imageset │ │ ├── button_left_highlight.png │ │ ├── button_left_highlight@2x.png │ │ └── Contents.json │ ├── button_right_highlight.imageset │ │ ├── button_right_highlight.png │ │ ├── button_right_highlight@2x.png │ │ └── Contents.json │ ├── wave_downSaw_selected.imageset │ │ ├── wave_downSaw_selected.png │ │ ├── wave_downSaw_selected@2x.png │ │ └── Contents.json │ └── wave_triangle_selected.imageset │ │ ├── wave_triangle_selected.png │ │ ├── wave_triangle_selected@2x.png │ │ └── Contents.json ├── AnalogSynthX.entitlements ├── AppDelegate.swift ├── Audiobus.txt ├── AnalogSynthX-Bridging-Header.h ├── Extensions │ ├── CGFloat+Extensions.swift │ ├── String+RandomGreeting.swift │ ├── Double+Extensions.swift │ └── WaveformSegmentedView+Extensions.swift ├── CustomControls │ ├── RoundedButton.swift │ ├── WaveformSegmentedView.swift │ ├── Knob+Touches.swift │ ├── Knob.swift │ ├── VerticalSlider.swift │ └── KnobStyleKit.swift ├── AudioSystem │ ├── Fatten.swift │ ├── FilterSection.swift │ ├── Conductor.swift │ ├── MultiDelay.swift │ └── GeneratorBank.swift ├── SMSegmentView │ ├── SMBasicSegment.swift │ ├── SMAlphaImageSegment.swift │ ├── SMSegmentView.swift │ ├── SMBasicSegmentView.swift │ └── SMSegment.swift ├── Info.plist ├── SynthVC+UIHelpers.swift ├── SynthVC+NoteNames.swift ├── Audiobus.swift └── SynthViewController.swift ├── AnalogSynthX.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata ├── xcshareddata │ └── xcschemes │ │ └── AnalogSynthX.xcscheme └── project.pbxproj ├── AnalogSynthX.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── .travis.yml ├── Podfile ├── Podfile.lock ├── LICENSE ├── .gitignore └── README.md /AnalogSynthX/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/AppIcon.appiconset/Icon-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/AppIcon.appiconset/Icon-29.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/AppIcon.appiconset/Icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/AppIcon.appiconset/Icon-40.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/AppIcon.appiconset/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/AppIcon.appiconset/Icon-76.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/blackkey.imageset/blackkey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/blackkey.imageset/blackkey.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_saw.imageset/wave_saw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_saw.imageset/wave_saw.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/whitekey.imageset/whitekey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/whitekey.imageset/whitekey.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/blackkey.imageset/blackkey@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/blackkey.imageset/blackkey@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/button_on.imageset/button_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/button_on.imageset/button_on.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/switch_on.imageset/switch_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/switch_on.imageset/switch_on.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_saw.imageset/wave_saw@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_saw.imageset/wave_saw@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_sine.imageset/wave_sine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_sine.imageset/wave_sine.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/whitekey.imageset/whitekey@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/whitekey.imageset/whitekey@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/button_off.imageset/button_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/button_off.imageset/button_off.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/button_on.imageset/button_on@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/button_on.imageset/button_on@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/slider_top.imageset/slider_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/slider_top.imageset/slider_top.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/switch_off.imageset/switch_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/switch_off.imageset/switch_off.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/switch_on.imageset/switch_on@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/switch_on.imageset/switch_on@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_sine.imageset/wave_sine@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_sine.imageset/wave_sine@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_upSaw.imageset/wave_upSaw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_upSaw.imageset/wave_upSaw.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/button_left.imageset/button_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/button_left.imageset/button_left.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/button_off.imageset/button_off@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/button_off.imageset/button_off@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/button_right.imageset/button_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/button_right.imageset/button_right.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/roundbtn_off.imageset/roundbtn_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/roundbtn_off.imageset/roundbtn_off.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/roundbtn_on.imageset/roundbtn_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/roundbtn_on.imageset/roundbtn_on.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/slider_top.imageset/slider_top@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/slider_top.imageset/slider_top@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/slider_track.imageset/slider_track.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/slider_track.imageset/slider_track.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/switch_off.imageset/switch_off@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/switch_off.imageset/switch_off@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_downSaw.imageset/wave_downSaw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_downSaw.imageset/wave_downSaw.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_pulse.imageset/wave_pulse@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_pulse.imageset/wave_pulse@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_square.imageset/wave_square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_square.imageset/wave_square.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_upSaw.imageset/wave_upSaw@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_upSaw.imageset/wave_upSaw@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/Brand Assets.launchimage/launchimage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/Brand Assets.launchimage/launchimage.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/UpperKeyPanel.imageset/UpperKeyPanel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/UpperKeyPanel.imageset/UpperKeyPanel.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/button_left.imageset/button_left@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/button_left.imageset/button_left@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/roundbtn_on.imageset/roundbtn_on@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/roundbtn_on.imageset/roundbtn_on@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_square.imageset/wave_square@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_square.imageset/wave_square@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_triangle.imageset/wave_triangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_triangle.imageset/wave_triangle.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/AppIcon.appiconset/iTunesArtwork3_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/AppIcon.appiconset/iTunesArtwork3_1024.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/Brand Assets.launchimage/launchimage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/Brand Assets.launchimage/launchimage@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/UpperKeyPanel.imageset/UpperKeyPanel@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/UpperKeyPanel.imageset/UpperKeyPanel@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/button_right.imageset/button_right@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/button_right.imageset/button_right@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/controls_guide.imageset/controls_guide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/controls_guide.imageset/controls_guide.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/roundbtn_off.imageset/roundbtn_off@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/roundbtn_off.imageset/roundbtn_off@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/slider_track.imageset/slider_track@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/slider_track.imageset/slider_track@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_downSaw.imageset/wave_downSaw@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_downSaw.imageset/wave_downSaw@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_triangle.imageset/wave_triangle@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_triangle.imageset/wave_triangle@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/controls_guide.imageset/controls_guide@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/controls_guide.imageset/controls_guide@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/blackkey_pressed.imageset/blackkey_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/blackkey_pressed.imageset/blackkey_pressed.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/blackkey_selected.imageset/blackkey_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/blackkey_selected.imageset/blackkey_selected.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_saw_selected.imageset/wave_saw_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_saw_selected.imageset/wave_saw_selected.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/whitekey_pressed.imageset/whitekey_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/whitekey_pressed.imageset/whitekey_pressed.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/whitekey_selected.imageset/whitekey_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/whitekey_selected.imageset/whitekey_selected.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/blackkey_pressed.imageset/blackkey_pressed@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/blackkey_pressed.imageset/blackkey_pressed@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_sine_selected.imageset/wave_sine_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_sine_selected.imageset/wave_sine_selected.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/whitekey_pressed.imageset/whitekey_pressed@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/whitekey_pressed.imageset/whitekey_pressed@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/blackkey_selected.imageset/blackkey_selected@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/blackkey_selected.imageset/blackkey_selected@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_saw_selected.imageset/wave_saw_selected@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_saw_selected.imageset/wave_saw_selected@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_sine_selected.imageset/wave_sine_selected@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_sine_selected.imageset/wave_sine_selected@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_upSaw_selected.imageset/wave_upSaw_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_upSaw_selected.imageset/wave_upSaw_selected.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/whitekey_selected.imageset/whitekey_selected@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/whitekey_selected.imageset/whitekey_selected@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_pulse_selected.imageset/wave_pulse_selected@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_pulse_selected.imageset/wave_pulse_selected@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_square_selected.imageset/wave_square_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_square_selected.imageset/wave_square_selected.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_upSaw_selected.imageset/wave_upSaw_selected@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_upSaw_selected.imageset/wave_upSaw_selected@2x.png -------------------------------------------------------------------------------- /AnalogSynthX.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/button_left_highlight.imageset/button_left_highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/button_left_highlight.imageset/button_left_highlight.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/button_right_highlight.imageset/button_right_highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/button_right_highlight.imageset/button_right_highlight.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_downSaw_selected.imageset/wave_downSaw_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_downSaw_selected.imageset/wave_downSaw_selected.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_square_selected.imageset/wave_square_selected@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_square_selected.imageset/wave_square_selected@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_triangle_selected.imageset/wave_triangle_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_triangle_selected.imageset/wave_triangle_selected.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/button_left_highlight.imageset/button_left_highlight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/button_left_highlight.imageset/button_left_highlight@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_downSaw_selected.imageset/wave_downSaw_selected@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_downSaw_selected.imageset/wave_downSaw_selected@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/button_right_highlight.imageset/button_right_highlight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/button_right_highlight.imageset/button_right_highlight@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_triangle_selected.imageset/wave_triangle_selected@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogcode/AnalogSynthX/HEAD/AnalogSynthX/Assets.xcassets/wave_triangle_selected.imageset/wave_triangle_selected@2x.png -------------------------------------------------------------------------------- /AnalogSynthX/AnalogSynthX.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | inter-app-audio 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /AnalogSynthX.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /AnalogSynthX.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode9.3 3 | env: 4 | - LANG=en_US.UTF-8 LC_CTYPE=en_US.UTF-8 5 | before_install: 6 | - pod repo update 7 | - pod install 8 | script: 9 | - xcodebuild -workspace AnalogSynthX.xcworkspace -sdk iphonesimulator -scheme AnalogSynthX -arch x86_64 ONLY_ACTIVE_ARCH=YES CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY="" clean build 10 | -------------------------------------------------------------------------------- /AnalogSynthX/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // AnalogSynthX 4 | // 5 | // Created by Aurelius Prochazka, revision history on Github. 6 | // Copyright © 2018 AudioKit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | } 17 | -------------------------------------------------------------------------------- /AnalogSynthX/Audiobus.txt: -------------------------------------------------------------------------------- 1 | H4sIAAAAAAAAA22MsQ6CMBRFf4W8GSnKxubs6GJiDSm0SiO0pK/P0BD+3dLoYOJ6zr1nATVP2gWoyxxaMnJQjRGjghqORgz2cQ7G9xfIgdzQYNer5ERyuLl5ty/KQpDUtiWsOeMsrifrPEJ9XcCHKT3I6ch/2lmKZ1tdKuycnry25p9Gar8dg3MEozB0F50np9x2oJOP9KUcpsJhveWgZTScfSBy9lSBs6osK1jfFS7eifgAAAA=:CeLNwT/sajoy2B4B5pZ61ZCUCID2w0mUPgfS2jhfGvgqXz33DlAXj2aGjQem0gAFa3oE/82J9WMkv5oLNLAotNj3/dmXGhQ8HBv76zN3NJu5NGuGGOjj6Ykjog3w4PKz 2 | -------------------------------------------------------------------------------- /AnalogSynthX/AnalogSynthX-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // AnalogSynthX-BridgingHeader.h 3 | // AnalogSynthX 4 | // 5 | // Created by Aurelius Prochazka, revision history on Githbub. 6 | // Copyright © 2018 AudioKit. All rights reserved. 7 | // 8 | 9 | #ifndef AnalogSynthX_BridgingHeader_h 10 | #define AnalogSynthX_BridgingHeader_h 11 | 12 | #import "Audiobus.h" 13 | 14 | #endif /* AnalogSynthX_BridgingHeader_h */ 15 | -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_pulse.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "wave_pulse@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /AnalogSynthX/Extensions/CGFloat+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CGFloat+Extensions.swift 3 | // AnalogSynthX 4 | // 5 | // Created by Matthew Fecher, revision history on Githbub. 6 | // Copyright © 2018 AudioKit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension CGFloat { 12 | 13 | // Formatted percentage string e.g. 0.55 -> 55% 14 | var percentageString: String { 15 | return "\(Int(100 * self))%" 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_pulse_selected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "wave_pulse_selected@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /AnalogSynthX/CustomControls/RoundedButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RoundedButton.swift 3 | // Swift Synth 4 | // 5 | // Created by Matthew Fecher, revision history on Githbub. 6 | // Copyright (c) 2016 AudioKit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class RoundedButton: UIButton { 12 | required init?(coder aDecoder: NSCoder) { 13 | super.init(coder: aDecoder) 14 | 15 | clipsToBounds = true 16 | layer.cornerRadius = 6 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/blackkey.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "blackkey.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "blackkey@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/button_on.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "button_on.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "button_on@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/switch_on.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "switch_on.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "switch_on@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_saw.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "wave_saw.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "wave_saw@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_sine.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "wave_sine.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "wave_sine@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/whitekey.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "whitekey.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "whitekey@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/button_left.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "button_left.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "button_left@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/button_off.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "button_off.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "button_off@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/roundbtn_on.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "roundbtn_on.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "roundbtn_on@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/slider_top.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "slider_top.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "slider_top@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/switch_off.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "switch_off.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "switch_off@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_square.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "wave_square.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "wave_square@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_upSaw.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "wave_upSaw.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "wave_upSaw@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/button_right.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "button_right.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "button_right@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/roundbtn_off.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "roundbtn_off.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "roundbtn_off@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/slider_track.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "slider_track.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "slider_track@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_downSaw.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "wave_downSaw.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "wave_downSaw@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/UpperKeyPanel.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "UpperKeyPanel.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "UpperKeyPanel@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/controls_guide.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "controls_guide.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "controls_guide@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_triangle.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "wave_triangle.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "wave_triangle@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/blackkey_pressed.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "blackkey_pressed.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "blackkey_pressed@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/whitekey_pressed.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "whitekey_pressed.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "whitekey_pressed@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/blackkey_selected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "blackkey_selected.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "blackkey_selected@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_saw_selected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "wave_saw_selected.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "wave_saw_selected@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/whitekey_selected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "whitekey_selected.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "whitekey_selected@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_sine_selected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "wave_sine_selected.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "wave_sine_selected@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_upSaw_selected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "wave_upSaw_selected.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "wave_upSaw_selected@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/button_left_highlight.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "button_left_highlight.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "button_left_highlight@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_downSaw_selected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "wave_downSaw_selected.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "wave_downSaw_selected@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_square_selected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "wave_square_selected.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "wave_square_selected@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/button_right_highlight.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "button_right_highlight.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "button_right_highlight@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/wave_triangle_selected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "wave_triangle_selected.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "wave_triangle_selected@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | platform :ios, '10.0' 3 | 4 | # Comment the following line to switch to the mainstream AudioKit pod 5 | source 'https://github.com/AudioKit/Specs.git' 6 | source 'https://github.com/CocoaPods/Specs.git' 7 | 8 | target 'AnalogSynthX' do 9 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks 10 | use_frameworks! 11 | 12 | # Pods for AnalogSynthX 13 | pod 'AudioKit' 14 | pod 'Audiobus' 15 | 16 | end 17 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Audiobus (3.0.0) 3 | - AudioKit (4.2.4): 4 | - AudioKit/UI (= 4.2.4) 5 | - AudioKit/UI (4.2.4) 6 | 7 | DEPENDENCIES: 8 | - Audiobus 9 | - AudioKit 10 | 11 | SPEC REPOS: 12 | https://github.com/CocoaPods/Specs.git: 13 | - Audiobus 14 | - AudioKit 15 | 16 | SPEC CHECKSUMS: 17 | Audiobus: ef8074b6b7409c9409b89241f6d7e9086e7cf237 18 | AudioKit: 90ed0de2bc50ab68306f4b424ae1622fc9149b8e 19 | 20 | PODFILE CHECKSUM: 81f15dbed0d035bf8a5f1881857399fb0a4d3200 21 | 22 | COCOAPODS: 1.5.0 23 | -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/Brand Assets.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "landscape", 5 | "idiom" : "ipad", 6 | "filename" : "launchimage.png", 7 | "extent" : "full-screen", 8 | "minimum-system-version" : "7.0", 9 | "scale" : "1x" 10 | }, 11 | { 12 | "orientation" : "landscape", 13 | "idiom" : "ipad", 14 | "filename" : "launchimage@2x.png", 15 | "extent" : "full-screen", 16 | "minimum-system-version" : "7.0", 17 | "scale" : "2x" 18 | } 19 | ], 20 | "info" : { 21 | "version" : 1, 22 | "author" : "xcode" 23 | } 24 | } -------------------------------------------------------------------------------- /AnalogSynthX/Extensions/String+RandomGreeting.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+RandomGreeting.swift 3 | // AnalogSynthX 4 | // 5 | // Created by Matthew Fecher, revision history on Githbub. 6 | // Copyright © 2018 AudioKit. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension String { 12 | public static func randomGreeting() -> String { 13 | let randomInt = floor(Double.random(min: 0, max: 4)) 14 | switch randomInt { 15 | case 0: 16 | return "Plug in headphones for best sound." 17 | case 1: 18 | return "Affirmative, Dave. I read you." 19 | case 2: 20 | return "Eat. Swift. Synth. Repeat." 21 | case 3: 22 | return "Welcome!" 23 | default: 24 | return "Welcome" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /AnalogSynthX/CustomControls/WaveformSegmentedView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WaveformSegmentedView.swift 3 | // AnalogSynthX 4 | // 5 | // Created by Matthew Fecher, revision history on Githbub. 6 | // Copyright © 2018 AudioKit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class WaveformSegmentedView: SMSegmentView { 12 | 13 | func setOscColors() { 14 | separatorColour = .clear 15 | separatorWidth = 0.5 16 | segmentOnSelectionColour = #colorLiteral(red: 34.0 / 255.0, 17 | green: 34.0 / 255.0, 18 | blue: 34.0 / 255.0, 19 | alpha: 1.0) 20 | segmentOffSelectionColour = .clear 21 | segmentVerticalMargin = CGFloat(10.0) 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /AnalogSynthX/CustomControls/Knob+Touches.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Knob+Touches.swift 3 | // Swift Synth 4 | // 5 | // Created by Matthew Fecher, revision history on Githbub. 6 | // Copyright © 2018 AudioKit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension Knob { 12 | 13 | override func touchesBegan(_ touches: Set, with event: UIEvent?) { 14 | for touch in touches { 15 | let touchPoint = touch.location(in: self) 16 | lastX = touchPoint.x 17 | lastY = touchPoint.y 18 | } 19 | } 20 | 21 | override func touchesMoved(_ touches: Set, with event: UIEvent?) { 22 | for touch in touches { 23 | let touchPoint = touch.location(in: self) 24 | setPercentagesWithTouchPoint(touchPoint) 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /AnalogSynthX/AudioSystem/Fatten.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Fatten.swift 3 | // AnalogSynthX 4 | // 5 | // Created by Aurelius Prochazka, revision history on Github. 6 | // Copyright © 2018 AudioKit. All rights reserved. 7 | // 8 | 9 | import AudioKit 10 | 11 | class Fatten: AKNode, AKInput { 12 | var dryWetMix: AKDryWetMixer 13 | var delay: AKDelay 14 | var pannedDelay: AKPanner 15 | var pannedSource: AKPanner 16 | var wet: AKMixer 17 | var inputMixer = AKMixer() 18 | 19 | var inputNode: AVAudioNode { 20 | return inputMixer.avAudioNode 21 | } 22 | 23 | init(_ input: AKNode) { 24 | input.connect(to: inputMixer) 25 | delay = AKDelay(inputMixer, time: 0.05, dryWetMix: 1) 26 | pannedDelay = AKPanner(delay, pan: 1) 27 | pannedSource = AKPanner(inputMixer, pan: -1) 28 | wet = AKMixer(pannedDelay, pannedSource) 29 | dryWetMix = AKDryWetMixer(inputMixer, wet, balance: 0) 30 | super.init() 31 | self.avAudioNode = dryWetMix.avAudioNode 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 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 | -------------------------------------------------------------------------------- /AnalogSynthX/SMSegmentView/SMBasicSegment.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SMBasicSegment.swift 3 | // SMSegmentViewController 4 | // 5 | // Created by mlaskowski, revision history on Githbub. 6 | // Copyright © 2016 si.ma. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | open class SMBasicSegment: UIView { 13 | open internal(set) var index: Int = 0 14 | open internal(set) weak var segmentView: SMBasicSegmentView? 15 | 16 | open fileprivate(set) var isSelected: Bool = false 17 | 18 | required public init?(coder aDecoder: NSCoder) { 19 | fatalError("init(coder:) has not been implemented") 20 | } 21 | 22 | override public init(frame: CGRect) { 23 | super.init(frame: frame) 24 | } 25 | 26 | // MARK: Selections 27 | internal func setSelected(_ selected: Bool, inView view: SMBasicSegmentView) { 28 | self.isSelected = selected 29 | } 30 | 31 | open func orientationChangedTo(_ mode: SegmentOrganiseMode) { 32 | 33 | } 34 | 35 | override open func touchesEnded(_ touches: Set, with event: UIEvent?) { 36 | super.touchesEnded(touches, with: event) 37 | if self.isSelected == false { 38 | self.segmentView?.selectSegmentAtIndex(self.index) 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /AnalogSynthX/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "ipad", 5 | "size" : "20x20", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "ipad", 10 | "size" : "20x20", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "size" : "29x29", 15 | "idiom" : "ipad", 16 | "filename" : "Icon-29.png", 17 | "scale" : "1x" 18 | }, 19 | { 20 | "size" : "29x29", 21 | "idiom" : "ipad", 22 | "filename" : "Icon-29@2x.png", 23 | "scale" : "2x" 24 | }, 25 | { 26 | "size" : "40x40", 27 | "idiom" : "ipad", 28 | "filename" : "Icon-40.png", 29 | "scale" : "1x" 30 | }, 31 | { 32 | "size" : "40x40", 33 | "idiom" : "ipad", 34 | "filename" : "Icon-40@2x.png", 35 | "scale" : "2x" 36 | }, 37 | { 38 | "size" : "76x76", 39 | "idiom" : "ipad", 40 | "filename" : "Icon-76.png", 41 | "scale" : "1x" 42 | }, 43 | { 44 | "size" : "76x76", 45 | "idiom" : "ipad", 46 | "filename" : "Icon-76@2x.png", 47 | "scale" : "2x" 48 | }, 49 | { 50 | "size" : "83.5x83.5", 51 | "idiom" : "ipad", 52 | "filename" : "Icon-83.5@2x.png", 53 | "scale" : "2x" 54 | }, 55 | { 56 | "size" : "1024x1024", 57 | "idiom" : "ios-marketing", 58 | "filename" : "iTunesArtwork3_1024.png", 59 | "scale" : "1x" 60 | } 61 | ], 62 | "info" : { 63 | "version" : 1, 64 | "author" : "xcode" 65 | } 66 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | .build/ 41 | 42 | # CocoaPods 43 | # 44 | # We recommend against adding the Pods directory to your .gitignore. However 45 | # you should judge for yourself, the pros and cons are mentioned at: 46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 47 | # 48 | # Pods/ 49 | 50 | # Carthage 51 | # 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | # Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 63 | 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | 69 | # CocoaPods 70 | 71 | Pods/* -------------------------------------------------------------------------------- /AnalogSynthX/Extensions/Double+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Double+Extensions.swift 3 | // Swift Synth 4 | // 5 | // Created by Matthew Fecher, revision history on Githbub. 6 | // Copyright © 2018 AudioKit. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // ********************************************************* 12 | // MARK: - UI Helper Extensions 13 | // ********************************************************* 14 | 15 | extension Double { 16 | 17 | // Return string formatted to 2 decimal places 18 | var decimalString: String { 19 | return String(format: "%.02f", self) 20 | } 21 | 22 | // Return string shifted 3 decimal places to left 23 | var decimal1000String: String { 24 | let newValue = 1_000 * self 25 | return String(format: "%.02f", newValue) 26 | } 27 | 28 | // ********************************************************* 29 | // MARK: - Random Generators 30 | // ********************************************************* 31 | 32 | // return random number between 0.0 and 1.0 33 | public static func random() -> Double { 34 | return Double(arc4random()) / 0xFFFFFFFF 35 | } 36 | 37 | // return random number in range 38 | public static func random(min: Double, max: Double) -> Double { 39 | return Double.random() * (max - min) + min 40 | } 41 | 42 | // return either -1 or 1 randomly 43 | public static func randomSign() -> Double { 44 | return (arc4random_uniform(2) == 0) ? 1.0 : -1.0 45 | } 46 | 47 | // ********************************************************* 48 | // MARK: - Scale Range 49 | // ********************************************************* 50 | 51 | // Linear scale 0.0 to 1.0 to any range 52 | public static func scaleRange(_ value: Double, rangeMin: Double, rangeMax: Double) -> Double { 53 | return ((rangeMax - rangeMin) * (value - 0.0) / (1.0 - 0.0)) + rangeMin 54 | } 55 | 56 | // Logarithmically scale 0.0 to 1.0 to any range 57 | public static func scaleRangeLog(_ value: Double, rangeMin: Double, rangeMax: Double) -> Double { 58 | let scale = (log(rangeMax) - log(rangeMin)) 59 | return exp(log(rangeMin) + (scale * value)) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /AnalogSynthX/AudioSystem/FilterSection.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FilterSection.swift 3 | // AnalogSynthX 4 | // 5 | // Created by Aurelius Prochazka, revision history on Github. 6 | // Copyright © 2018 AudioKit. All rights reserved. 7 | // 8 | 9 | import AudioKit 10 | 11 | class FilterSection: AKNode, AKInput { 12 | var parameters: [Double] = [1_000, 0.9, 1_000, 1, 0] 13 | 14 | var cutoffFrequency: Double = 1_000 { 15 | didSet { 16 | parameters[0] = cutoffFrequency 17 | output.parameters = parameters 18 | } 19 | } 20 | 21 | var resonance: Double = 0.9 { 22 | didSet { 23 | parameters[1] = resonance 24 | output.parameters = parameters 25 | } 26 | } 27 | 28 | var lfoAmplitude: Double = 1_000 { 29 | didSet { 30 | parameters[2] = lfoAmplitude 31 | output.parameters = parameters 32 | } 33 | } 34 | 35 | var lfoRate: Double = 1 { 36 | didSet { 37 | parameters[3] = lfoRate 38 | output.parameters = parameters 39 | } 40 | } 41 | 42 | var lfoIndex: Double = 0 { 43 | didSet { 44 | parameters[4] = lfoIndex 45 | output.parameters = parameters 46 | } 47 | } 48 | 49 | var output: AKOperationEffect 50 | 51 | var inputNode: AVAudioNode { 52 | return output.avAudioNode 53 | } 54 | 55 | init(_ input: AKNode) { 56 | 57 | output = AKOperationEffect(input) { input, parameters in 58 | 59 | let cutoff = parameters[0] 60 | let rez = parameters[1] 61 | let oscAmp = parameters[2] 62 | let oscRate = parameters[3] 63 | let oscIndex = parameters[4] 64 | 65 | let lfo = AKOperation.morphingOscillator(frequency: oscRate, 66 | amplitude: oscAmp, 67 | index: oscIndex) 68 | 69 | return input.moogLadderFilter(cutoffFrequency: max(lfo + cutoff, 0), 70 | resonance: rez) 71 | } 72 | output.parameters = parameters 73 | 74 | super.init() 75 | self.avAudioNode = output.avAudioNode 76 | 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /AnalogSynthX/Extensions/WaveformSegmentedView+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SMSegmentView+Extensions.swift 3 | // Swift Synth 4 | // 5 | // Created by Matthew Fecher, revision history on Githbub. 6 | // Copyright © 2018 AudioKit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension WaveformSegmentedView { 12 | 13 | func addOscWaveforms() { 14 | // Add segments 15 | let _ = self.addSegmentWithTitle("", 16 | onSelectionImage: UIImage(named: "wave_triangle_selected"), 17 | offSelectionImage: UIImage(named: "wave_triangle")) 18 | let _ = self.addSegmentWithTitle("", 19 | onSelectionImage: UIImage(named: "wave_square_selected"), 20 | offSelectionImage: UIImage(named: "wave_square")) 21 | let _ = self.addSegmentWithTitle("", 22 | onSelectionImage: UIImage(named: "wave_pulse_selected"), 23 | offSelectionImage: UIImage(named: "wave_pulse")) 24 | let _ = self.addSegmentWithTitle("", 25 | onSelectionImage: UIImage(named: "wave_saw_selected"), 26 | offSelectionImage: UIImage(named: "wave_saw")) 27 | } 28 | 29 | func addLfoWaveforms() { 30 | let _ = self.addSegmentWithTitle("", 31 | onSelectionImage: UIImage(named: "wave_sine_selected"), 32 | offSelectionImage: UIImage(named: "wave_sine")) 33 | let _ = self.addSegmentWithTitle("", 34 | onSelectionImage: UIImage(named: "wave_square_selected"), 35 | offSelectionImage: UIImage(named: "wave_square")) 36 | let _ = self.addSegmentWithTitle("", 37 | onSelectionImage: UIImage(named: "wave_upSaw_selected"), 38 | offSelectionImage: UIImage(named: "wave_upSaw")) 39 | let _ = self.addSegmentWithTitle("", 40 | onSelectionImage: UIImage(named: "wave_downSaw_selected"), 41 | offSelectionImage: UIImage(named: "wave_downSaw")) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /AnalogSynthX/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AudioComponents 6 | 7 | 8 | manufacturer 9 | AuKt 10 | name 11 | Analog Synth X 12 | subtype 13 | ansx 14 | type 15 | auri 16 | version 17 | 2 18 | 19 | 20 | CFBundleDevelopmentRegion 21 | en 22 | CFBundleDisplayName 23 | Analog Synth X 24 | CFBundleExecutable 25 | $(EXECUTABLE_NAME) 26 | CFBundleIdentifier 27 | $(PRODUCT_BUNDLE_IDENTIFIER) 28 | CFBundleInfoDictionaryVersion 29 | 6.0 30 | CFBundleName 31 | $(PRODUCT_NAME) 32 | CFBundlePackageType 33 | APPL 34 | CFBundleShortVersionString 35 | 1.3 36 | CFBundleSignature 37 | ???? 38 | CFBundleURLTypes 39 | 40 | 41 | CFBundleTypeRole 42 | Editor 43 | CFBundleURLName 44 | io.audiokit.analogsynthx 45 | CFBundleURLSchemes 46 | 47 | analogsynthx-1.0.audiobus 48 | 49 | 50 | 51 | CFBundleVersion 52 | 12 53 | LSRequiresIPhoneOS 54 | 55 | NSMicrophoneUsageDescription 56 | Only need to access microphone as part of Audiobus signal chain 57 | UIBackgroundModes 58 | 59 | audio 60 | 61 | UIMainStoryboardFile 62 | Main 63 | UIRequiredDeviceCapabilities 64 | 65 | armv7 66 | 67 | UIRequiresFullScreen 68 | 69 | UIStatusBarHidden~ipad 70 | 71 | UISupportedInterfaceOrientations 72 | 73 | UIInterfaceOrientationPortrait 74 | UIInterfaceOrientationLandscapeLeft 75 | UIInterfaceOrientationLandscapeRight 76 | 77 | UISupportedInterfaceOrientations~ipad 78 | 79 | UIInterfaceOrientationLandscapeRight 80 | UIInterfaceOrientationLandscapeLeft 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /AnalogSynthX/AudioSystem/Conductor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Conductor.swift 3 | // AnalogSynthX 4 | // 5 | // Created by Aurelius Prochazka, revision history on Github. 6 | // Copyright © 2018 AudioKit. All rights reserved. 7 | // 8 | 9 | import AudioKit 10 | 11 | class Conductor: AKMIDIListener { 12 | /// Globally accessible singleton 13 | static let sharedInstance = Conductor() 14 | 15 | var core = GeneratorBank() 16 | var bitCrusher: AKBitCrusher 17 | var fatten: Fatten 18 | var filterSection: FilterSection 19 | var multiDelay: MultiDelay 20 | var multiDelayMixer: AKDryWetMixer 21 | 22 | var masterVolume = AKMixer() 23 | var reverb: AKCostelloReverb 24 | var reverbMixer: AKDryWetMixer 25 | 26 | var midiBendRange: Double = 2.0 27 | 28 | init() { 29 | AKSettings.audioInputEnabled = true 30 | bitCrusher = AKBitCrusher(core) 31 | bitCrusher.stop() 32 | 33 | filterSection = FilterSection(bitCrusher) 34 | filterSection.output.stop() 35 | 36 | fatten = Fatten(filterSection) 37 | multiDelay = MultiDelay(fatten) 38 | multiDelayMixer = AKDryWetMixer(fatten, multiDelay, balance: 0.0) 39 | 40 | masterVolume = AKMixer(multiDelayMixer) 41 | reverb = AKCostelloReverb(masterVolume) 42 | reverb.stop() 43 | 44 | reverbMixer = AKDryWetMixer(masterVolume, reverb, balance: 0.0) 45 | 46 | // uncomment this to allow background operation 47 | // AKSettings.playbackWhileMuted = true 48 | 49 | AudioKit.output = reverbMixer 50 | do { 51 | try AudioKit.start() 52 | } catch { 53 | AKLog("AudioKit did not start!") 54 | } 55 | Audiobus.start() 56 | 57 | let midi = AudioKit.midi 58 | midi.createVirtualPorts() 59 | midi.openInput("Session 1") 60 | midi.addListener(self) 61 | } 62 | 63 | // MARK: - AKMIDIListener protocol functions 64 | 65 | func receivedMIDINoteOn(noteNumber: MIDINoteNumber, 66 | velocity: MIDIVelocity, 67 | channel: MIDIChannel) { 68 | core.play(noteNumber: noteNumber, velocity: velocity) 69 | } 70 | func receivedMIDINoteOff(noteNumber: MIDINoteNumber, 71 | velocity: MIDIVelocity, 72 | channel: MIDIChannel) { 73 | core.stop(noteNumber: noteNumber) 74 | } 75 | func receivedMIDIPitchWheel(_ pitchWheelValue: MIDIWord, channel: MIDIChannel) { 76 | let bendSemi = (Double(pitchWheelValue - 8_192) / 8_192.0) * midiBendRange 77 | core.globalbend = bendSemi 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /AnalogSynthX/CustomControls/Knob.swift: -------------------------------------------------------------------------------- 1 | // 2 | // KnobView.swift 3 | // Analog Synth X 4 | // 5 | // Created by Matthew Fecher, revision history on Githbub. 6 | // Copyright © 2018 AudioKit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | protocol KnobDelegate { 12 | func updateKnobValue(_ value: Double, tag: Int) 13 | } 14 | 15 | @IBDesignable 16 | class Knob: UIView { 17 | 18 | var delegate: KnobDelegate? 19 | 20 | var minimum = 0.0 { 21 | didSet { 22 | self.knobValue = CGFloat((value - minimum) / (maximum - minimum)) 23 | } 24 | } 25 | var maximum = 1.0 { 26 | didSet { 27 | self.knobValue = CGFloat((value - minimum) / (maximum - minimum)) 28 | } 29 | } 30 | 31 | var value: Double = 0.5 { 32 | didSet { 33 | if value > maximum { 34 | value = maximum 35 | } 36 | if value < minimum { 37 | value = minimum 38 | } 39 | self.knobValue = CGFloat((value - minimum) / (maximum - minimum)) 40 | } 41 | } 42 | 43 | // Knob properties 44 | var knobValue: CGFloat = 0.5 { 45 | didSet { 46 | setNeedsDisplay() 47 | 48 | } 49 | } 50 | var knobFill: CGFloat = 0 51 | var knobSensitivity = 0.005 52 | var lastX: CGFloat = 0 53 | var lastY: CGFloat = 0 54 | 55 | // Init / Lifecycle 56 | override init(frame: CGRect) { 57 | super.init(frame: frame) 58 | contentMode = .redraw 59 | } 60 | 61 | required init?(coder: NSCoder) { 62 | super.init(coder: coder) 63 | self.isUserInteractionEnabled = true 64 | contentMode = .redraw 65 | } 66 | 67 | override func prepareForInterfaceBuilder() { 68 | super.prepareForInterfaceBuilder() 69 | 70 | contentMode = .scaleAspectFit 71 | clipsToBounds = true 72 | } 73 | 74 | class override var requiresConstraintBasedLayout: Bool { 75 | return true 76 | } 77 | 78 | override func draw(_ rect: CGRect) { 79 | KnobStyleKit.drawKnobOne(frame: CGRect(x:0, y:0, width: self.bounds.width, height: self.bounds.height), knobValue: knobValue) 80 | } 81 | 82 | // Helper 83 | func setPercentagesWithTouchPoint(_ touchPoint: CGPoint) { 84 | // Knobs assume up or right is increasing, and down or left is decreasing 85 | 86 | let horizontalChange = Double(touchPoint.x - lastX) * knobSensitivity 87 | value += horizontalChange * (maximum - minimum) 88 | 89 | let verticalChange = Double(touchPoint.y - lastY) * knobSensitivity 90 | value -= verticalChange * (maximum - minimum) 91 | 92 | lastX = touchPoint.x 93 | lastY = touchPoint.y 94 | 95 | delegate?.updateKnobValue(value, tag: self.tag) 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /AnalogSynthX/AudioSystem/MultiDelay.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MultiDelay.swift 3 | // AnalogSynthX 4 | // 5 | // Created by Aurelius Prochazka, revision history on Github. 6 | // Copyright © 2018 AudioKit. All rights reserved. 7 | // 8 | 9 | import AudioKit 10 | 11 | class MultiDelay: AKNode, AKInput { 12 | 13 | let leftDelayMix = AKMixer() 14 | let rightDelayMix = AKMixer() 15 | var delayPannedLeft: AKPanner! 16 | var delayPannedRight: AKPanner! 17 | var mixer: AKMixer! 18 | 19 | var time: Double = 0.0 { 20 | didSet { 21 | leftTimes = [1, 2, 3].map { t -> Double in t * time } 22 | updateDelays(leftDelays, boosters: leftBoosters, times: leftTimes, gains: gains) 23 | 24 | rightTimes = [1.5, 2.5, 3.5].map { t -> Double in t * time } 25 | updateDelays(rightDelays, boosters: rightBoosters, times: rightTimes, gains: gains) 26 | } 27 | } 28 | 29 | var mix: Double = 0 { 30 | didSet { 31 | gains = [0.5, 0.25, 0.15].map { g -> Double in g * mix } 32 | updateDelays(leftDelays, boosters: leftBoosters, times: leftTimes, gains: gains) 33 | updateDelays(rightDelays, boosters: rightBoosters, times: rightTimes, gains: gains) 34 | } 35 | } 36 | 37 | fileprivate var leftDelays: [AKDelay] = [] 38 | fileprivate var rightDelays: [AKDelay] = [] 39 | fileprivate var leftBoosters: [AKBooster] = [] 40 | fileprivate var rightBoosters: [AKBooster] = [] 41 | fileprivate var gains = [0.5, 0.25, 0.15] 42 | fileprivate var leftTimes = [1.0, 2.0, 3.0] 43 | fileprivate var rightTimes = [1.5, 2.5, 3.5] 44 | 45 | func updateDelays(_ delays: [AKDelay], boosters: [AKBooster], times: [Double], gains: [Double]) { 46 | for i in 0..>> leftDelayMix 65 | rightBoosters[i] >>> rightDelayMix 66 | } 67 | 68 | let delayPannedLeft = AKPanner(leftDelayMix, pan: -1) 69 | let delayPannedRight = AKPanner(rightDelayMix, pan: 1) 70 | 71 | mixer = AKMixer(delayPannedLeft, delayPannedRight) 72 | 73 | super.init() 74 | self.avAudioNode = mixer.avAudioNode 75 | input.connect(to: mixer) 76 | 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /AnalogSynthX/SynthVC+UIHelpers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SynthViewController+UIHelpers.swift 3 | // AnalogSynthX 4 | // 5 | // Created by Matthew Fecher, revision history on Githbub. 6 | // Copyright © 2018 AudioKit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension SynthViewController { 12 | 13 | //***************************************************************** 14 | // MARK: - Synth UI Helpers 15 | //***************************************************************** 16 | 17 | override var prefersStatusBarHidden: Bool { 18 | return true 19 | } 20 | 21 | func openURL(_ url: String) { 22 | guard let url = URL(string: url) else { 23 | return 24 | } 25 | if #available(iOS 10.0, *) { 26 | UIApplication.shared.open(url) 27 | } else { 28 | // Fallback on earlier versions 29 | } 30 | } 31 | 32 | func cutoffFreqFromValue(_ value: Double) -> Double { 33 | // Logarithmic scale: knobvalue to frequency 34 | let scaledValue = Double.scaleRangeLog(value, rangeMin: 30, rangeMax: 7_000) 35 | return scaledValue * 4 36 | } 37 | 38 | func crusherFreqFromValue(_ value: Double) -> Double { 39 | // Logarithmic scale: reverse knobvalue to frequency 40 | let value = 1 - value 41 | let scaledValue = Double.scaleRangeLog(value, rangeMin: 50, rangeMax: 8_000) 42 | return scaledValue 43 | } 44 | 45 | //***************************************************************** 46 | // MARK: - SegmentViews 47 | //***************************************************************** 48 | 49 | func createWaveFormSegmentViews() { 50 | setupOscSegmentView(x: 8, y: 75.0, width: 195, height: 46.0, tag: ControlTag.vco1Waveform.rawValue, type: 0) 51 | setupOscSegmentView(x: 212, y: 75.0, width: 226, height: 46.0, tag: ControlTag.vco2Waveform.rawValue, type: 0) 52 | setupOscSegmentView(x: 10, y: 377, width: 255, height: 46.0, tag: ControlTag.lfoWaveform.rawValue, type: 1) 53 | } 54 | 55 | func setupOscSegmentView(x: CGFloat, 56 | y: CGFloat, 57 | width: CGFloat, 58 | height: CGFloat, 59 | tag: Int, 60 | type: Int) { 61 | let segmentFrame = CGRect(x: x, y: y, width: width, height: height) 62 | let segmentView = WaveformSegmentedView(frame: segmentFrame) 63 | segmentView.setOscColors() 64 | 65 | if type == 0 { 66 | segmentView.addOscWaveforms() 67 | } else { 68 | segmentView.addLfoWaveforms() 69 | } 70 | 71 | segmentView.delegate = self 72 | segmentView.tag = tag 73 | 74 | // Set segment with index 0 as selected by default 75 | segmentView.selectSegmentAtIndex(0) 76 | self.view.addSubview(segmentView) 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /AnalogSynthX/SynthVC+NoteNames.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NoteNames.swift 3 | // AnalogSynthX 4 | // 5 | // Created by Matthew Fecher, revision history on Githbub. 6 | // Copyright © 2018 AudioKit. All rights reserved. 7 | // 8 | 9 | import AudioKit 10 | 11 | extension SynthViewController { 12 | 13 | func noteNameFromMidiNote(_ noteNumber: MIDINoteNumber) -> String { 14 | 15 | // Handy table of Midi Note Names 16 | let noteNames: [MIDINoteNumber: String] = 17 | [ 18 | 21: "A0", 19 | 22: "A0#", 20 | 23: "B0", 21 | 24: "C1", 22 | 25: "C1#", 23 | 26: "D1", 24 | 27: "D1#", 25 | 28: "E1", 26 | 29: "F1", 27 | 30: "F1#", 28 | 31: "G1", 29 | 32: "G1#", 30 | 33: "A1", 31 | 34: "A1#", 32 | 35: "B1", 33 | 36: "C2", 34 | 37: "C2#", 35 | 38: "D2", 36 | 39: "D2#", 37 | 40: "E2", 38 | 41: "F2", 39 | 42: "F2#", 40 | 43: "G2", 41 | 44: "G2#", 42 | 45: "A2", 43 | 46: "A2#", 44 | 47: "B2", 45 | 48: "C3", 46 | 49: "C3#", 47 | 50: "D3", 48 | 51: "D3#", 49 | 52: "E3", 50 | 53: "F3", 51 | 54: "F3#", 52 | 55: "G3", 53 | 56: "G3#", 54 | 57: "A3", 55 | 58: "A3#", 56 | 59: "B3", 57 | 60: "C4", 58 | 61: "C4#", 59 | 62: "D4", 60 | 63: "D4#", 61 | 64: "E4", 62 | 65: "F4", 63 | 66: "F4#", 64 | 67: "G4", 65 | 68: "G4#", 66 | 69: "A4", 67 | 70: "A4#", 68 | 71: "B4", 69 | 72: "C5", 70 | 73: "C5#", 71 | 74: "D5", 72 | 75: "D5#", 73 | 76: "E5", 74 | 77: "F5", 75 | 78: "F5#", 76 | 79: "G5", 77 | 80: "G5#", 78 | 81: "A5", 79 | 82: "A5#", 80 | 83: "B5", 81 | 84: "C6", 82 | 85: "C6#", 83 | 86: "D6", 84 | 87: "D6#", 85 | 88: "E6", 86 | 89: "F6", 87 | 90: "F6#", 88 | 91: "G6", 89 | 92: "G6#", 90 | 93: "A6", 91 | 94: "A6#", 92 | 95: "B6", 93 | 96: "C7", 94 | 97: "C7#", 95 | 98: "D7", 96 | 99: "D7#", 97 | 100: "E7", 98 | 101: "F7", 99 | 102: "F7#", 100 | 103: "G7", 101 | 104: "G7#", 102 | 105: "A7", 103 | 106: "A7#", 104 | 107: "B7", 105 | 108: "C8" 106 | ] 107 | 108 | guard let noteName = noteNames[noteNumber] else { 109 | return String(noteNumber) 110 | } 111 | 112 | return noteName 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AudioKit Analog Synth X Example 2 | 3 | [![Build Status](https://travis-ci.org/AudioKit/AnalogSynthX.svg)](https://travis-ci.org/AudioKit/AnalogSynthX) 4 | [![License](https://img.shields.io/cocoapods/l/AudioKit.svg?style=flat)](https://github.com/AudioKit/AnalogSynthX/blob/master/LICENSE) 5 | [![Twitter Follow](https://img.shields.io/twitter/follow/AudioKitMan.svg?style=social)](http://twitter.com/AudioKitMan) 6 | 7 | This is a simple iPad synthesizer app example by **Matthew Fecher** and **Aure Prochazka** built with Swift and AudioKit. It includes examples of Audiobus, Inter-app audio, and more. Created in late 2015, this is the first open-source synthesizer ever written in Swift. This code was originally included in AudioKit, and now has been updated to its own repo. 8 | 9 | The complete source code is MIT open source. Meaning, you can use it as a learning tool, or even create your own synth app from the code. There's no charge or fee to use the code. Use it as a starting point to create the synth of your dreams. 10 | 11 | If you use this code in an app to be released to the App Store, you must change the graphics. And, please thank AudioKit. 12 | 13 | 14 | 15 | ## Compiling from source: 16 | 17 | This project makes use of CocoaPods, so make sure you have that installed and then run 18 | 19 | ``` 20 | cd Examples/iOS/AnalogSynthX; pod install; 21 | ``` 22 | 23 | ## Synth Features 24 | 25 | * 5-Voice Virtual Analog Synthesizer 26 | * Audiobus and Inter-app Audio (IAA) 27 | * Dual VCO-style Oscillators 28 | * MIDI in for notes 29 | * Dedicated Sub Oscillator 30 | * FM Oscillator w/ Mod (Nord Lead style) 31 | * 4-Pole Vintage Low-Pass Filter (Moog style) 32 | * Oscillator Morph Knob (Access Virus style) 33 | * Beautiful Sean Costello Reverb 34 | * Free-running LFO w/ 4 waveforms 35 | * Multi-tap (ping-pong) delay 36 | * ADSR Envelope 37 | * Detune Oscillators by Semitone & Hz 38 | * Hold & Mono modes for keyboard 39 | * Noise generator 40 | * 8-Bit Crusher 41 | 42 | ## Updated Synth Example 43 | 44 | For a more robust open-source iOS synth example, please see our new [AudioKit Synth One](https://github.com/AudioKit/AudioKitSynthOne) code 45 | 46 | ## Sound Tips for Analog Synth X: 47 | 48 | * You can get a pure Sine wave by (1) turning the Osc Mix to the left (2) turning off VCO1 (3) Turning the FM up! 49 | * Use the morph knob between square and pulse for basic PWM control. 50 | * Not getting enough low-end for your liking? Turn down the Rez. 51 | * Use 2 saws and detune VCO2 for a shimmery vintage Polysynth sound. Slowly open the filter to your taste. 52 | * The reverse saw LFO (the last wave setting on the LFO) can simulate a basic voltage-controlled note repeat. 53 | * Keep dry/wet knobs under 50% for a more powerful sound. 54 | * Turn the ADSR Release down to zero and turn the echo on to hear how the echo taps fire. 55 | 56 | ## Get in the Code: 57 | 58 | * The sub is set to a sine wave for a more powerful bass tone. You can change it to a square if you'd like the synth to have more of a vintage feel. You can also experiment between -12/-24 settings. 59 | * Try changing the preset knob bounds (minimum/maximum) in the SynthViewController to extremes to play a synth with wild settings! 60 | * Sub and FM are tracked to the keyboard. Try tracking them to VCO1 for a more accurate Analog synth effect. (i.e. If you detune VCO1, FM & Sub also detune). 61 | -------------------------------------------------------------------------------- /AnalogSynthX/SMSegmentView/SMAlphaImageSegment.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SMAlphaImageSegment.swift 3 | // SMSegmentViewController 4 | // 5 | // Created by mlaskowski, revision history on Githbub. 6 | // Copyright © 2016 si.ma. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | open class SMAlphaImageSegment: SMBasicSegment { 12 | 13 | // UI Elements 14 | override open var frame: CGRect { 15 | didSet { 16 | self.resetContentFrame() 17 | } 18 | } 19 | 20 | open var margin: CGFloat = 5.0 { 21 | didSet { 22 | self.resetContentFrame() 23 | } 24 | } 25 | 26 | var vertical = false 27 | 28 | open var animationDuration: TimeInterval = 0.5 29 | open var selectedAlpha: CGFloat = 1.0 30 | open var unselectedAlpha: CGFloat = 0.3 31 | open var pressedAlpha: CGFloat = 0.65 32 | 33 | internal(set) var imageView: UIImageView = UIImageView() 34 | required public init?(coder aDecoder: NSCoder) { 35 | fatalError("init(coder:) has not been implemented") 36 | } 37 | 38 | public init(margin: CGFloat, 39 | selectedAlpha: CGFloat, 40 | unselectedAlpha: CGFloat, 41 | pressedAlpha: CGFloat, 42 | image: UIImage?) { 43 | 44 | self.margin = margin 45 | self.selectedAlpha = selectedAlpha 46 | self.unselectedAlpha = unselectedAlpha 47 | self.pressedAlpha = pressedAlpha 48 | self.imageView.image = image 49 | self.imageView.alpha = unselectedAlpha 50 | 51 | super.init(frame: CGRect.zero) 52 | self.setupUIElements() 53 | } 54 | 55 | override open func orientationChangedTo(_ mode: SegmentOrganiseMode) { 56 | self.vertical = mode == .segmentOrganiseVertical 57 | //resetContentFrame(vertical) 58 | } 59 | 60 | func setupUIElements() { 61 | 62 | self.imageView.contentMode = UIViewContentMode.scaleAspectFit 63 | self.addSubview(self.imageView) 64 | } 65 | 66 | // MARK: Update Frame 67 | func resetContentFrame() { 68 | let margin = self.vertical ? (self.margin * 1.5) : self.margin 69 | let imageViewFrame = CGRect(x: margin, 70 | y: margin, 71 | width: self.frame.size.width - margin * 2, 72 | height: self.frame.size.height - margin * 2) 73 | 74 | self.imageView.frame = imageViewFrame 75 | 76 | } 77 | 78 | // MARK: Selections 79 | override func setSelected(_ selected: Bool, inView view: SMBasicSegmentView) { 80 | super.setSelected(selected, inView: view) 81 | if selected { 82 | self.startAnimationToAlpha(self.selectedAlpha) 83 | } else { 84 | self.startAnimationToAlpha(self.unselectedAlpha) 85 | } 86 | } 87 | 88 | func startAnimationToAlpha(_ alpha: CGFloat) { 89 | UIView.animate(withDuration: self.animationDuration, 90 | delay: 0, 91 | usingSpringWithDamping: 0.8, 92 | initialSpringVelocity: 0.1, 93 | options: .beginFromCurrentState, 94 | animations: { () -> Void in 95 | self.imageView.alpha = alpha 96 | }, completion: nil) 97 | } 98 | 99 | // MARK: Handle touch 100 | override open func touchesBegan(_ touches: Set, with event: UIEvent?) { 101 | super.touchesBegan(touches, with: event) 102 | 103 | if self.isSelected == false { 104 | self.startAnimationToAlpha(self.pressedAlpha) 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /AnalogSynthX.xcodeproj/xcshareddata/xcschemes/AnalogSynthX.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 69 | 70 | 71 | 72 | 73 | 74 | 80 | 82 | 88 | 89 | 90 | 91 | 93 | 94 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /AnalogSynthX/SMSegmentView/SMSegmentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SMSegmentView.swift 3 | // 4 | // Created by Si MA, revision history on Githbub. 5 | // Copyright (c) 2016 Si Ma. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | // swiftlint:disable force_cast 10 | 11 | /* 12 | Keys for segment properties 13 | */ 14 | 15 | // This is mainly for the top/bottom margin of the imageView 16 | let keyContentVerticalMargin = "VerticalMargin" 17 | 18 | // The colour when the segment is under selected/unselected 19 | let keySegmentOnSelectionColour = "OnSelectionBackgroundColour" 20 | let keySegmentOffSelectionColour = "OffSelectionBackgroundColour" 21 | 22 | // The colour of the text in the segment for the segment is under selected/unselected 23 | let keySegmentOnSelectionTextColour = "OnSelectionTextColour" 24 | let keySegmentOffSelectionTextColour = "OffSelectionTextColour" 25 | 26 | // The font of the text in the segment 27 | let keySegmentTitleFont = "TitleFont" 28 | 29 | @IBDesignable 30 | open class SMSegmentView: SMBasicSegmentView { 31 | 32 | @IBInspectable open var segmentVerticalMargin: CGFloat = 5.0 { 33 | didSet { 34 | for segment in self.segments as! [SMSegment] { 35 | segment.verticalMargin = self.segmentVerticalMargin 36 | } 37 | } 38 | } 39 | 40 | // Segment Colour 41 | @IBInspectable open var segmentOnSelectionColour: UIColor = UIColor.darkGray { 42 | didSet { 43 | for segment in self.segments as! [SMSegment] { 44 | segment.onSelectionColour = self.segmentOnSelectionColour 45 | } 46 | } 47 | } 48 | @IBInspectable open var segmentOffSelectionColour: UIColor = UIColor.white { 49 | didSet { 50 | for segment in self.segments as! [SMSegment] { 51 | segment.offSelectionColour = self.segmentOffSelectionColour 52 | } 53 | } 54 | } 55 | 56 | // Segment Title Text Colour & Font 57 | @IBInspectable open var segmentOnSelectionTextColour: UIColor = UIColor.white { 58 | didSet { 59 | for segment in self.segments as! [SMSegment] { 60 | segment.onSelectionTextColour = self.segmentOnSelectionTextColour 61 | } 62 | } 63 | } 64 | @IBInspectable open var segmentOffSelectionTextColour: UIColor = UIColor.darkGray { 65 | didSet { 66 | for segment in self.segments as! [SMSegment] { 67 | segment.offSelectionTextColour = self.segmentOffSelectionTextColour 68 | } 69 | } 70 | } 71 | open var segmentTitleFont: UIFont = UIFont.systemFont(ofSize: 17.0) { 72 | didSet { 73 | for segment in self.segments as! [SMSegment] { 74 | segment.titleFont = self.segmentTitleFont 75 | } 76 | } 77 | } 78 | 79 | required public init?(coder aDecoder: NSCoder) { 80 | fatalError("init(coder:) has not been implemented") 81 | } 82 | 83 | override public init(frame: CGRect) { 84 | super.init(frame: frame) 85 | self.backgroundColor = UIColor.clear 86 | self.layer.masksToBounds = true 87 | } 88 | 89 | public init(frame: CGRect, 90 | separatorColour: UIColor, 91 | separatorWidth: CGFloat, 92 | segmentProperties: [String: AnyObject]?) { 93 | 94 | super.init(frame: frame) 95 | 96 | self.separatorColour = separatorColour 97 | self.separatorWidth = separatorWidth 98 | 99 | if let margin = segmentProperties?[keyContentVerticalMargin] as? Float { 100 | self.segmentVerticalMargin = CGFloat(margin) 101 | } 102 | 103 | if let onSelectionColour = segmentProperties?[keySegmentOnSelectionColour] as? UIColor { 104 | self.segmentOnSelectionColour = onSelectionColour 105 | } else { 106 | self.segmentOnSelectionColour = UIColor.darkGray 107 | } 108 | 109 | if let offSelectionColour = segmentProperties?[keySegmentOffSelectionColour] as? UIColor { 110 | self.segmentOffSelectionColour = offSelectionColour 111 | } else { 112 | self.segmentOffSelectionColour = UIColor.white 113 | } 114 | 115 | if let onSelectionTextColour = segmentProperties?[keySegmentOnSelectionTextColour] as? UIColor { 116 | self.segmentOnSelectionTextColour = onSelectionTextColour 117 | } else { 118 | self.segmentOnSelectionTextColour = UIColor.white 119 | } 120 | 121 | if let offSelectionTextColour = segmentProperties?[keySegmentOffSelectionTextColour] as? UIColor { 122 | self.segmentOffSelectionTextColour = offSelectionTextColour 123 | } else { 124 | self.segmentOffSelectionTextColour = UIColor.darkGray 125 | } 126 | 127 | if let titleFont = segmentProperties?[keySegmentTitleFont] as? UIFont { 128 | self.segmentTitleFont = titleFont 129 | } else { 130 | self.segmentTitleFont = UIFont.systemFont(ofSize: 17.0) 131 | } 132 | 133 | self.backgroundColor = UIColor.clear 134 | self.layer.masksToBounds = true 135 | } 136 | 137 | open func addSegmentWithTitle(_ title: String?, 138 | onSelectionImage: UIImage?, 139 | offSelectionImage: UIImage?) -> SMSegment { 140 | 141 | let segment = SMSegment(verticalMargin: self.segmentVerticalMargin, 142 | onSelectionColour: self.segmentOnSelectionColour, 143 | offSelectionColour: self.segmentOffSelectionColour, 144 | onSelectionTextColour: self.segmentOnSelectionTextColour, 145 | offSelectionTextColour: self.segmentOffSelectionTextColour, 146 | titleFont: self.segmentTitleFont) 147 | 148 | segment.title = title 149 | segment.onSelectionImage = onSelectionImage 150 | segment.offSelectionImage = offSelectionImage 151 | 152 | super.addSegment(segment) 153 | 154 | return segment 155 | } 156 | 157 | } 158 | -------------------------------------------------------------------------------- /AnalogSynthX/CustomControls/VerticalSlider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // VerticalSlider.swift 3 | // Analog Synth X 4 | // 5 | // Created by Matthew Fecher, revision history on Githbub. 6 | // Copyright (c) 2016 AudioKit. All rights reserved. 7 | 8 | // Slider code adapted from: 9 | // http://www.totem.training/swift-ios-tips-tricks-tutorials-blog/paint-code-and-live-views 10 | 11 | import UIKit 12 | 13 | protocol VerticalSliderDelegate: class { 14 | func sliderValueDidChange(_ value: Double, tag: Int) 15 | } 16 | 17 | let sliderTopImage = "slider_top.png" 18 | let sliderTrackImage = "slider_track.png" 19 | 20 | @IBDesignable 21 | class VerticalSlider: UIControl { 22 | 23 | var minValue: CGFloat = 0.0 24 | var maxValue: CGFloat = 1.0 25 | var currentValue: CGFloat = 0.45 { 26 | didSet { 27 | if currentValue < 0 { 28 | currentValue = 0 29 | } 30 | if currentValue > maxValue { 31 | currentValue = maxValue 32 | } 33 | self.sliderValue = CGFloat((currentValue - minValue) / (maxValue - minValue)) 34 | setupView() 35 | } 36 | } 37 | 38 | let knobSize = CGSize(width: 43, height: 31) 39 | let barMargin: CGFloat = 20.0 40 | var knobRect: CGRect! 41 | var barLength: CGFloat = 164.0 42 | var isSliding = false 43 | var sliderValue: CGFloat = 0.5 44 | weak var delegate: VerticalSliderDelegate? 45 | 46 | //// Image Declarations 47 | var sliderTop = UIImage(named: sliderTopImage) 48 | var sliderTrack = UIImage(named: sliderTrackImage) 49 | 50 | override init(frame: CGRect) { 51 | super.init(frame: frame) 52 | contentMode = .redraw 53 | } 54 | 55 | required init?(coder: NSCoder) { 56 | super.init(coder: coder) 57 | self.isUserInteractionEnabled = true 58 | contentMode = .redraw 59 | } 60 | 61 | class override var requiresConstraintBasedLayout: Bool { 62 | return true 63 | } 64 | } 65 | 66 | // MARK: - Lifecycle 67 | extension VerticalSlider { 68 | override func awakeFromNib() { 69 | super.awakeFromNib() 70 | setupView() 71 | } 72 | 73 | func setupView() { 74 | 75 | knobRect = CGRect(x: 0, 76 | y: convertValueToY(currentValue) - (knobSize.height / 2), 77 | width: knobSize.width, 78 | height: knobSize.height) 79 | barLength = bounds.height - (barMargin * 2) 80 | 81 | let bundle = Bundle(for: type(of: self)) 82 | sliderTop = UIImage(named: sliderTopImage, in: bundle, compatibleWith: self.traitCollection) 83 | sliderTrack = UIImage(named: sliderTrackImage, in: bundle, compatibleWith: self.traitCollection) 84 | } 85 | 86 | override func draw(_ rect: CGRect) { 87 | drawVerticalSlider(controlFrame: CGRect(x: 0, 88 | y: 0, 89 | width: bounds.width, 90 | height: bounds.height), 91 | knobRect: knobRect) 92 | } 93 | 94 | override func prepareForInterfaceBuilder() { 95 | super.prepareForInterfaceBuilder() 96 | setupView() 97 | } 98 | } 99 | 100 | // MARK: - Helpers 101 | extension VerticalSlider { 102 | func convertYToValue(_ y: CGFloat) -> CGFloat { 103 | let offsetY = bounds.height - barMargin - y 104 | let value = (offsetY * maxValue) / barLength 105 | return value 106 | } 107 | func convertValueToY(_ value: CGFloat) -> CGFloat { 108 | let rawY = (value * barLength) / maxValue 109 | let offsetY = bounds.height - barMargin - rawY 110 | return offsetY 111 | } 112 | } 113 | 114 | // MARK: - Control Touch Handling 115 | extension VerticalSlider { 116 | override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool { 117 | if knobRect.contains(touch.location(in: self)) { 118 | isSliding = true 119 | } 120 | return true 121 | } 122 | 123 | override func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool { 124 | let rawY = touch.location(in: self).y 125 | 126 | if isSliding { 127 | let value = convertYToValue(rawY) 128 | 129 | if value != minValue || value != maxValue { 130 | currentValue = value 131 | delegate?.sliderValueDidChange(Double(currentValue), tag: self.tag) 132 | setNeedsDisplay() 133 | } 134 | } 135 | return true 136 | } 137 | 138 | override func endTracking(_ touch: UITouch?, with event: UIEvent?) { 139 | isSliding = false 140 | } 141 | 142 | func drawVerticalSlider(controlFrame: CGRect = CGRect(x: 0, y: 0, width: 40, height: 216), 143 | knobRect: CGRect = CGRect(x: 0, y: 89, width: 36, height: 32)) { 144 | //// General Declarations 145 | let context = UIGraphicsGetCurrentContext() 146 | 147 | //// Background Drawing 148 | let backgroundRect = CGRect(x: controlFrame.minX + 2, y: controlFrame.minY + 10, width: 38, height: 144) 149 | let backgroundPath = UIBezierPath(rect: backgroundRect) 150 | context?.saveGState() 151 | backgroundPath.addClip() 152 | sliderTrack?.draw(in: CGRect(x: floor(backgroundRect.minX + 0.5), 153 | y: floor(backgroundRect.minY + 0.5), 154 | width: sliderTrack?.size.width ?? 0, 155 | height: sliderTrack?.size.height ?? 0)) 156 | context?.restoreGState() 157 | 158 | //// Slider Top Drawing 159 | let sliderTopRect = CGRect(x: knobRect.origin.x, 160 | y: knobRect.origin.y, 161 | width: knobRect.size.width, 162 | height: knobRect.size.height) 163 | let sliderTopPath = UIBezierPath(rect: sliderTopRect) 164 | context?.saveGState() 165 | sliderTopPath.addClip() 166 | sliderTop?.draw(in: CGRect(x: floor(sliderTopRect.minX + 0.5), 167 | y: floor(sliderTopRect.minY + 0.5), 168 | width: sliderTop?.size.width ?? 0, 169 | height: sliderTop?.size.height ?? 0)) 170 | context?.restoreGState() 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /AnalogSynthX/SMSegmentView/SMBasicSegmentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SMBasicSegmentView.swift 3 | // SMSegmentViewController 4 | // 5 | // Created by mlaskowski, revision history on Githbub. 6 | // Copyright © 2016 si.ma. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public enum SegmentOrganiseMode: Int { 13 | case segmentOrganiseHorizontal = 0 14 | case segmentOrganiseVertical 15 | } 16 | 17 | public protocol SMSegmentViewDelegate: class { 18 | func segmentView(_ segmentView: SMBasicSegmentView, didSelectSegmentAtIndex index: Int) 19 | } 20 | 21 | open class SMBasicSegmentView: UIView { 22 | open var segments: [SMBasicSegment] = [] { 23 | didSet { 24 | var i = 0 25 | for segment in segments { 26 | segment.index = i 27 | i += 1 28 | segment.segmentView = self 29 | self.addSubview(segment) 30 | } 31 | self.updateFrameForSegments() 32 | 33 | } 34 | } 35 | open weak var delegate: SMSegmentViewDelegate? 36 | 37 | open fileprivate(set) var indexOfSelectedSegment: Int = NSNotFound 38 | var numberOfSegments: Int { 39 | return segments.count 40 | } 41 | 42 | @IBInspectable open var vertical: Bool = false { 43 | didSet { 44 | let mode = vertical ? 45 | SegmentOrganiseMode.segmentOrganiseVertical : 46 | SegmentOrganiseMode.segmentOrganiseHorizontal 47 | self.orientationChangedTo(mode) 48 | } 49 | } 50 | 51 | // Segment Separator 52 | @IBInspectable open var separatorColour: UIColor = UIColor.lightGray { 53 | didSet { 54 | self.setNeedsDisplay() 55 | } 56 | } 57 | @IBInspectable open var separatorWidth: CGFloat = 1.0 { 58 | didSet { 59 | self.updateFrameForSegments() 60 | } 61 | } 62 | 63 | open override func layoutSubviews() { 64 | super.layoutSubviews() 65 | self.updateFrameForSegments() 66 | } 67 | 68 | open func orientationChangedTo(_ mode: SegmentOrganiseMode) { 69 | for segment in self.segments { 70 | segment.orientationChangedTo(mode) 71 | } 72 | setNeedsDisplay() 73 | } 74 | 75 | open func updateFrameForSegments() { 76 | if self.segments.isEmpty { 77 | return 78 | } 79 | 80 | let count = self.segments.count 81 | if count > 1 { 82 | if self.vertical == false { 83 | let segmentWidth = (self.frame.size.width - self.separatorWidth * CGFloat(count - 1)) / CGFloat(count) 84 | var originX: CGFloat = 0.0 85 | for segment in self.segments { 86 | segment.frame = CGRect(x: originX, y: 0.0, width: segmentWidth, height: self.frame.size.height) 87 | originX += segmentWidth + self.separatorWidth 88 | } 89 | } else { 90 | let segmentHeight = (self.frame.size.height - self.separatorWidth * CGFloat(count - 1)) / CGFloat(count) 91 | var originY: CGFloat = 0.0 92 | for segment in self.segments { 93 | segment.frame = CGRect(x: 0.0, y: originY, width: self.frame.size.width, height: segmentHeight) 94 | originY += segmentHeight + self.separatorWidth 95 | } 96 | } 97 | } else { 98 | self.segments[0].frame = CGRect(x: 0.0, 99 | y: 0.0, 100 | width: self.frame.size.width, 101 | height: self.frame.size.height) 102 | } 103 | 104 | self.setNeedsDisplay() 105 | } 106 | 107 | open func drawSeparatorWithContext(_ context: CGContext) { 108 | context.saveGState() 109 | 110 | if self.segments.count > 1 { 111 | let path = CGMutablePath() 112 | 113 | if self.vertical == false { 114 | var originX: CGFloat = self.segments[0].frame.size.width + self.separatorWidth / 2.0 115 | for index in 1..= 0 && index < self.segments.count, "Index at \(index) is out of bounds") 150 | 151 | if self.indexOfSelectedSegment != NSNotFound { 152 | let previousSelectedSegment = self.segments[self.indexOfSelectedSegment] 153 | previousSelectedSegment.setSelected(false, inView: self) 154 | } 155 | self.indexOfSelectedSegment = index 156 | let segment = self.segments[index] 157 | segment.setSelected(true, inView: self) 158 | self.delegate?.segmentView(self, didSelectSegmentAtIndex: index) 159 | } 160 | 161 | open func deselectSegment() { 162 | if self.indexOfSelectedSegment != NSNotFound { 163 | let segment = self.segments[self.indexOfSelectedSegment] 164 | segment.setSelected(false, inView: self) 165 | self.indexOfSelectedSegment = NSNotFound 166 | } 167 | } 168 | 169 | open func addSegment(_ segment: SMBasicSegment) { 170 | segment.index = self.segments.count 171 | self.segments.append(segment) 172 | 173 | segment.segmentView = self 174 | self.updateFrameForSegments() 175 | self.addSubview(segment) 176 | 177 | } 178 | 179 | } 180 | -------------------------------------------------------------------------------- /AnalogSynthX/Audiobus.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Audiobus.swift 3 | // AudioKit 4 | // 5 | // Created by Daniel Clelland, revision history on Githbub. 6 | // Updated for AudioKit by Aurelius Prochazka. 7 | // 8 | // Copyright © 2018 AudioKit. All rights reserved. 9 | // 10 | 11 | import Foundation 12 | import AudioKit 13 | import CoreAudio 14 | 15 | class Audiobus { 16 | 17 | // MARK: Client 18 | 19 | static var client: Audiobus? 20 | 21 | // MARK: Actions 22 | 23 | static func start() { 24 | guard client == nil else { 25 | return 26 | } 27 | 28 | if let apiKey = apiKey { 29 | client = Audiobus(apiKey: apiKey) 30 | } 31 | } 32 | 33 | private static var apiKey: String? { 34 | guard let path = Bundle.main.path(forResource: "Audiobus", ofType: "txt") else { 35 | return nil 36 | } 37 | do { 38 | return try String(contentsOfFile: path).replacingOccurrences(of: "\n", with: "") 39 | } catch { 40 | return nil 41 | } 42 | } 43 | 44 | // MARK: Initialization 45 | 46 | var controller: ABAudiobusController 47 | 48 | var audioUnit: AudioUnit { 49 | return AudioKit.engine.outputNode.audioUnit! 50 | } 51 | 52 | init(apiKey: String) { 53 | self.controller = ABAudiobusController(apiKey: apiKey) 54 | 55 | var myDict: NSDictionary? 56 | if let path = Bundle.main.path(forResource:"Info", ofType: "plist") { 57 | myDict = NSDictionary(contentsOfFile: path) 58 | } 59 | if let dict = myDict { 60 | for component in dict["AudioComponents"] as! [[String: AnyObject]] { 61 | let type = fourCC(component["type"] as! String) 62 | let subtype = fourCC(component["subtype"] as! String) 63 | let name = component["name"] as! String 64 | let manufacturer = fourCC(component["manufacturer"] as! String) 65 | 66 | if type == kAudioUnitType_RemoteInstrument || 67 | type == kAudioUnitType_RemoteGenerator { 68 | self.controller.addAudioSenderPort( 69 | ABAudioSenderPort( 70 | name: name, 71 | title: name, 72 | audioComponentDescription: AudioComponentDescription( 73 | componentType: type, 74 | componentSubType: subtype, 75 | componentManufacturer: manufacturer, 76 | componentFlags: 0, 77 | componentFlagsMask: 0 78 | ), 79 | audioUnit: audioUnit 80 | ) 81 | ) 82 | } 83 | if type == kAudioUnitType_RemoteEffect { 84 | self.controller.addAudioFilterPort( 85 | ABAudioFilterPort( 86 | name: name, 87 | title: name, 88 | audioComponentDescription: AudioComponentDescription( 89 | componentType: type, 90 | componentSubType: subtype, 91 | componentManufacturer: manufacturer, 92 | componentFlags: 0, 93 | componentFlagsMask: 0 94 | ), 95 | audioUnit: audioUnit 96 | ) 97 | ) 98 | } 99 | } 100 | } 101 | 102 | startObservingInterAppAudioConnections() 103 | startObservingAudiobusConnections() 104 | 105 | controller.enableReceivingCoreMIDIBlock = { _ in return } 106 | } 107 | 108 | deinit { 109 | stopObservingInterAppAudioConnections() 110 | stopObservingAudiobusConnections() 111 | } 112 | 113 | // MARK: Properties 114 | 115 | var isConnected: Bool { 116 | return controller.isConnectedToAudiobus || audioUnit.isConnectedToInterAppAudio 117 | } 118 | 119 | var isConnectedToInput: Bool { 120 | return controller.isConnectedToAudiobus(portOfType: ABPortTypeAudioSender) || 121 | audioUnit.isConnectedToInterAppAudio(nodeOfType: kAudioUnitType_RemoteEffect) 122 | } 123 | 124 | // MARK: Connections 125 | 126 | private var audioUnitPropertyListener: AudioUnitPropertyListener! 127 | 128 | private func startObservingInterAppAudioConnections() { 129 | audioUnitPropertyListener = AudioUnitPropertyListener { (_, _) in 130 | self.updateConnections() 131 | } 132 | 133 | try! audioUnit.add(listener: audioUnitPropertyListener, toProperty: kAudioUnitProperty_IsInterAppConnected) 134 | } 135 | 136 | private func stopObservingInterAppAudioConnections() { 137 | audioUnit.remove(listener: self.audioUnitPropertyListener, fromProperty: kAudioUnitProperty_IsInterAppConnected) 138 | } 139 | 140 | private func startObservingAudiobusConnections() { 141 | let _ = NotificationCenter.default.addObserver(forName: NSNotification.Name.ABConnectionsChanged, 142 | object: nil, 143 | queue: nil, 144 | using: { _ in self.updateConnections() }) 145 | } 146 | 147 | private func stopObservingAudiobusConnections() { 148 | NotificationCenter.default.removeObserver(self, name: NSNotification.Name.ABConnectionsChanged, object: nil) 149 | } 150 | 151 | private func updateConnections() { 152 | if isConnected { 153 | NotificationCenter.default.post(name: NSNotification.Name(rawValue: "IAAConnected"), object: nil) 154 | } else { 155 | NotificationCenter.default.post(name: NSNotification.Name(rawValue: "IAADisconnected"), object: nil) 156 | } 157 | } 158 | 159 | } 160 | 161 | private extension ABAudiobusController { 162 | 163 | var isConnectedToAudiobus: Bool { 164 | return connected && memberOfActiveAudiobusSession 165 | } 166 | 167 | func isConnectedToAudiobus(portOfType type: ABPortType) -> Bool { 168 | guard connectedPorts != nil else { 169 | return false 170 | } 171 | 172 | return connectedPorts.compactMap { $0 as? ABPort }.filter { $0.type == type }.isEmpty == false 173 | } 174 | 175 | } 176 | 177 | private extension AudioUnit { 178 | 179 | var isConnectedToInterAppAudio: Bool { 180 | let value: UInt32 = try! getValue(forProperty: kAudioUnitProperty_IsInterAppConnected) 181 | return value != 0 182 | } 183 | 184 | func isConnectedToInterAppAudio(nodeOfType type: OSType) -> Bool { 185 | let value: AudioComponentDescription = try! getValue(forProperty: kAudioOutputUnitProperty_NodeComponentDescription) 186 | return value.componentType == type 187 | } 188 | 189 | } 190 | -------------------------------------------------------------------------------- /AnalogSynthX/AudioSystem/GeneratorBank.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GeneratorBank.swift 3 | // AnalogSynthX 4 | // 5 | // Created by Aurelius Prochazka, revision history on Githbub. 6 | // Copyright © 2018 AudioKit. All rights reserved. 7 | // 8 | 9 | import AudioKit 10 | 11 | class GeneratorBank: AKPolyphonicNode { 12 | 13 | func updateWaveform1() { 14 | vco1.index = (0...3).clamp(waveform1 + morph) 15 | } 16 | 17 | func updateWaveform2() { 18 | vco2.index = (0...3).clamp(waveform2 + morph) 19 | } 20 | 21 | var waveform1 = 0.0 { didSet { updateWaveform1() } } 22 | var waveform2 = 0.0 { didSet { updateWaveform2() } } 23 | 24 | var globalbend: Double = 1.0 { 25 | didSet { 26 | vco1.pitchBend = globalbend 27 | vco2.pitchBend = globalbend 28 | subOsc.pitchBend = globalbend 29 | fmOsc.pitchBend = globalbend 30 | } 31 | } 32 | 33 | var offset1 = 0 { 34 | willSet { 35 | for noteNumber in onNotes { 36 | vco1.stop(noteNumber: MIDINoteNumber(Int(noteNumber) + offset1)) 37 | vco1.play(noteNumber: MIDINoteNumber(Int(noteNumber) + newValue), velocity: 127) 38 | } 39 | } 40 | } 41 | 42 | var offset2 = 0 { 43 | willSet { 44 | for noteNumber in onNotes { 45 | vco2.stop(noteNumber: MIDINoteNumber(Int(noteNumber) + offset2)) 46 | vco2.play(noteNumber: MIDINoteNumber(Int(noteNumber) + newValue), velocity: 127) 47 | } 48 | } 49 | } 50 | 51 | var morph: Double = 0.0 { 52 | didSet { 53 | updateWaveform1() 54 | updateWaveform2() 55 | } 56 | } 57 | 58 | /// Attack time 59 | var attackDuration: Double = 0.1 { 60 | didSet { 61 | if attackDuration < 0.02 { attackDuration = 0.02 } 62 | vco1.attackDuration = attackDuration 63 | vco2.attackDuration = attackDuration 64 | subOsc.attackDuration = attackDuration 65 | fmOsc.attackDuration = attackDuration 66 | noiseADSR.attackDuration = attackDuration 67 | 68 | } 69 | } 70 | 71 | /// Decay time 72 | var decayDuration: Double = 0.1 { 73 | didSet { 74 | if decayDuration < 0.02 { decayDuration = 0.02 } 75 | vco1.decayDuration = decayDuration 76 | vco2.decayDuration = decayDuration 77 | subOsc.decayDuration = decayDuration 78 | fmOsc.decayDuration = decayDuration 79 | noiseADSR.decayDuration = decayDuration 80 | } 81 | } 82 | 83 | /// Sustain Level 84 | var sustainLevel: Double = 0.66 { 85 | didSet { 86 | vco1.sustainLevel = sustainLevel 87 | vco2.sustainLevel = sustainLevel 88 | subOsc.sustainLevel = sustainLevel 89 | fmOsc.sustainLevel = sustainLevel 90 | noiseADSR.sustainLevel = sustainLevel 91 | } 92 | } 93 | 94 | /// Release time 95 | var releaseDuration: Double = 0.5 { 96 | didSet { 97 | if releaseDuration < 0.02 { releaseDuration = 0.02 } 98 | vco1.releaseDuration = releaseDuration 99 | vco2.releaseDuration = releaseDuration 100 | subOsc.releaseDuration = releaseDuration 101 | fmOsc.releaseDuration = releaseDuration 102 | noiseADSR.releaseDuration = releaseDuration 103 | } 104 | } 105 | 106 | var vco1On = true { 107 | didSet { 108 | vco1Mixer.volume = vco1On ? 1.0 : 0.0 109 | } 110 | } 111 | 112 | var vco2On = true { 113 | didSet { 114 | vco2Mixer.volume = vco2On ? 1.0 : 0.0 115 | } 116 | } 117 | 118 | var vco1: AKMorphingOscillatorBank 119 | var vco2: AKMorphingOscillatorBank 120 | var subOsc = AKOscillatorBank() 121 | var fmOsc = AKFMOscillatorBank() 122 | var noise = AKWhiteNoise() 123 | var noiseADSR: AKAmplitudeEnvelope 124 | 125 | // We'll be using these simply to control volume independent of velocity 126 | var vco1Mixer: AKMixer 127 | var vco2Mixer: AKMixer 128 | var subOscMixer: AKMixer 129 | var fmOscMixer: AKMixer 130 | var noiseMixer: AKMixer 131 | 132 | var vcoBalancer: AKDryWetMixer 133 | var sourceMixer: AKMixer 134 | 135 | var onNotes = Set() 136 | 137 | override init() { 138 | let triangle = AKTable(.triangle) 139 | let square = AKTable(.square) 140 | let sawtooth = AKTable(.sawtooth) 141 | 142 | let squareWithHighPWM = AKTable() 143 | let count = squareWithHighPWM.count 144 | for i in squareWithHighPWM.indices { 145 | if i < count / 8 { 146 | squareWithHighPWM[i] = -1.0 147 | } else { 148 | squareWithHighPWM[i] = 1.0 149 | } 150 | } 151 | vco1 = AKMorphingOscillatorBank(waveformArray: [triangle, square, squareWithHighPWM, sawtooth]) 152 | vco2 = AKMorphingOscillatorBank(waveformArray: [triangle, square, squareWithHighPWM, sawtooth]) 153 | 154 | noiseADSR = AKAmplitudeEnvelope(noise) 155 | 156 | vco1Mixer = AKMixer(vco1) 157 | vco2Mixer = AKMixer(vco2) 158 | subOscMixer = AKMixer(subOsc) 159 | fmOscMixer = AKMixer(fmOsc) 160 | noiseMixer = AKMixer(noiseADSR) 161 | 162 | // Default non-VCO's off 163 | subOscMixer.volume = 0 164 | fmOscMixer.volume = 0 165 | noiseMixer.volume = 0 166 | 167 | vcoBalancer = AKDryWetMixer(vco1Mixer, vco2Mixer, balance: 0.5) 168 | 169 | sourceMixer = AKMixer(vcoBalancer, fmOscMixer, subOscMixer, noiseMixer) 170 | 171 | super.init() 172 | 173 | avAudioNode = sourceMixer.avAudioNode 174 | } 175 | 176 | /// Function to start, play, or activate the node, all do the same thing 177 | override func play(noteNumber: MIDINoteNumber, velocity: MIDIVelocity) { 178 | 179 | vco1.play(noteNumber: MIDINoteNumber(Int(noteNumber) + offset1), velocity: velocity) 180 | vco2.play(noteNumber: MIDINoteNumber(Int(noteNumber) + offset2), velocity: velocity) 181 | if noteNumber >= 12 { 182 | subOsc.play(noteNumber: noteNumber - 12, velocity: velocity) 183 | } 184 | fmOsc.play(noteNumber: noteNumber, velocity: velocity) 185 | if onNotes.isEmpty { 186 | noise.start() 187 | noiseADSR.start() 188 | } 189 | onNotes.insert(noteNumber) 190 | } 191 | 192 | /// Function to stop or bypass the node, both are equivalent 193 | override func stop(noteNumber: MIDINoteNumber) { 194 | 195 | vco1.stop(noteNumber: MIDINoteNumber(Int(noteNumber) + offset1)) 196 | vco2.stop(noteNumber: MIDINoteNumber(Int(noteNumber) + offset2)) 197 | if noteNumber >= 12 { 198 | subOsc.stop(noteNumber: noteNumber - 12) 199 | } 200 | fmOsc.stop(noteNumber: noteNumber) 201 | onNotes.remove(noteNumber) 202 | if onNotes.isEmpty { 203 | noiseADSR.stop() 204 | } 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /AnalogSynthX/SMSegmentView/SMSegment.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SMSegment.swift 3 | // 4 | // Created by Si MA, revision history on Githbub. 5 | // Copyright (c) 2016 Si Ma. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | 10 | open class SMSegment: SMBasicSegment { 11 | 12 | // UI Elements 13 | override open var frame: CGRect { 14 | didSet { 15 | self.resetContentFrame() 16 | } 17 | } 18 | 19 | open var verticalMargin: CGFloat = 5.0 { 20 | didSet { 21 | self.resetContentFrame() 22 | } 23 | } 24 | 25 | // Segment Colour 26 | open var onSelectionColour: UIColor = UIColor.darkGray { 27 | didSet { 28 | if self.isSelected == true { 29 | self.backgroundColor = self.onSelectionColour 30 | } 31 | } 32 | } 33 | open var offSelectionColour: UIColor = UIColor.white { 34 | didSet { 35 | if self.isSelected == false { 36 | self.backgroundColor = self.offSelectionColour 37 | } 38 | } 39 | } 40 | fileprivate var willOnSelectionColour: UIColor! { 41 | var hue: CGFloat = 0.0 42 | var saturation: CGFloat = 0.0 43 | var brightness: CGFloat = 0.0 44 | var alpha: CGFloat = 0.0 45 | self.onSelectionColour.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) 46 | return UIColor(hue: hue, saturation: saturation * 0.5, brightness: min(brightness * 1.5, 1.0), alpha: alpha) 47 | } 48 | 49 | // Segment Title Text & Colour & Font 50 | open var title: String? { 51 | didSet { 52 | self.label.text = self.title 53 | 54 | if let titleText = self.label.text as NSString? { 55 | self.labelWidth = titleText.boundingRect(with: CGSize(width: self.frame.size.width, 56 | height: self.frame.size.height), 57 | options:NSStringDrawingOptions.usesLineFragmentOrigin, 58 | attributes: [NSAttributedStringKey.font: self.label.font], 59 | context: nil).size.width 60 | } else { 61 | self.labelWidth = 0.0 62 | } 63 | 64 | self.resetContentFrame() 65 | } 66 | } 67 | open var onSelectionTextColour: UIColor = UIColor.white { 68 | didSet { 69 | if self.isSelected == true { 70 | self.label.textColor = self.onSelectionTextColour 71 | } 72 | } 73 | } 74 | open var offSelectionTextColour: UIColor = UIColor.darkGray { 75 | didSet { 76 | if self.isSelected == false { 77 | self.label.textColor = self.offSelectionTextColour 78 | } 79 | } 80 | } 81 | open var titleFont: UIFont = UIFont.systemFont(ofSize: 17.0) { 82 | didSet { 83 | self.label.font = self.titleFont 84 | 85 | if let titleText = self.label.text as NSString? { 86 | self.labelWidth = titleText.boundingRect(with: CGSize(width: self.frame.size.width + 1.0, 87 | height: self.frame.size.height), 88 | options:NSStringDrawingOptions.usesLineFragmentOrigin, 89 | attributes: [NSAttributedStringKey.font: self.label.font], 90 | context: nil).size.width 91 | } else { 92 | self.labelWidth = 0.0 93 | } 94 | 95 | self.resetContentFrame() 96 | } 97 | } 98 | 99 | // Segment Image 100 | open var onSelectionImage: UIImage? { 101 | didSet { 102 | if self.onSelectionImage != nil { 103 | self.resetContentFrame() 104 | } 105 | if self.isSelected == true { 106 | self.imageView.image = self.onSelectionImage 107 | } 108 | } 109 | } 110 | open var offSelectionImage: UIImage? { 111 | didSet { 112 | if self.offSelectionImage != nil { 113 | self.resetContentFrame() 114 | } 115 | if self.isSelected == false { 116 | self.imageView.image = self.offSelectionImage 117 | } 118 | } 119 | } 120 | 121 | fileprivate var imageView: UIImageView = UIImageView() 122 | fileprivate var label: UILabel = UILabel() 123 | fileprivate var labelWidth: CGFloat = 0.0 124 | 125 | required public init?(coder aDecoder: NSCoder) { 126 | fatalError("init(coder:) has not been implemented") 127 | } 128 | 129 | public init(verticalMargin: CGFloat, 130 | onSelectionColour: UIColor, 131 | offSelectionColour: UIColor, 132 | onSelectionTextColour: UIColor, 133 | offSelectionTextColour: UIColor, 134 | titleFont: UIFont) { 135 | 136 | self.verticalMargin = verticalMargin 137 | self.onSelectionColour = onSelectionColour 138 | self.offSelectionColour = offSelectionColour 139 | self.onSelectionTextColour = onSelectionTextColour 140 | self.offSelectionTextColour = offSelectionTextColour 141 | self.titleFont = titleFont 142 | 143 | super.init(frame: CGRect.zero) 144 | self.setupUIElements() 145 | } 146 | 147 | func setupUIElements() { 148 | 149 | self.backgroundColor = self.offSelectionColour 150 | 151 | self.imageView.contentMode = UIViewContentMode.scaleAspectFit 152 | self.addSubview(self.imageView) 153 | 154 | self.label.textAlignment = NSTextAlignment.center 155 | self.label.font = self.titleFont 156 | self.label.textColor = self.offSelectionTextColour 157 | self.addSubview(self.label) 158 | } 159 | 160 | // MARK: Update Frame 161 | fileprivate func resetContentFrame() { 162 | 163 | var distanceBetween: CGFloat = 0.0 164 | var imageViewFrame = CGRect(x: 0.0, 165 | y: self.verticalMargin, 166 | width: 0.0, 167 | height: self.frame.size.height - self.verticalMargin * 2) 168 | 169 | if self.onSelectionImage != nil || self.offSelectionImage != nil { 170 | // Set imageView as a square 171 | imageViewFrame.size.width = self.frame.size.height - self.verticalMargin * 2 172 | distanceBetween = 5.0 173 | } 174 | 175 | // If there's no text, align imageView centred 176 | // Else align text centred 177 | if self.labelWidth == 0.0 { 178 | imageViewFrame.origin.x = max((self.frame.size.width - imageViewFrame.size.width) / 2.0, 0.0) 179 | } else { 180 | imageViewFrame.origin.x = 181 | max((self.frame.size.width - imageViewFrame.size.width - self.labelWidth) / 2.0 - distanceBetween, 0.0) 182 | } 183 | 184 | self.imageView.frame = imageViewFrame 185 | 186 | self.label.frame = CGRect(x: imageViewFrame.origin.x + imageViewFrame.size.width + distanceBetween, 187 | y: self.verticalMargin, 188 | width: self.labelWidth, 189 | height: self.frame.size.height - self.verticalMargin * 2) 190 | } 191 | 192 | // MARK: Selections 193 | override open func setSelected(_ selected: Bool, inView view: SMBasicSegmentView) { 194 | super.setSelected(selected, inView: view) 195 | if selected { 196 | self.backgroundColor = self.onSelectionColour 197 | self.label.textColor = self.onSelectionTextColour 198 | self.imageView.image = self.onSelectionImage 199 | } else { 200 | self.backgroundColor = self.offSelectionColour 201 | self.label.textColor = self.offSelectionTextColour 202 | self.imageView.image = self.offSelectionImage 203 | } 204 | } 205 | 206 | // MARK: Handle touch 207 | override open func touchesBegan(_ touches: Set, with event: UIEvent?) { 208 | super.touchesBegan(touches, with: event) 209 | 210 | if self.isSelected == false { 211 | self.backgroundColor = self.willOnSelectionColour 212 | } 213 | } 214 | 215 | } 216 | -------------------------------------------------------------------------------- /AnalogSynthX/CustomControls/KnobStyleKit.swift: -------------------------------------------------------------------------------- 1 | // 2 | // KnobStyleKit.swift 3 | // Analog Synth X 4 | // 5 | // Created by Matthew Fecher, revision history on Githbub. 6 | // Copyright © 2018 AudioKit. All rights reserved. 7 | // 8 | // Generated by PaintCode 9 | // http://www.paintcodeapp.com 10 | // 11 | 12 | import UIKit 13 | 14 | public class KnobStyleKit: NSObject { 15 | 16 | //// Drawing Methods 17 | 18 | @objc dynamic public class func drawKnobOne(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 124, height: 124), resizing: ResizingBehavior = .aspectFit, knobValue: CGFloat = 0.5) { 19 | //// General Declarations 20 | let context = UIGraphicsGetCurrentContext()! 21 | 22 | //// Resize to Target Frame 23 | context.saveGState() 24 | let resizedFrame: CGRect = resizing.apply(rect: CGRect(x: 0, y: 0, width: 124, height: 124), target: targetFrame) 25 | context.translateBy(x: resizedFrame.minX, y: resizedFrame.minY) 26 | context.scaleBy(x: resizedFrame.width / 124, y: resizedFrame.height / 124) 27 | let resizedShadowScale: CGFloat = min(resizedFrame.width / 124, resizedFrame.height / 124) 28 | 29 | //// Color Declarations 30 | let black = UIColor(red: 0.000, green: 0.000, blue: 0.000, alpha: 1.000) 31 | let shadowColor = UIColor(red: 1.000, green: 0.596, blue: 0.000, alpha: 1.000) 32 | let knobBottom = UIColor(red: 0.180, green: 0.180, blue: 0.192, alpha: 1.000) 33 | let knobLight = UIColor(red: 0.498, green: 0.498, blue: 0.510, alpha: 1.000) 34 | let knobTop2 = UIColor(red: 0.141, green: 0.141, blue: 0.161, alpha: 1.000) 35 | let orange2 = UIColor(red: 0.902, green: 0.533, blue: 0.008, alpha: 1.000) 36 | 37 | //// Gradient Declarations 38 | let edge2 = CGGradient(colorsSpace: nil, colors: [knobBottom.cgColor, knobBottom.blended(withFraction: 0.5, of: knobTop2).cgColor, knobTop2.cgColor, knobTop2.blended(withFraction: 0.5, of: knobLight).cgColor, knobLight.cgColor] as CFArray, locations: [0, 0.23, 0.41, 0.73, 1])! 39 | let lowerKnobGradient2 = CGGradient(colorsSpace: nil, colors: [knobTop2.cgColor, knobBottom.cgColor, knobLight.cgColor] as CFArray, locations: [0, 0.51, 1])! 40 | 41 | //// Shadow Declarations 42 | let shadow2 = NSShadow() 43 | shadow2.shadowColor = UIColor.black.withAlphaComponent(0.46) 44 | shadow2.shadowOffset = CGSize(width: 2, height: 8) 45 | shadow2.shadowBlurRadius = 5 46 | let shadow3 = NSShadow() 47 | shadow3.shadowColor = knobLight.withAlphaComponent(0.41 * knobLight.cgColor.alpha) 48 | shadow3.shadowOffset = CGSize(width: 0, height: 10) 49 | shadow3.shadowBlurRadius = 5 50 | let shadow4 = NSShadow() 51 | shadow4.shadowColor = shadowColor 52 | shadow4.shadowOffset = CGSize(width: 0, height: 0) 53 | shadow4.shadowBlurRadius = 12 54 | 55 | //// Variable Declarations 56 | let knobAngle: CGFloat = -240 * knobValue 57 | 58 | //// Knob 59 | context.saveGState() 60 | context.translateBy(x: 3, y: 3) 61 | 62 | //// BlackBackground Drawing 63 | let blackBackgroundPath = UIBezierPath(ovalIn: CGRect(x: -1, y: -1, width: 120, height: 120)) 64 | black.setFill() 65 | blackBackgroundPath.fill() 66 | 67 | //// GradientKnob 2 Drawing 68 | let gradientKnob2Path = UIBezierPath(ovalIn: CGRect(x: 8, y: 8, width: 102, height: 102)) 69 | context.saveGState() 70 | gradientKnob2Path.addClip() 71 | context.drawLinearGradient(lowerKnobGradient2, start: CGPoint(x: 59, y: 110), end: CGPoint(x: 59, y: 8), options: []) 72 | context.restoreGState() 73 | 74 | //// GradientKnob Drawing 75 | let gradientKnobPath = UIBezierPath(ovalIn: CGRect(x: 14, y: 14, width: 90, height: 90)) 76 | context.saveGState() 77 | context.setShadow(offset: CGSize(width: shadow2.shadowOffset.width * resizedShadowScale, height: shadow2.shadowOffset.height * resizedShadowScale), blur: shadow2.shadowBlurRadius * resizedShadowScale, color: (shadow2.shadowColor as! UIColor).cgColor) 78 | context.beginTransparencyLayer(auxiliaryInfo: nil) 79 | gradientKnobPath.addClip() 80 | context.drawLinearGradient(edge2, start: CGPoint(x: 59, y: 104), end: CGPoint(x: 59, y: 14), options: []) 81 | context.endTransparencyLayer() 82 | 83 | ////// GradientKnob Inner Shadow 84 | context.saveGState() 85 | context.clip(to: gradientKnobPath.bounds) 86 | context.setShadow(offset: CGSize.zero, blur: 0) 87 | context.setAlpha((shadow3.shadowColor as! UIColor).cgColor.alpha) 88 | context.beginTransparencyLayer(auxiliaryInfo: nil) 89 | let gradientKnobOpaqueShadow = (shadow3.shadowColor as! UIColor).withAlphaComponent(1) 90 | context.setShadow(offset: CGSize(width: shadow3.shadowOffset.width * resizedShadowScale, height: shadow3.shadowOffset.height * resizedShadowScale), blur: shadow3.shadowBlurRadius * resizedShadowScale, color: gradientKnobOpaqueShadow.cgColor) 91 | context.setBlendMode(.sourceOut) 92 | context.beginTransparencyLayer(auxiliaryInfo: nil) 93 | 94 | gradientKnobOpaqueShadow.setFill() 95 | gradientKnobPath.fill() 96 | 97 | context.endTransparencyLayer() 98 | context.endTransparencyLayer() 99 | context.restoreGState() 100 | 101 | context.restoreGState() 102 | 103 | //// IndicatorGroup 104 | //// Indicator Drawing 105 | context.saveGState() 106 | context.translateBy(x: 59, y: 59) 107 | context.rotate(by: -(knobAngle - 240) * CGFloat.pi / 180) 108 | 109 | let indicatorPath = UIBezierPath(rect: CGRect(x: -3, y: -45, width: 6, height: 17)) 110 | context.saveGState() 111 | context.setShadow(offset: CGSize(width: shadow4.shadowOffset.width * resizedShadowScale, height: shadow4.shadowOffset.height * resizedShadowScale), blur: shadow4.shadowBlurRadius * resizedShadowScale, color: (shadow4.shadowColor as! UIColor).cgColor) 112 | orange2.setFill() 113 | indicatorPath.fill() 114 | context.restoreGState() 115 | 116 | context.restoreGState() 117 | 118 | context.restoreGState() 119 | 120 | context.restoreGState() 121 | 122 | } 123 | 124 | @objc(KnobStyleKitResizingBehavior) 125 | public enum ResizingBehavior: Int { 126 | case aspectFit /// The content is proportionally resized to fit into the target rectangle. 127 | case aspectFill /// The content is proportionally resized to completely fill the target rectangle. 128 | case stretch /// The content is stretched to match the entire target rectangle. 129 | case center /// The content is centered in the target rectangle, but it is NOT resized. 130 | 131 | public func apply(rect: CGRect, target: CGRect) -> CGRect { 132 | if rect == target || target == CGRect.zero { 133 | return rect 134 | } 135 | 136 | var scales = CGSize.zero 137 | scales.width = abs(target.width / rect.width) 138 | scales.height = abs(target.height / rect.height) 139 | 140 | switch self { 141 | case .aspectFit: 142 | scales.width = min(scales.width, scales.height) 143 | scales.height = scales.width 144 | case .aspectFill: 145 | scales.width = max(scales.width, scales.height) 146 | scales.height = scales.width 147 | case .stretch: 148 | break 149 | case .center: 150 | scales.width = 1 151 | scales.height = 1 152 | } 153 | 154 | var result = rect.standardized 155 | result.size.width *= scales.width 156 | result.size.height *= scales.height 157 | result.origin.x = target.minX + (target.width - result.width) / 2 158 | result.origin.y = target.minY + (target.height - result.height) / 2 159 | return result 160 | } 161 | } 162 | } 163 | 164 | private extension UIColor { 165 | func blended(withFraction fraction: CGFloat, of color: UIColor) -> UIColor { 166 | var r1: CGFloat = 1, g1: CGFloat = 1, b1: CGFloat = 1, a1: CGFloat = 1 167 | var r2: CGFloat = 1, g2: CGFloat = 1, b2: CGFloat = 1, a2: CGFloat = 1 168 | 169 | self.getRed(&r1, green: &g1, blue: &b1, alpha: &a1) 170 | color.getRed(&r2, green: &g2, blue: &b2, alpha: &a2) 171 | 172 | return UIColor(red: r1 * (1 - fraction) + r2 * fraction, 173 | green: g1 * (1 - fraction) + g2 * fraction, 174 | blue: b1 * (1 - fraction) + b2 * fraction, 175 | alpha: a1 * (1 - fraction) + a2 * fraction) 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /AnalogSynthX/SynthViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SynthViewController.swift 3 | // Swift Synth 4 | // 5 | // Created by Matthew Fecher, revision history on Githbub. 6 | // Copyright © 2018 AudioKit. All rights reserved. 7 | // 8 | 9 | import AudioKit 10 | import AudioKitUI 11 | import UIKit 12 | 13 | class SynthViewController: UIViewController { 14 | 15 | // ********************************************************* 16 | // MARK: - Instance Properties 17 | // ********************************************************* 18 | 19 | @IBOutlet fileprivate weak var statusLabel: UILabel! 20 | @IBOutlet fileprivate weak var octavePositionLabel: UILabel! 21 | @IBOutlet fileprivate weak var oscMixKnob: Knob! 22 | @IBOutlet fileprivate weak var osc1SemitonesKnob: Knob! 23 | @IBOutlet fileprivate weak var osc2SemitonesKnob: Knob! 24 | @IBOutlet fileprivate weak var osc2DetuneKnob: Knob! 25 | @IBOutlet fileprivate weak var lfoAmtKnob: Knob! 26 | @IBOutlet fileprivate weak var lfoRateKnob: Knob! 27 | @IBOutlet fileprivate weak var crushAmtKnob: Knob! 28 | @IBOutlet fileprivate weak var delayTimeKnob: Knob! 29 | @IBOutlet fileprivate weak var delayMixKnob: Knob! 30 | @IBOutlet fileprivate weak var reverbAmtKnob: Knob! 31 | @IBOutlet fileprivate weak var reverbMixKnob: Knob! 32 | @IBOutlet fileprivate weak var cutoffKnob: Knob! 33 | @IBOutlet fileprivate weak var rezKnob: Knob! 34 | @IBOutlet fileprivate weak var subMixKnob: Knob! 35 | @IBOutlet fileprivate weak var fmMixKnob: Knob! 36 | @IBOutlet fileprivate weak var fmModKnob: Knob! 37 | @IBOutlet fileprivate weak var noiseMixKnob: Knob! 38 | @IBOutlet fileprivate weak var morphKnob: Knob! 39 | @IBOutlet fileprivate weak var masterVolKnob: Knob! 40 | @IBOutlet fileprivate weak var attackSlider: VerticalSlider! 41 | @IBOutlet fileprivate weak var decaySlider: VerticalSlider! 42 | @IBOutlet fileprivate weak var sustainSlider: VerticalSlider! 43 | @IBOutlet fileprivate weak var releaseSlider: VerticalSlider! 44 | @IBOutlet fileprivate weak var vco1Toggle: UIButton! 45 | @IBOutlet fileprivate weak var vco2Toggle: UIButton! 46 | @IBOutlet fileprivate weak var bitcrushToggle: UIButton! 47 | @IBOutlet fileprivate weak var filterToggle: UIButton! 48 | @IBOutlet fileprivate weak var delayToggle: UIButton! 49 | @IBOutlet fileprivate weak var reverbToggle: UIButton! 50 | @IBOutlet fileprivate weak var fattenToggle: UIButton! 51 | @IBOutlet fileprivate weak var holdToggle: UIButton! 52 | @IBOutlet fileprivate weak var monoToggle: UIButton! 53 | @IBOutlet weak var audioPlot: AKNodeOutputPlot! 54 | @IBOutlet fileprivate weak var plotToggle: UIButton! 55 | 56 | enum ControlTag: Int { 57 | case cutoff = 101 58 | case rez = 102 59 | case vco1Waveform = 103 60 | case vco2Waveform = 104 61 | case vco1Semitones = 105 62 | case vco2Semitones = 106 63 | case vco2Detune = 107 64 | case oscMix = 108 65 | case subMix = 109 66 | case fmMix = 110 67 | case fmMod = 111 68 | case lfoWaveform = 112 69 | case morph = 113 70 | case noiseMix = 114 71 | case lfoAmt = 115 72 | case lfoRate = 116 73 | case crushAmt = 117 74 | case delayTime = 118 75 | case delayMix = 119 76 | case reverbAmt = 120 77 | case reverbMix = 121 78 | case masterVol = 122 79 | case adsrAttack = 123 80 | case adsrDecay = 124 81 | case adsrSustain = 125 82 | case adsrRelease = 126 83 | } 84 | 85 | var keyboardOctavePosition: Int = 0 86 | var lastKey: UIButton? 87 | var monoMode: Bool = false 88 | var holdMode: Bool = false 89 | var midiNotesHeld = [MIDINoteNumber]() 90 | let blackKeys = [49, 51, 54, 56, 58, 61, 63, 66, 68, 70] 91 | 92 | var conductor = Conductor.sharedInstance 93 | 94 | // ********************************************************* 95 | // MARK: - viewDidLoad 96 | // ********************************************************* 97 | 98 | override func viewDidLoad() { 99 | super.viewDidLoad() 100 | 101 | // Create WaveformSegmentedViews 102 | createWaveFormSegmentViews() 103 | 104 | // Set Delegates 105 | setDelegates() 106 | 107 | // Set Preset Control Values 108 | setDefaultValues() 109 | 110 | // Greeting 111 | statusLabel.text = String.randomGreeting() 112 | } 113 | 114 | // ********************************************************* 115 | // MARK: - Defaults/Presets 116 | // ********************************************************* 117 | 118 | func setDefaultValues() { 119 | 120 | // Set Preset Values 121 | conductor.masterVolume.volume = 1.0 // Master Volume 122 | conductor.core.offset2 = 0 // VCO2 Semitones 123 | conductor.core.vco2.vibratoDepth = 0.0 // VCO2 Detune (Hz) 124 | conductor.core.vco2.vibratoRate = 1.0 // VCO2 Detune (Hz) 125 | conductor.core.vcoBalancer.balance = 0.5 // VCO1/VCO2 Mix 126 | conductor.core.subOscMixer.volume = 0.0 // SubOsc Mix 127 | conductor.core.fmOscMixer.volume = 0.0 // FM Mix 128 | conductor.core.fmOsc.modulationIndex = 0.0 // FM Modulation Amt 129 | conductor.core.morph = 0.0 // Morphing between waveforms 130 | conductor.core.noiseMixer.volume = 0.0 // Noise Mix 131 | conductor.filterSection.lfoAmplitude = 0.0 // LFO Amp (Hz) 132 | conductor.filterSection.lfoRate = 1.4 // LFO Rate 133 | conductor.filterSection.resonance = 0.5 // Filter Q/Rez 134 | conductor.multiDelay.time = 0.5 // Delay (seconds) 135 | conductor.multiDelay.mix = 0.5 // Dry/Wet 136 | conductor.reverb.feedback = 0.88 // Amt 137 | conductor.reverbMixer.balance = 0.4 // Dry/Wet 138 | conductor.midiBendRange = 2.0 // MIDI bend range in +/- semitones 139 | 140 | cutoffKnob.value = 0.36 // Cutoff Knob Position 141 | crushAmtKnob.value = 0.0 // Crusher Knob Position 142 | 143 | // ADSR 144 | conductor.core.attackDuration = 0.1 145 | conductor.core.decayDuration = 0.1 146 | conductor.core.sustainLevel = 0.66 147 | conductor.core.releaseDuration = 0.5 148 | 149 | // Update Knob & Slider UI Values 150 | setupKnobValues() 151 | setupSliderValues() 152 | 153 | // Update Toggle Presets 154 | displayModeToggled(plotToggle) 155 | 156 | vco1Toggled(vco1Toggle) 157 | vco2Toggled(vco2Toggle) 158 | filterToggled(filterToggle) 159 | delayToggled(delayToggle) 160 | reverbToggled(reverbToggle) 161 | } 162 | 163 | func setupKnobValues() { 164 | osc1SemitonesKnob.minimum = -12 165 | osc1SemitonesKnob.maximum = 12 166 | osc1SemitonesKnob.value = Double(conductor.core.offset1) 167 | 168 | osc2SemitonesKnob.minimum = -12 169 | osc2SemitonesKnob.maximum = 12 170 | osc2SemitonesKnob.value = Double(conductor.core.offset2) 171 | 172 | osc2DetuneKnob.minimum = -0.25 173 | osc2DetuneKnob.maximum = 0.25 174 | osc2DetuneKnob.value = conductor.core.vco2.vibratoDepth 175 | 176 | subMixKnob.maximum = 1.0 177 | subMixKnob.value = conductor.core.subOscMixer.volume 178 | 179 | fmMixKnob.maximum = 1.25 180 | fmMixKnob.value = conductor.core.fmOscMixer.volume 181 | 182 | fmModKnob.maximum = 15 183 | 184 | morphKnob.minimum = -0.99 185 | morphKnob.maximum = 0.99 186 | morphKnob.value = conductor.core.morph 187 | 188 | noiseMixKnob.value = conductor.core.noiseMixer.volume 189 | 190 | oscMixKnob.value = conductor.core.vcoBalancer.balance 191 | 192 | lfoAmtKnob.maximum = 1_200 193 | lfoAmtKnob.value = conductor.filterSection.lfoAmplitude 194 | 195 | lfoRateKnob.maximum = 5 196 | lfoRateKnob.value = conductor.filterSection.lfoRate 197 | 198 | rezKnob.maximum = 0.99 199 | rezKnob.value = conductor.filterSection.resonance 200 | 201 | delayTimeKnob.value = conductor.multiDelay.time 202 | delayMixKnob.value = conductor.multiDelay.mix 203 | 204 | reverbAmtKnob.maximum = 0.99 205 | reverbAmtKnob.value = conductor.reverb.feedback 206 | reverbMixKnob.value = conductor.reverbMixer.balance 207 | 208 | masterVolKnob.maximum = 1.0 209 | masterVolKnob.value = conductor.masterVolume.volume 210 | 211 | // Calculate Logarithmic scales based on knob position 212 | conductor.filterSection.cutoffFrequency = cutoffFreqFromValue(Double(cutoffKnob.value)) 213 | conductor.bitCrusher.sampleRate = crusherFreqFromValue(Double(crushAmtKnob.value)) 214 | conductor.bitCrusher.bitDepth = 8 215 | } 216 | 217 | func setupSliderValues() { 218 | attackSlider.maxValue = 1.0 219 | attackSlider.currentValue = CGFloat(conductor.core.attackDuration) 220 | 221 | decaySlider.maxValue = 1.0 222 | decaySlider.currentValue = CGFloat(conductor.core.decayDuration) 223 | 224 | sustainSlider.currentValue = CGFloat(conductor.core.sustainLevel) 225 | 226 | releaseSlider.maxValue = 2 227 | releaseSlider.currentValue = CGFloat(conductor.core.releaseDuration) 228 | } 229 | 230 | //***************************************************************** 231 | // MARK: - IBActions 232 | //***************************************************************** 233 | 234 | @IBAction func vco1Toggled(_ sender: UIButton) { 235 | if sender.isSelected { 236 | sender.isSelected = false 237 | statusLabel.text = "VCO 1 Off" 238 | conductor.core.vco1On = false 239 | } else { 240 | sender.isSelected = true 241 | statusLabel.text = "VCO 1 On" 242 | conductor.core.vco1On = true 243 | } 244 | } 245 | 246 | @IBAction func vco2Toggled(_ sender: UIButton) { 247 | if sender.isSelected { 248 | sender.isSelected = false 249 | statusLabel.text = "VCO 2 Off" 250 | conductor.core.vco2On = false 251 | } else { 252 | sender.isSelected = true 253 | statusLabel.text = "VCO 2 On" 254 | conductor.core.vco2On = true 255 | } 256 | } 257 | 258 | @IBAction func crusherToggled(_ sender: UIButton) { 259 | if sender.isSelected { 260 | sender.isSelected = false 261 | statusLabel.text = "Bitcrush Off" 262 | conductor.bitCrusher.bypass() 263 | } else { 264 | sender.isSelected = true 265 | statusLabel.text = "Bitcrush On" 266 | conductor.bitCrusher.start() 267 | } 268 | } 269 | 270 | @IBAction func filterToggled(_ sender: UIButton) { 271 | if sender.isSelected { 272 | sender.isSelected = false 273 | statusLabel.text = "Filter Off" 274 | conductor.filterSection.output.stop() 275 | } else { 276 | sender.isSelected = true 277 | statusLabel.text = "Filter On" 278 | conductor.filterSection.output.start() 279 | } 280 | } 281 | 282 | @IBAction func delayToggled(_ sender: UIButton) { 283 | if sender.isSelected { 284 | sender.isSelected = false 285 | statusLabel.text = "Delay Off" 286 | conductor.multiDelayMixer.balance = 0 287 | } else { 288 | sender.isSelected = true 289 | statusLabel.text = "Delay On" 290 | conductor.multiDelayMixer.balance = 1 291 | } 292 | } 293 | 294 | @IBAction func reverbToggled(_ sender: UIButton) { 295 | if sender.isSelected { 296 | sender.isSelected = false 297 | statusLabel.text = "Reverb Off" 298 | conductor.reverb.bypass() 299 | } else { 300 | sender.isSelected = true 301 | statusLabel.text = "Reverb On" 302 | conductor.reverb.start() 303 | } 304 | } 305 | 306 | @IBAction func stereoFattenToggled(_ sender: UIButton) { 307 | if sender.isSelected { 308 | sender.isSelected = false 309 | statusLabel.text = "Stereo Fatten Off" 310 | conductor.fatten.dryWetMix.balance = 0 311 | } else { 312 | sender.isSelected = true 313 | statusLabel.text = "Stereo Fatten On" 314 | conductor.fatten.dryWetMix.balance = 1 315 | } 316 | } 317 | 318 | // Keyboard 319 | @IBAction func octaveDownPressed(_ sender: UIButton) { 320 | guard keyboardOctavePosition > -2 else { 321 | statusLabel.text = "How low can you go? This low." 322 | return 323 | } 324 | 325 | keyboardOctavePosition += -1 326 | octavePositionLabel.text = String(keyboardOctavePosition) 327 | redisplayHeldKeys() 328 | 329 | } 330 | 331 | @IBAction func octaveUpPressed(_ sender: UIButton) { 332 | guard keyboardOctavePosition < 3 else { 333 | statusLabel.text = "Captain, she can't go any higher!" 334 | return 335 | } 336 | 337 | keyboardOctavePosition += 1 338 | octavePositionLabel.text = String(keyboardOctavePosition) 339 | redisplayHeldKeys() 340 | } 341 | 342 | @IBAction func holdModeToggled(_ sender: UIButton) { 343 | if sender.isSelected { 344 | sender.isSelected = false 345 | statusLabel.text = "Hold Mode Off" 346 | holdMode = false 347 | turnOffHeldKeys() 348 | } else { 349 | sender.isSelected = true 350 | statusLabel.text = "Hold Mode On" 351 | holdMode = true 352 | } 353 | } 354 | 355 | @IBAction func monoModeToggled(_ sender: UIButton) { 356 | if sender.isSelected { 357 | sender.isSelected = false 358 | statusLabel.text = "Mono Mode Off" 359 | monoMode = false 360 | } else { 361 | sender.isSelected = true 362 | statusLabel.text = "Mono Mode On" 363 | monoMode = true 364 | turnOffHeldKeys() 365 | } 366 | } 367 | 368 | // Universal 369 | @IBAction func midiPanicPressed(_ sender: RoundedButton) { 370 | turnOffHeldKeys() 371 | statusLabel.text = "All Notes Off" 372 | } 373 | 374 | @IBAction func displayModeToggled(_ sender: UIButton) { 375 | if sender.isSelected { 376 | sender.isSelected = false 377 | statusLabel.text = "Wave Display Filled Off" 378 | audioPlot.shouldFill = false 379 | } else { 380 | sender.isSelected = true 381 | statusLabel.text = "Wave Display Filled On" 382 | audioPlot.shouldFill = true 383 | } 384 | } 385 | 386 | // About App 387 | @IBAction func buildThisSynth(_ sender: RoundedButton) { 388 | openURL("https://audiokitpro.com/audiokit/") 389 | } 390 | 391 | @IBAction func newAppPressed(_ sender: RoundedButton) { 392 | openURL("https://audiokitpro.com/audiokit-synth-one/") 393 | } 394 | 395 | @IBAction func webPressed(_ sender: RoundedButton) { 396 | openURL("http://audiokit.io/examples/AnalogSynthX") 397 | } 398 | 399 | @IBAction func updatePressed(_ sender: RoundedButton) { 400 | openURL("https://itunes.apple.com/us/app/audiokit-synth-one-synthesizer/id1371050497?ls=1&mt=8") 401 | } 402 | 403 | 404 | //***************************************************************** 405 | // MARK: - 🎹 Key Presses 406 | //***************************************************************** 407 | 408 | @IBAction func keyPressed(_ sender: UIButton) { 409 | let key = sender 410 | 411 | // Turn off last key press in Mono 412 | if monoMode { 413 | if let lastKey = lastKey { 414 | turnOffKey(lastKey) 415 | } 416 | } 417 | 418 | // Toggle key if in Hold mode 419 | if holdMode { 420 | if midiNotesHeld.contains(midiNoteFromTag(key.tag)) { 421 | turnOffKey(key) 422 | return 423 | } 424 | } 425 | 426 | turnOnKey(key) 427 | lastKey = key 428 | } 429 | 430 | @IBAction func keyReleased(_ sender: UIButton) { 431 | let key = sender 432 | 433 | if holdMode && monoMode { 434 | toggleMonoKeyHeld(key) 435 | } else if holdMode && !monoMode { 436 | toggleKeyHeld(key) 437 | 438 | } else { 439 | turnOffKey(key) 440 | } 441 | } 442 | 443 | // ********************************************************* 444 | // MARK: - 🎹 Key UI/UX Helpers 445 | // ********************************************************* 446 | 447 | func turnOnKey(_ key: UIButton) { 448 | updateKeyToDownPosition(key) 449 | let midiNote = midiNoteFromTag(key.tag) 450 | statusLabel.text = "Key Pressed: \(noteNameFromMidiNote(midiNote))" 451 | conductor.core.play(noteNumber: midiNote, velocity: 127) 452 | } 453 | 454 | func turnOffKey(_ key: UIButton) { 455 | updateKeyToUpPosition(key) 456 | statusLabel.text = "Key Released" 457 | conductor.core.stop(noteNumber: midiNoteFromTag(key.tag)) 458 | } 459 | 460 | func turnOffHeldKeys() { 461 | updateAllKeysToUpPosition() 462 | 463 | for note in 0...127 { 464 | conductor.core.stop(noteNumber: MIDINoteNumber(note)) 465 | } 466 | midiNotesHeld.removeAll(keepingCapacity: false) 467 | } 468 | 469 | func updateAllKeysToUpPosition() { 470 | // Key up all keys shown on display 471 | for tag in 248...272 { 472 | guard let key = self.view.viewWithTag(tag) as? UIButton else { 473 | return 474 | } 475 | updateKeyToUpPosition(key) 476 | } 477 | } 478 | 479 | func redisplayHeldKeys() { 480 | 481 | // Determine new keyboard bounds 482 | let lowerMidiNote = MIDINoteNumber(48 + (keyboardOctavePosition * 12)) 483 | let upperMidiNote = lowerMidiNote + 24 484 | statusLabel.text = "Keyboard Range: " + 485 | "\(noteNameFromMidiNote(lowerMidiNote)) to " + 486 | "\(noteNameFromMidiNote(upperMidiNote))" 487 | 488 | guard !monoMode else { 489 | turnOffHeldKeys() 490 | return 491 | } 492 | 493 | // Refresh keyboard 494 | updateAllKeysToUpPosition() 495 | 496 | // Check notes currently in view and turn on if held 497 | for note in lowerMidiNote...upperMidiNote { 498 | if midiNotesHeld.contains(note) { 499 | let keyTag = (Int(note) - (keyboardOctavePosition * 12)) + 200 500 | guard let key = self.view.viewWithTag(keyTag) as? UIButton else { 501 | return 502 | } 503 | updateKeyToDownPosition(key) 504 | } 505 | } 506 | } 507 | 508 | func toggleKeyHeld(_ key: UIButton) { 509 | if let i = midiNotesHeld.index(of: midiNoteFromTag(key.tag)) { 510 | midiNotesHeld.remove(at: i) 511 | } else { 512 | midiNotesHeld.append(midiNoteFromTag(key.tag)) 513 | } 514 | } 515 | 516 | func toggleMonoKeyHeld(_ key: UIButton) { 517 | if midiNotesHeld.contains(midiNoteFromTag(key.tag)) { 518 | midiNotesHeld.removeAll() 519 | } else { 520 | midiNotesHeld.removeAll() 521 | midiNotesHeld.append(midiNoteFromTag(key.tag)) 522 | } 523 | } 524 | 525 | func updateKeyToUpPosition(_ key: UIButton) { 526 | let index = key.tag - 200 527 | if blackKeys.contains(index) { 528 | key.setImage(#imageLiteral(resourceName: "blackkey"), for: UIControlState()) 529 | } else { 530 | key.setImage(#imageLiteral(resourceName: "whitekey"), for: UIControlState()) 531 | } 532 | } 533 | 534 | func updateKeyToDownPosition(_ key: UIButton) { 535 | let index = key.tag - 200 536 | if blackKeys.contains(index) { 537 | key.setImage(#imageLiteral(resourceName:"blackkey_selected"), for: UIControlState()) 538 | } else { 539 | key.setImage(#imageLiteral(resourceName: "whitekey_selected"), for: UIControlState()) 540 | } 541 | } 542 | 543 | func midiNoteFromTag(_ tag: Int) -> MIDINoteNumber { 544 | return MIDINoteNumber((tag - 200) + (keyboardOctavePosition * 12)) 545 | } 546 | } 547 | 548 | //***************************************************************** 549 | // MARK: - 🎛 Knob Delegates 550 | //***************************************************************** 551 | 552 | extension SynthViewController: KnobDelegate { 553 | 554 | func updateKnobValue(_ value: Double, tag: Int) { 555 | 556 | switch tag { 557 | 558 | // VCOs 559 | case ControlTag.vco1Semitones.rawValue: 560 | let intValue = Int(floor(value)) 561 | statusLabel.text = "Semitones: \(intValue)" 562 | conductor.core.offset1 = intValue 563 | 564 | case ControlTag.vco2Semitones.rawValue: 565 | let intValue = Int(floor(value)) 566 | statusLabel.text = "Semitones: \(intValue)" 567 | conductor.core.offset2 = intValue 568 | 569 | case ControlTag.vco2Detune.rawValue: 570 | statusLabel.text = "Detune: \(value.decimalString) Hz" 571 | conductor.core.vco2.vibratoDepth = value 572 | 573 | case ControlTag.oscMix.rawValue: 574 | statusLabel.text = "OscMix: \(value.decimalString)" 575 | conductor.core.vcoBalancer.balance = value 576 | 577 | case ControlTag.morph.rawValue: 578 | statusLabel.text = "Morph Waveform: \(value.decimalString)" 579 | conductor.core.morph = value 580 | 581 | // Additional OSCs 582 | case ControlTag.subMix.rawValue: 583 | statusLabel.text = "Sub Osc: \(subMixKnob.knobValue.percentageString)" 584 | conductor.core.subOscMixer.volume = value 585 | 586 | case ControlTag.fmMix.rawValue: 587 | statusLabel.text = "FM Amt: \(fmMixKnob.knobValue.percentageString)" 588 | conductor.core.fmOscMixer.volume = value 589 | 590 | case ControlTag.fmMod.rawValue: 591 | statusLabel.text = "FM Mod: \(fmModKnob.knobValue.percentageString)" 592 | conductor.core.fmOsc.modulationIndex = value 593 | 594 | case ControlTag.noiseMix.rawValue: 595 | statusLabel.text = "Noise Amt: \(noiseMixKnob.knobValue.percentageString)" 596 | conductor.core.noiseMixer.volume = value 597 | 598 | // LFO 599 | case ControlTag.lfoAmt.rawValue: 600 | statusLabel.text = "LFO Amp: \(value.decimalString) Hz" 601 | conductor.filterSection.lfoAmplitude = value 602 | 603 | case ControlTag.lfoRate.rawValue: 604 | statusLabel.text = "LFO Rate: \(value.decimalString)" 605 | conductor.filterSection.lfoRate = value 606 | 607 | // Filter 608 | case ControlTag.cutoff.rawValue: 609 | let cutOffFrequency = cutoffFreqFromValue(value) 610 | statusLabel.text = "Cutoff: \(cutOffFrequency.decimalString) Hz" 611 | conductor.filterSection.cutoffFrequency = cutOffFrequency 612 | 613 | case ControlTag.rez.rawValue: 614 | statusLabel.text = "Rez: \(value.decimalString)" 615 | conductor.filterSection.resonance = value 616 | 617 | // Crusher 618 | case ControlTag.crushAmt.rawValue: 619 | let crushAmt = crusherFreqFromValue(value) 620 | statusLabel.text = "Bitcrush: \(crushAmt.decimalString) Sample Rate" 621 | conductor.bitCrusher.sampleRate = crushAmt 622 | 623 | // Delay 624 | case ControlTag.delayTime.rawValue: 625 | statusLabel.text = "Delay Time: \(value.decimal1000String) ms" 626 | conductor.multiDelay.time = value 627 | 628 | case ControlTag.delayMix.rawValue: 629 | statusLabel.text = "Delay Mix: \(value.decimalString)" 630 | conductor.multiDelay.mix = value 631 | 632 | // Reverb 633 | case ControlTag.reverbAmt.rawValue: 634 | if value == 0.99 { 635 | statusLabel.text = "Reverb Size: Grand Canyon!" 636 | } else { 637 | statusLabel.text = "Reverb Size: \(reverbAmtKnob.knobValue.percentageString)" 638 | } 639 | conductor.reverb.feedback = value 640 | 641 | case ControlTag.reverbMix.rawValue: 642 | statusLabel.text = "Reverb Mix: \(value.decimalString)" 643 | conductor.reverbMixer.balance = value 644 | 645 | // Master 646 | case ControlTag.masterVol.rawValue: 647 | statusLabel.text = "Master Vol: \(masterVolKnob.knobValue.percentageString)" 648 | conductor.masterVolume.volume = value 649 | 650 | default: 651 | break 652 | } 653 | } 654 | } 655 | 656 | //***************************************************************** 657 | // MARK: - 🎚Slider Delegate (ADSR) 658 | //***************************************************************** 659 | 660 | extension SynthViewController: VerticalSliderDelegate { 661 | func sliderValueDidChange(_ value: Double, tag: Int) { 662 | 663 | switch tag { 664 | case ControlTag.adsrAttack.rawValue: 665 | statusLabel.text = "Attack: \(attackSlider.sliderValue.percentageString)" 666 | conductor.core.attackDuration = value 667 | 668 | case ControlTag.adsrDecay.rawValue: 669 | statusLabel.text = "Decay: \(decaySlider.sliderValue.percentageString)" 670 | conductor.core.decayDuration = value 671 | 672 | case ControlTag.adsrSustain.rawValue: 673 | statusLabel.text = "Sustain: \(sustainSlider.sliderValue.percentageString)" 674 | conductor.core.sustainLevel = value 675 | 676 | case ControlTag.adsrRelease.rawValue: 677 | statusLabel.text = "Release: \(releaseSlider.sliderValue.percentageString)" 678 | conductor.core.releaseDuration = value 679 | 680 | default: 681 | break 682 | } 683 | } 684 | } 685 | 686 | //***************************************************************** 687 | // MARK: - WaveformSegmentedView Delegate 688 | //***************************************************************** 689 | 690 | extension SynthViewController: SMSegmentViewDelegate { 691 | 692 | // SMSegment Delegate 693 | func segmentView(_ segmentView: SMBasicSegmentView, didSelectSegmentAtIndex index: Int) { 694 | 695 | switch segmentView.tag { 696 | case ControlTag.vco1Waveform.rawValue: 697 | conductor.core.waveform1 = Double(index) 698 | statusLabel.text = "VCO1 Waveform Changed" 699 | 700 | case ControlTag.vco2Waveform.rawValue: 701 | conductor.core.waveform2 = Double(index) 702 | statusLabel.text = "VCO2 Waveform Changed" 703 | 704 | case ControlTag.lfoWaveform.rawValue: 705 | statusLabel.text = "LFO Waveform Changed" 706 | conductor.filterSection.lfoIndex = min(Double(index), 3) 707 | 708 | default: 709 | break 710 | } 711 | } 712 | } 713 | 714 | //***************************************************************** 715 | // MARK: - Set Delegates 716 | //***************************************************************** 717 | 718 | extension SynthViewController { 719 | 720 | func setDelegates() { 721 | oscMixKnob.delegate = self 722 | cutoffKnob.delegate = self 723 | rezKnob.delegate = self 724 | osc1SemitonesKnob.delegate = self 725 | osc2SemitonesKnob.delegate = self 726 | osc2DetuneKnob.delegate = self 727 | lfoAmtKnob.delegate = self 728 | lfoRateKnob.delegate = self 729 | crushAmtKnob.delegate = self 730 | delayTimeKnob.delegate = self 731 | delayMixKnob.delegate = self 732 | reverbAmtKnob.delegate = self 733 | reverbMixKnob.delegate = self 734 | subMixKnob.delegate = self 735 | fmMixKnob.delegate = self 736 | fmModKnob.delegate = self 737 | morphKnob.delegate = self 738 | noiseMixKnob.delegate = self 739 | masterVolKnob.delegate = self 740 | attackSlider.delegate = self 741 | decaySlider.delegate = self 742 | sustainSlider.delegate = self 743 | releaseSlider.delegate = self 744 | } 745 | } 746 | -------------------------------------------------------------------------------- /AnalogSynthX.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 7A1A9549E1538EC24A8D9831 /* Pods_AnalogSynthX.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B75886810A4646AB1B3DCF3E /* Pods_AnalogSynthX.framework */; }; 11 | 940D15131C49A9E200C88CA6 /* SynthVC+UIHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 940D15121C49A9E200C88CA6 /* SynthVC+UIHelpers.swift */; }; 12 | 940D15171C49AC5400C88CA6 /* WaveformSegmentedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 940D15161C49AC5400C88CA6 /* WaveformSegmentedView.swift */; }; 13 | 941771121C4C908000855BDA /* CGFloat+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 941771111C4C908000855BDA /* CGFloat+Extensions.swift */; }; 14 | 94453BC31C4499BD00608231 /* String+RandomGreeting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94453BC21C4499BD00608231 /* String+RandomGreeting.swift */; }; 15 | 948440791F254B850079FB9C /* KnobStyleKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 948440781F254B850079FB9C /* KnobStyleKit.swift */; }; 16 | 949B1C481C431E5400BFFA10 /* Knob+Touches.swift in Sources */ = {isa = PBXBuildFile; fileRef = 949B1C2B1C431E5400BFFA10 /* Knob+Touches.swift */; }; 17 | 949B1C491C431E5400BFFA10 /* Knob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 949B1C2C1C431E5400BFFA10 /* Knob.swift */; }; 18 | 949B1C4D1C431E5400BFFA10 /* RoundedButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 949B1C301C431E5400BFFA10 /* RoundedButton.swift */; }; 19 | 949B1C501C431E5400BFFA10 /* WaveformSegmentedView+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 949B1C341C431E5400BFFA10 /* WaveformSegmentedView+Extensions.swift */; }; 20 | 949B1C511C431E5400BFFA10 /* SMAlphaImageSegment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 949B1C361C431E5400BFFA10 /* SMAlphaImageSegment.swift */; }; 21 | 949B1C521C431E5400BFFA10 /* SMBasicSegment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 949B1C371C431E5400BFFA10 /* SMBasicSegment.swift */; }; 22 | 949B1C531C431E5400BFFA10 /* SMBasicSegmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 949B1C381C431E5400BFFA10 /* SMBasicSegmentView.swift */; }; 23 | 949B1C541C431E5400BFFA10 /* SMSegment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 949B1C391C431E5400BFFA10 /* SMSegment.swift */; }; 24 | 949B1C551C431E5400BFFA10 /* SMSegmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 949B1C3A1C431E5400BFFA10 /* SMSegmentView.swift */; }; 25 | 949B1C561C431E5400BFFA10 /* SynthViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 949B1C3B1C431E5400BFFA10 /* SynthViewController.swift */; }; 26 | 94B009E71C4B61BD000CF18E /* SynthVC+NoteNames.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94B009E61C4B61BD000CF18E /* SynthVC+NoteNames.swift */; }; 27 | 94FBB47E1C4483AE00E14C86 /* Double+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94FBB47D1C4483AE00E14C86 /* Double+Extensions.swift */; }; 28 | 94FBB4821C44868000E14C86 /* VerticalSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94FBB4811C44868000E14C86 /* VerticalSlider.swift */; }; 29 | C42FFBFA1C3DDAAC00823BD4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42FFBF91C3DDAAC00823BD4 /* AppDelegate.swift */; }; 30 | C42FFBFF1C3DDAAC00823BD4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C42FFBFD1C3DDAAC00823BD4 /* Main.storyboard */; }; 31 | C42FFC011C3DDAAC00823BD4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C42FFC001C3DDAAC00823BD4 /* Assets.xcassets */; }; 32 | C44760651DCD64A800628666 /* Audiobus.txt in Resources */ = {isa = PBXBuildFile; fileRef = C44760641DCD64A800628666 /* Audiobus.txt */; }; 33 | C44760681DCD65ED00628666 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C44760671DCD65ED00628666 /* AudioToolbox.framework */; }; 34 | C49D697A1D1F2CB000BF018A /* GeneratorBank.swift in Sources */ = {isa = PBXBuildFile; fileRef = C49D69791D1F2CB000BF018A /* GeneratorBank.swift */; }; 35 | C4CC1FD6209429A9006C5342 /* Audiobus.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CC1FD5209429A9006C5342 /* Audiobus.swift */; }; 36 | C4E8ED221C43AA8E0041965F /* Conductor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E8ED211C43AA8E0041965F /* Conductor.swift */; }; 37 | C4E8ED291C43ADA10041965F /* FilterSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E8ED281C43ADA10041965F /* FilterSection.swift */; }; 38 | C4E8ED2B1C43B04A0041965F /* MultiDelay.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E8ED2A1C43B04A0041965F /* MultiDelay.swift */; }; 39 | C4E8ED2D1C43B2540041965F /* Fatten.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E8ED2C1C43B2540041965F /* Fatten.swift */; }; 40 | EA10E15F1F4F9833003F0CA9 /* AudioKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA10E15D1F4F982D003F0CA9 /* AudioKitUI.framework */; }; 41 | EAF0A5B71C4F943E00F37994 /* AudioKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EAF0A5B61C4F943E00F37994 /* AudioKit.framework */; }; 42 | /* End PBXBuildFile section */ 43 | 44 | /* Begin PBXCopyFilesBuildPhase section */ 45 | C4E8ED011C4357040041965F /* CopyFiles */ = { 46 | isa = PBXCopyFilesBuildPhase; 47 | buildActionMask = 2147483647; 48 | dstPath = ""; 49 | dstSubfolderSpec = 10; 50 | files = ( 51 | ); 52 | runOnlyForDeploymentPostprocessing = 0; 53 | }; 54 | EA127F461C42094300289567 /* Embed Frameworks */ = { 55 | isa = PBXCopyFilesBuildPhase; 56 | buildActionMask = 2147483647; 57 | dstPath = ""; 58 | dstSubfolderSpec = 10; 59 | files = ( 60 | ); 61 | name = "Embed Frameworks"; 62 | runOnlyForDeploymentPostprocessing = 0; 63 | }; 64 | /* End PBXCopyFilesBuildPhase section */ 65 | 66 | /* Begin PBXFileReference section */ 67 | 894A16D4E1FB8A3B4DDBEDAF /* Pods-AnalogSynthX.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AnalogSynthX.release.xcconfig"; path = "Pods/Target Support Files/Pods-AnalogSynthX/Pods-AnalogSynthX.release.xcconfig"; sourceTree = ""; }; 68 | 940D15121C49A9E200C88CA6 /* SynthVC+UIHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SynthVC+UIHelpers.swift"; sourceTree = ""; }; 69 | 940D15161C49AC5400C88CA6 /* WaveformSegmentedView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WaveformSegmentedView.swift; sourceTree = ""; }; 70 | 941771111C4C908000855BDA /* CGFloat+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGFloat+Extensions.swift"; sourceTree = ""; }; 71 | 94453BC21C4499BD00608231 /* String+RandomGreeting.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "String+RandomGreeting.swift"; path = "Extensions/String+RandomGreeting.swift"; sourceTree = ""; }; 72 | 948440781F254B850079FB9C /* KnobStyleKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KnobStyleKit.swift; sourceTree = ""; }; 73 | 949B1C2B1C431E5400BFFA10 /* Knob+Touches.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Knob+Touches.swift"; sourceTree = ""; }; 74 | 949B1C2C1C431E5400BFFA10 /* Knob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Knob.swift; sourceTree = ""; }; 75 | 949B1C301C431E5400BFFA10 /* RoundedButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoundedButton.swift; sourceTree = ""; }; 76 | 949B1C341C431E5400BFFA10 /* WaveformSegmentedView+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "WaveformSegmentedView+Extensions.swift"; path = "../Extensions/WaveformSegmentedView+Extensions.swift"; sourceTree = ""; }; 77 | 949B1C361C431E5400BFFA10 /* SMAlphaImageSegment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMAlphaImageSegment.swift; sourceTree = ""; }; 78 | 949B1C371C431E5400BFFA10 /* SMBasicSegment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMBasicSegment.swift; sourceTree = ""; }; 79 | 949B1C381C431E5400BFFA10 /* SMBasicSegmentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMBasicSegmentView.swift; sourceTree = ""; }; 80 | 949B1C391C431E5400BFFA10 /* SMSegment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMSegment.swift; sourceTree = ""; }; 81 | 949B1C3A1C431E5400BFFA10 /* SMSegmentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMSegmentView.swift; sourceTree = ""; }; 82 | 949B1C3B1C431E5400BFFA10 /* SynthViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynthViewController.swift; sourceTree = ""; }; 83 | 94B009E61C4B61BD000CF18E /* SynthVC+NoteNames.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SynthVC+NoteNames.swift"; sourceTree = ""; }; 84 | 94FBB47D1C4483AE00E14C86 /* Double+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Double+Extensions.swift"; sourceTree = ""; }; 85 | 94FBB4811C44868000E14C86 /* VerticalSlider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VerticalSlider.swift; sourceTree = ""; }; 86 | AF75A6912F14504847F31345 /* Pods-AnalogSynthX.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AnalogSynthX.debug.xcconfig"; path = "Pods/Target Support Files/Pods-AnalogSynthX/Pods-AnalogSynthX.debug.xcconfig"; sourceTree = ""; }; 87 | B75886810A4646AB1B3DCF3E /* Pods_AnalogSynthX.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AnalogSynthX.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 88 | C42FFBF61C3DDAAC00823BD4 /* AnalogSynthX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AnalogSynthX.app; sourceTree = BUILT_PRODUCTS_DIR; }; 89 | C42FFBF91C3DDAAC00823BD4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 90 | C42FFBFE1C3DDAAC00823BD4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 91 | C42FFC001C3DDAAC00823BD4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 92 | C42FFC051C3DDAAC00823BD4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 93 | C44760641DCD64A800628666 /* Audiobus.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Audiobus.txt; path = AnalogSynthX/Audiobus.txt; sourceTree = SOURCE_ROOT; }; 94 | C44760661DCD65EC00628666 /* AnalogSynthX.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = AnalogSynthX.entitlements; sourceTree = ""; }; 95 | C44760671DCD65ED00628666 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; 96 | C447606A1DCD675400628666 /* AnalogSynthX-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "AnalogSynthX-Bridging-Header.h"; sourceTree = ""; }; 97 | C472C969202305060038D986 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 98 | C49D69791D1F2CB000BF018A /* GeneratorBank.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GeneratorBank.swift; path = AudioSystem/GeneratorBank.swift; sourceTree = ""; }; 99 | C4CC1FD5209429A9006C5342 /* Audiobus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Audiobus.swift; sourceTree = ""; }; 100 | C4E8ED211C43AA8E0041965F /* Conductor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Conductor.swift; path = AudioSystem/Conductor.swift; sourceTree = ""; }; 101 | C4E8ED281C43ADA10041965F /* FilterSection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FilterSection.swift; path = AudioSystem/FilterSection.swift; sourceTree = ""; }; 102 | C4E8ED2A1C43B04A0041965F /* MultiDelay.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MultiDelay.swift; path = AudioSystem/MultiDelay.swift; sourceTree = ""; }; 103 | C4E8ED2C1C43B2540041965F /* Fatten.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Fatten.swift; path = AudioSystem/Fatten.swift; sourceTree = ""; }; 104 | EA10E15D1F4F982D003F0CA9 /* AudioKitUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioKitUI.framework; path = "../../../../Frameworks/AudioKit-iOS/AudioKitUI.framework"; sourceTree = ""; }; 105 | EAF0A5B61C4F943E00F37994 /* AudioKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioKit.framework; path = "../../../../Frameworks/AudioKit-iOS/AudioKit.framework"; sourceTree = ""; }; 106 | /* End PBXFileReference section */ 107 | 108 | /* Begin PBXFrameworksBuildPhase section */ 109 | C42FFBF31C3DDAAC00823BD4 /* Frameworks */ = { 110 | isa = PBXFrameworksBuildPhase; 111 | buildActionMask = 2147483647; 112 | files = ( 113 | EAF0A5B71C4F943E00F37994 /* AudioKit.framework in Frameworks */, 114 | EA10E15F1F4F9833003F0CA9 /* AudioKitUI.framework in Frameworks */, 115 | C44760681DCD65ED00628666 /* AudioToolbox.framework in Frameworks */, 116 | 7A1A9549E1538EC24A8D9831 /* Pods_AnalogSynthX.framework in Frameworks */, 117 | ); 118 | runOnlyForDeploymentPostprocessing = 0; 119 | }; 120 | /* End PBXFrameworksBuildPhase section */ 121 | 122 | /* Begin PBXGroup section */ 123 | 857372549B43C46D7EB6DAE7 /* Pods */ = { 124 | isa = PBXGroup; 125 | children = ( 126 | AF75A6912F14504847F31345 /* Pods-AnalogSynthX.debug.xcconfig */, 127 | 894A16D4E1FB8A3B4DDBEDAF /* Pods-AnalogSynthX.release.xcconfig */, 128 | ); 129 | name = Pods; 130 | sourceTree = ""; 131 | }; 132 | 949B1C1D1C431E5400BFFA10 /* CustomControls */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | 94B798961C4AA7E70020727B /* Buttons */, 136 | 94B798931C4AA6F90020727B /* Knobs */, 137 | 94B798951C4AA73D0020727B /* Segments */, 138 | 94B798941C4AA72F0020727B /* Sliders */, 139 | ); 140 | path = CustomControls; 141 | sourceTree = ""; 142 | }; 143 | 949B1C321C431E5400BFFA10 /* Extensions */ = { 144 | isa = PBXGroup; 145 | children = ( 146 | 941771111C4C908000855BDA /* CGFloat+Extensions.swift */, 147 | 94FBB47D1C4483AE00E14C86 /* Double+Extensions.swift */, 148 | ); 149 | path = Extensions; 150 | sourceTree = ""; 151 | }; 152 | 949B1C351C431E5400BFFA10 /* SMSegmentView */ = { 153 | isa = PBXGroup; 154 | children = ( 155 | 949B1C361C431E5400BFFA10 /* SMAlphaImageSegment.swift */, 156 | 949B1C371C431E5400BFFA10 /* SMBasicSegment.swift */, 157 | 949B1C381C431E5400BFFA10 /* SMBasicSegmentView.swift */, 158 | 949B1C391C431E5400BFFA10 /* SMSegment.swift */, 159 | 949B1C3A1C431E5400BFFA10 /* SMSegmentView.swift */, 160 | ); 161 | path = SMSegmentView; 162 | sourceTree = ""; 163 | }; 164 | 949B1C571C431E5B00BFFA10 /* ViewControllers */ = { 165 | isa = PBXGroup; 166 | children = ( 167 | 949B1C3B1C431E5400BFFA10 /* SynthViewController.swift */, 168 | 94B009E81C4B61EB000CF18E /* Helpers */, 169 | ); 170 | name = ViewControllers; 171 | sourceTree = ""; 172 | }; 173 | 94B009E81C4B61EB000CF18E /* Helpers */ = { 174 | isa = PBXGroup; 175 | children = ( 176 | 94B009E61C4B61BD000CF18E /* SynthVC+NoteNames.swift */, 177 | 940D15121C49A9E200C88CA6 /* SynthVC+UIHelpers.swift */, 178 | 94453BC21C4499BD00608231 /* String+RandomGreeting.swift */, 179 | ); 180 | name = Helpers; 181 | sourceTree = ""; 182 | }; 183 | 94B798911C4AA6B30020727B /* AudioProcessors */ = { 184 | isa = PBXGroup; 185 | children = ( 186 | C4E8ED2C1C43B2540041965F /* Fatten.swift */, 187 | C4E8ED281C43ADA10041965F /* FilterSection.swift */, 188 | C4E8ED2A1C43B04A0041965F /* MultiDelay.swift */, 189 | ); 190 | name = AudioProcessors; 191 | sourceTree = ""; 192 | }; 193 | 94B798931C4AA6F90020727B /* Knobs */ = { 194 | isa = PBXGroup; 195 | children = ( 196 | 948440781F254B850079FB9C /* KnobStyleKit.swift */, 197 | 949B1C2C1C431E5400BFFA10 /* Knob.swift */, 198 | 949B1C2B1C431E5400BFFA10 /* Knob+Touches.swift */, 199 | ); 200 | name = Knobs; 201 | sourceTree = ""; 202 | }; 203 | 94B798941C4AA72F0020727B /* Sliders */ = { 204 | isa = PBXGroup; 205 | children = ( 206 | 94FBB4811C44868000E14C86 /* VerticalSlider.swift */, 207 | ); 208 | name = Sliders; 209 | sourceTree = ""; 210 | }; 211 | 94B798951C4AA73D0020727B /* Segments */ = { 212 | isa = PBXGroup; 213 | children = ( 214 | 940D15161C49AC5400C88CA6 /* WaveformSegmentedView.swift */, 215 | 949B1C341C431E5400BFFA10 /* WaveformSegmentedView+Extensions.swift */, 216 | ); 217 | name = Segments; 218 | sourceTree = ""; 219 | }; 220 | 94B798961C4AA7E70020727B /* Buttons */ = { 221 | isa = PBXGroup; 222 | children = ( 223 | 949B1C301C431E5400BFFA10 /* RoundedButton.swift */, 224 | ); 225 | name = Buttons; 226 | sourceTree = ""; 227 | }; 228 | 94F234F01C43FC0200072159 /* Libraries */ = { 229 | isa = PBXGroup; 230 | children = ( 231 | 949B1C351C431E5400BFFA10 /* SMSegmentView */, 232 | ); 233 | name = Libraries; 234 | sourceTree = ""; 235 | }; 236 | 94FBB4851C44886000E14C86 /* Supporting Files */ = { 237 | isa = PBXGroup; 238 | children = ( 239 | C42FFBF91C3DDAAC00823BD4 /* AppDelegate.swift */, 240 | C42FFC051C3DDAAC00823BD4 /* Info.plist */, 241 | 949B1C321C431E5400BFFA10 /* Extensions */, 242 | C447606A1DCD675400628666 /* AnalogSynthX-Bridging-Header.h */, 243 | ); 244 | name = "Supporting Files"; 245 | sourceTree = ""; 246 | }; 247 | C42FFBED1C3DDAAC00823BD4 = { 248 | isa = PBXGroup; 249 | children = ( 250 | C472C969202305060038D986 /* README.md */, 251 | C42FFBF81C3DDAAC00823BD4 /* AnalogSynthX */, 252 | EA127F471C42097600289567 /* Frameworks */, 253 | C42FFBF71C3DDAAC00823BD4 /* Products */, 254 | 857372549B43C46D7EB6DAE7 /* Pods */, 255 | ); 256 | sourceTree = ""; 257 | }; 258 | C42FFBF71C3DDAAC00823BD4 /* Products */ = { 259 | isa = PBXGroup; 260 | children = ( 261 | C42FFBF61C3DDAAC00823BD4 /* AnalogSynthX.app */, 262 | ); 263 | name = Products; 264 | sourceTree = ""; 265 | }; 266 | C42FFBF81C3DDAAC00823BD4 /* AnalogSynthX */ = { 267 | isa = PBXGroup; 268 | children = ( 269 | C44760661DCD65EC00628666 /* AnalogSynthX.entitlements */, 270 | C44760641DCD64A800628666 /* Audiobus.txt */, 271 | C4CC1FD5209429A9006C5342 /* Audiobus.swift */, 272 | C4E8ED251C43AD650041965F /* AudioSystem */, 273 | 94B798911C4AA6B30020727B /* AudioProcessors */, 274 | 949B1C1D1C431E5400BFFA10 /* CustomControls */, 275 | 949B1C571C431E5B00BFFA10 /* ViewControllers */, 276 | C42FFC001C3DDAAC00823BD4 /* Assets.xcassets */, 277 | C42FFBFD1C3DDAAC00823BD4 /* Main.storyboard */, 278 | 94FBB4851C44886000E14C86 /* Supporting Files */, 279 | 94F234F01C43FC0200072159 /* Libraries */, 280 | ); 281 | path = AnalogSynthX; 282 | sourceTree = ""; 283 | }; 284 | C4E8ED251C43AD650041965F /* AudioSystem */ = { 285 | isa = PBXGroup; 286 | children = ( 287 | C4E8ED211C43AA8E0041965F /* Conductor.swift */, 288 | C49D69791D1F2CB000BF018A /* GeneratorBank.swift */, 289 | ); 290 | name = AudioSystem; 291 | sourceTree = ""; 292 | }; 293 | EA127F471C42097600289567 /* Frameworks */ = { 294 | isa = PBXGroup; 295 | children = ( 296 | EA10E15D1F4F982D003F0CA9 /* AudioKitUI.framework */, 297 | C44760671DCD65ED00628666 /* AudioToolbox.framework */, 298 | EAF0A5B61C4F943E00F37994 /* AudioKit.framework */, 299 | B75886810A4646AB1B3DCF3E /* Pods_AnalogSynthX.framework */, 300 | ); 301 | name = Frameworks; 302 | path = AnalogSynthX; 303 | sourceTree = ""; 304 | }; 305 | /* End PBXGroup section */ 306 | 307 | /* Begin PBXNativeTarget section */ 308 | C42FFBF51C3DDAAC00823BD4 /* AnalogSynthX */ = { 309 | isa = PBXNativeTarget; 310 | buildConfigurationList = C42FFC081C3DDAAC00823BD4 /* Build configuration list for PBXNativeTarget "AnalogSynthX" */; 311 | buildPhases = ( 312 | 78596E510FCCA3E53AC80F15 /* [CP] Check Pods Manifest.lock */, 313 | C42FFBF21C3DDAAC00823BD4 /* Sources */, 314 | C42FFBF31C3DDAAC00823BD4 /* Frameworks */, 315 | C42FFBF41C3DDAAC00823BD4 /* Resources */, 316 | EA127F461C42094300289567 /* Embed Frameworks */, 317 | C4E8ED011C4357040041965F /* CopyFiles */, 318 | ); 319 | buildRules = ( 320 | ); 321 | dependencies = ( 322 | ); 323 | name = AnalogSynthX; 324 | productName = AnalogSynthX; 325 | productReference = C42FFBF61C3DDAAC00823BD4 /* AnalogSynthX.app */; 326 | productType = "com.apple.product-type.application"; 327 | }; 328 | /* End PBXNativeTarget section */ 329 | 330 | /* Begin PBXProject section */ 331 | C42FFBEE1C3DDAAC00823BD4 /* Project object */ = { 332 | isa = PBXProject; 333 | attributes = { 334 | LastSwiftUpdateCheck = 0720; 335 | LastUpgradeCheck = 0930; 336 | ORGANIZATIONNAME = AudioKit; 337 | TargetAttributes = { 338 | C42FFBF51C3DDAAC00823BD4 = { 339 | CreatedOnToolsVersion = 7.2; 340 | DevelopmentTeam = W22K9JG3J6; 341 | LastSwiftMigration = 0900; 342 | SystemCapabilities = { 343 | com.apple.BackgroundModes = { 344 | enabled = 1; 345 | }; 346 | com.apple.InterAppAudio = { 347 | enabled = 1; 348 | }; 349 | }; 350 | }; 351 | }; 352 | }; 353 | buildConfigurationList = C42FFBF11C3DDAAC00823BD4 /* Build configuration list for PBXProject "AnalogSynthX" */; 354 | compatibilityVersion = "Xcode 3.2"; 355 | developmentRegion = English; 356 | hasScannedForEncodings = 0; 357 | knownRegions = ( 358 | en, 359 | Base, 360 | ); 361 | mainGroup = C42FFBED1C3DDAAC00823BD4; 362 | productRefGroup = C42FFBF71C3DDAAC00823BD4 /* Products */; 363 | projectDirPath = ""; 364 | projectRoot = ""; 365 | targets = ( 366 | C42FFBF51C3DDAAC00823BD4 /* AnalogSynthX */, 367 | ); 368 | }; 369 | /* End PBXProject section */ 370 | 371 | /* Begin PBXResourcesBuildPhase section */ 372 | C42FFBF41C3DDAAC00823BD4 /* Resources */ = { 373 | isa = PBXResourcesBuildPhase; 374 | buildActionMask = 2147483647; 375 | files = ( 376 | C42FFC011C3DDAAC00823BD4 /* Assets.xcassets in Resources */, 377 | C42FFBFF1C3DDAAC00823BD4 /* Main.storyboard in Resources */, 378 | C44760651DCD64A800628666 /* Audiobus.txt in Resources */, 379 | ); 380 | runOnlyForDeploymentPostprocessing = 0; 381 | }; 382 | /* End PBXResourcesBuildPhase section */ 383 | 384 | /* Begin PBXShellScriptBuildPhase section */ 385 | 78596E510FCCA3E53AC80F15 /* [CP] Check Pods Manifest.lock */ = { 386 | isa = PBXShellScriptBuildPhase; 387 | buildActionMask = 2147483647; 388 | files = ( 389 | ); 390 | inputPaths = ( 391 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 392 | "${PODS_ROOT}/Manifest.lock", 393 | ); 394 | name = "[CP] Check Pods Manifest.lock"; 395 | outputPaths = ( 396 | "$(DERIVED_FILE_DIR)/Pods-AnalogSynthX-checkManifestLockResult.txt", 397 | ); 398 | runOnlyForDeploymentPostprocessing = 0; 399 | shellPath = /bin/sh; 400 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 401 | showEnvVarsInLog = 0; 402 | }; 403 | /* End PBXShellScriptBuildPhase section */ 404 | 405 | /* Begin PBXSourcesBuildPhase section */ 406 | C42FFBF21C3DDAAC00823BD4 /* Sources */ = { 407 | isa = PBXSourcesBuildPhase; 408 | buildActionMask = 2147483647; 409 | files = ( 410 | C4E8ED2B1C43B04A0041965F /* MultiDelay.swift in Sources */, 411 | C49D697A1D1F2CB000BF018A /* GeneratorBank.swift in Sources */, 412 | 949B1C531C431E5400BFFA10 /* SMBasicSegmentView.swift in Sources */, 413 | C4E8ED291C43ADA10041965F /* FilterSection.swift in Sources */, 414 | 949B1C521C431E5400BFFA10 /* SMBasicSegment.swift in Sources */, 415 | 949B1C481C431E5400BFFA10 /* Knob+Touches.swift in Sources */, 416 | 949B1C4D1C431E5400BFFA10 /* RoundedButton.swift in Sources */, 417 | 94453BC31C4499BD00608231 /* String+RandomGreeting.swift in Sources */, 418 | C42FFBFA1C3DDAAC00823BD4 /* AppDelegate.swift in Sources */, 419 | 949B1C501C431E5400BFFA10 /* WaveformSegmentedView+Extensions.swift in Sources */, 420 | C4CC1FD6209429A9006C5342 /* Audiobus.swift in Sources */, 421 | 949B1C511C431E5400BFFA10 /* SMAlphaImageSegment.swift in Sources */, 422 | 949B1C491C431E5400BFFA10 /* Knob.swift in Sources */, 423 | 941771121C4C908000855BDA /* CGFloat+Extensions.swift in Sources */, 424 | 949B1C551C431E5400BFFA10 /* SMSegmentView.swift in Sources */, 425 | 940D15131C49A9E200C88CA6 /* SynthVC+UIHelpers.swift in Sources */, 426 | 948440791F254B850079FB9C /* KnobStyleKit.swift in Sources */, 427 | 940D15171C49AC5400C88CA6 /* WaveformSegmentedView.swift in Sources */, 428 | C4E8ED221C43AA8E0041965F /* Conductor.swift in Sources */, 429 | C4E8ED2D1C43B2540041965F /* Fatten.swift in Sources */, 430 | 949B1C561C431E5400BFFA10 /* SynthViewController.swift in Sources */, 431 | 949B1C541C431E5400BFFA10 /* SMSegment.swift in Sources */, 432 | 94FBB4821C44868000E14C86 /* VerticalSlider.swift in Sources */, 433 | 94FBB47E1C4483AE00E14C86 /* Double+Extensions.swift in Sources */, 434 | 94B009E71C4B61BD000CF18E /* SynthVC+NoteNames.swift in Sources */, 435 | ); 436 | runOnlyForDeploymentPostprocessing = 0; 437 | }; 438 | /* End PBXSourcesBuildPhase section */ 439 | 440 | /* Begin PBXVariantGroup section */ 441 | C42FFBFD1C3DDAAC00823BD4 /* Main.storyboard */ = { 442 | isa = PBXVariantGroup; 443 | children = ( 444 | C42FFBFE1C3DDAAC00823BD4 /* Base */, 445 | ); 446 | name = Main.storyboard; 447 | sourceTree = ""; 448 | }; 449 | /* End PBXVariantGroup section */ 450 | 451 | /* Begin XCBuildConfiguration section */ 452 | C42FFC061C3DDAAC00823BD4 /* Debug */ = { 453 | isa = XCBuildConfiguration; 454 | buildSettings = { 455 | ALWAYS_SEARCH_USER_PATHS = NO; 456 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 457 | CLANG_CXX_LIBRARY = "libc++"; 458 | CLANG_ENABLE_MODULES = YES; 459 | CLANG_ENABLE_OBJC_ARC = YES; 460 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 461 | CLANG_WARN_BOOL_CONVERSION = YES; 462 | CLANG_WARN_COMMA = YES; 463 | CLANG_WARN_CONSTANT_CONVERSION = YES; 464 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 465 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 466 | CLANG_WARN_EMPTY_BODY = YES; 467 | CLANG_WARN_ENUM_CONVERSION = YES; 468 | CLANG_WARN_INFINITE_RECURSION = YES; 469 | CLANG_WARN_INT_CONVERSION = YES; 470 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 471 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 472 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 473 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 474 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 475 | CLANG_WARN_STRICT_PROTOTYPES = YES; 476 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 477 | CLANG_WARN_UNREACHABLE_CODE = YES; 478 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 479 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 480 | COPY_PHASE_STRIP = NO; 481 | DEBUG_INFORMATION_FORMAT = dwarf; 482 | ENABLE_STRICT_OBJC_MSGSEND = YES; 483 | ENABLE_TESTABILITY = YES; 484 | FRAMEWORK_SEARCH_PATHS = ""; 485 | GCC_C_LANGUAGE_STANDARD = gnu99; 486 | GCC_DYNAMIC_NO_PIC = NO; 487 | GCC_NO_COMMON_BLOCKS = YES; 488 | GCC_OPTIMIZATION_LEVEL = 3; 489 | GCC_PREPROCESSOR_DEFINITIONS = ( 490 | "DEBUG=1", 491 | "$(inherited)", 492 | ); 493 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 494 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 495 | GCC_WARN_UNDECLARED_SELECTOR = YES; 496 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 497 | GCC_WARN_UNUSED_FUNCTION = YES; 498 | GCC_WARN_UNUSED_VARIABLE = YES; 499 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 500 | MTL_ENABLE_DEBUG_INFO = YES; 501 | ONLY_ACTIVE_ARCH = YES; 502 | SDKROOT = iphoneos; 503 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 504 | TARGETED_DEVICE_FAMILY = "1,2"; 505 | VALID_ARCHS = "$(ARCHS_STANDARD)"; 506 | }; 507 | name = Debug; 508 | }; 509 | C42FFC071C3DDAAC00823BD4 /* Release */ = { 510 | isa = XCBuildConfiguration; 511 | buildSettings = { 512 | ALWAYS_SEARCH_USER_PATHS = NO; 513 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 514 | CLANG_CXX_LIBRARY = "libc++"; 515 | CLANG_ENABLE_MODULES = YES; 516 | CLANG_ENABLE_OBJC_ARC = YES; 517 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 518 | CLANG_WARN_BOOL_CONVERSION = YES; 519 | CLANG_WARN_COMMA = YES; 520 | CLANG_WARN_CONSTANT_CONVERSION = YES; 521 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 522 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 523 | CLANG_WARN_EMPTY_BODY = YES; 524 | CLANG_WARN_ENUM_CONVERSION = YES; 525 | CLANG_WARN_INFINITE_RECURSION = YES; 526 | CLANG_WARN_INT_CONVERSION = YES; 527 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 528 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 529 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 530 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 531 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 532 | CLANG_WARN_STRICT_PROTOTYPES = YES; 533 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 534 | CLANG_WARN_UNREACHABLE_CODE = YES; 535 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 536 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 537 | COPY_PHASE_STRIP = NO; 538 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 539 | ENABLE_NS_ASSERTIONS = NO; 540 | ENABLE_STRICT_OBJC_MSGSEND = YES; 541 | FRAMEWORK_SEARCH_PATHS = ""; 542 | GCC_C_LANGUAGE_STANDARD = gnu99; 543 | GCC_NO_COMMON_BLOCKS = YES; 544 | GCC_OPTIMIZATION_LEVEL = 3; 545 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 546 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 547 | GCC_WARN_UNDECLARED_SELECTOR = YES; 548 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 549 | GCC_WARN_UNUSED_FUNCTION = YES; 550 | GCC_WARN_UNUSED_VARIABLE = YES; 551 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 552 | MTL_ENABLE_DEBUG_INFO = NO; 553 | SDKROOT = iphoneos; 554 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 555 | TARGETED_DEVICE_FAMILY = "1,2"; 556 | VALIDATE_PRODUCT = YES; 557 | VALID_ARCHS = "$(ARCHS_STANDARD)"; 558 | }; 559 | name = Release; 560 | }; 561 | C42FFC091C3DDAAC00823BD4 /* Debug */ = { 562 | isa = XCBuildConfiguration; 563 | baseConfigurationReference = AF75A6912F14504847F31345 /* Pods-AnalogSynthX.debug.xcconfig */; 564 | buildSettings = { 565 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 566 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = "Brand Assets"; 567 | CLANG_ENABLE_MODULES = YES; 568 | CODE_SIGN_ENTITLEMENTS = AnalogSynthX/AnalogSynthX.entitlements; 569 | CODE_SIGN_IDENTITY = "iPhone Developer"; 570 | DEVELOPMENT_TEAM = W22K9JG3J6; 571 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 572 | INFOPLIST_FILE = AnalogSynthX/Info.plist; 573 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 574 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 575 | OTHER_LDFLAGS = ( 576 | "$(inherited)", 577 | "-lstdc++", 578 | ); 579 | PRODUCT_BUNDLE_IDENTIFIER = io.audiokit.AudioKitSynth; 580 | PRODUCT_NAME = AnalogSynthX; 581 | SWIFT_OBJC_BRIDGING_HEADER = "AnalogSynthX/AnalogSynthX-Bridging-Header.h"; 582 | SWIFT_VERSION = 4.0; 583 | TARGETED_DEVICE_FAMILY = 2; 584 | VALID_ARCHS = "$(ARCHS_STANDARD)"; 585 | }; 586 | name = Debug; 587 | }; 588 | C42FFC0A1C3DDAAC00823BD4 /* Release */ = { 589 | isa = XCBuildConfiguration; 590 | baseConfigurationReference = 894A16D4E1FB8A3B4DDBEDAF /* Pods-AnalogSynthX.release.xcconfig */; 591 | buildSettings = { 592 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 593 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = "Brand Assets"; 594 | CLANG_ENABLE_MODULES = YES; 595 | CODE_SIGN_ENTITLEMENTS = AnalogSynthX/AnalogSynthX.entitlements; 596 | CODE_SIGN_IDENTITY = "iPhone Developer"; 597 | DEVELOPMENT_TEAM = W22K9JG3J6; 598 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 599 | INFOPLIST_FILE = AnalogSynthX/Info.plist; 600 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 601 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 602 | OTHER_LDFLAGS = ( 603 | "$(inherited)", 604 | "-lstdc++", 605 | ); 606 | PRODUCT_BUNDLE_IDENTIFIER = io.audiokit.AudioKitSynth; 607 | PRODUCT_NAME = AnalogSynthX; 608 | SWIFT_OBJC_BRIDGING_HEADER = "AnalogSynthX/AnalogSynthX-Bridging-Header.h"; 609 | SWIFT_VERSION = 4.0; 610 | TARGETED_DEVICE_FAMILY = 2; 611 | VALID_ARCHS = "$(ARCHS_STANDARD)"; 612 | }; 613 | name = Release; 614 | }; 615 | /* End XCBuildConfiguration section */ 616 | 617 | /* Begin XCConfigurationList section */ 618 | C42FFBF11C3DDAAC00823BD4 /* Build configuration list for PBXProject "AnalogSynthX" */ = { 619 | isa = XCConfigurationList; 620 | buildConfigurations = ( 621 | C42FFC061C3DDAAC00823BD4 /* Debug */, 622 | C42FFC071C3DDAAC00823BD4 /* Release */, 623 | ); 624 | defaultConfigurationIsVisible = 0; 625 | defaultConfigurationName = Release; 626 | }; 627 | C42FFC081C3DDAAC00823BD4 /* Build configuration list for PBXNativeTarget "AnalogSynthX" */ = { 628 | isa = XCConfigurationList; 629 | buildConfigurations = ( 630 | C42FFC091C3DDAAC00823BD4 /* Debug */, 631 | C42FFC0A1C3DDAAC00823BD4 /* Release */, 632 | ); 633 | defaultConfigurationIsVisible = 0; 634 | defaultConfigurationName = Release; 635 | }; 636 | /* End XCConfigurationList section */ 637 | }; 638 | rootObject = C42FFBEE1C3DDAAC00823BD4 /* Project object */; 639 | } 640 | --------------------------------------------------------------------------------