├── 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 | [](https://travis-ci.org/AudioKit/AnalogSynthX)
4 | [](https://github.com/AudioKit/AnalogSynthX/blob/master/LICENSE)
5 | [](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 |
--------------------------------------------------------------------------------