├── .gitignore ├── README.md ├── audio ├── buildozer.spec ├── main.kv ├── main.py └── tools.py ├── graphs ├── buildozer.spec ├── main.kv └── main.py └── multicore ├── buildozer.spec ├── main.kv └── main.py /.gitignore: -------------------------------------------------------------------------------- 1 | **/__pycache__ 2 | **/build 3 | **/.buildozer/ 4 | **/dist 5 | **/.vscode 6 | **/.idea 7 | **/bin 8 | **/keystores 9 | **/test.spec -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kivy App Tutorial 2 | 3 | This repository is a collection of example projects to learn how to use different components of kivy. These projects are able to run on Android. 4 | 5 | > What can you find in these projects? 6 | 7 | - Graphs 8 | - Plot Graphs with the Widget Kivy Garden Graph 9 | - Configured Buildozer.spec file to create .apk or .aab 10 | - Audio 11 | - Realtime Audio Processing with Library Audiostream 12 | - Configured Buildozer.spec file to create .apk 13 | - Simultaniously play and change frequency (threading) 14 | - Multicore (Work in Progress) 15 | - Rendering of graphs is done on multiple cores 16 | - Use of the library multiprocessing 17 | 18 | 19 | -------------------------------------------------------------------------------- /audio/buildozer.spec: -------------------------------------------------------------------------------- 1 | [app] 2 | 3 | # (str) Title of your application 4 | title = KivyExample 5 | 6 | # (str) Package name 7 | package.name = kivy_example 8 | 9 | # (str) Package domain (needed for android/ios packaging) 10 | package.domain = org.kivy_example 11 | 12 | # (str) Source code where the main.py live 13 | source.dir = . 14 | 15 | # (list) Source files to include (let empty to include all the files) 16 | source.include_exts = py,png,jpg,kv,atlas 17 | 18 | # (list) List of inclusions using pattern matching 19 | #source.include_patterns = assets/*,images/*.png 20 | 21 | # (list) Source files to exclude (let empty to not exclude anything) 22 | #source.exclude_exts = spec 23 | 24 | # (list) List of directory to exclude (let empty to not exclude anything) 25 | #source.exclude_dirs = tests, bin, venv 26 | 27 | # (list) List of exclusions using pattern matching 28 | # Do not prefix with './' 29 | #source.exclude_patterns = license,images/*/*.jpg 30 | 31 | # (str) Application versioning (method 1) 32 | version = 0.1 33 | 34 | # (str) Application versioning (method 2) 35 | # version.regex = __version__ = ['"](.*)['"] 36 | # version.filename = %(source.dir)s/main.py 37 | 38 | # (list) Application requirements 39 | # comma separated e.g. requirements = sqlite3,kivy 40 | requirements = python3,kivy==2.0.0rc4,kivy_garden.graph,numpy,audiostream 41 | 42 | # (str) Custom source folders for requirements 43 | # Sets custom source for any requirements with recipes 44 | # requirements.source.kivy = ../../kivy 45 | 46 | # (str) Presplash of the application 47 | #presplash.filename = %(source.dir)s/data/presplash.png 48 | 49 | # (str) Icon of the application 50 | #icon.filename = %(source.dir)s/data/icon.png 51 | 52 | # (str) Supported orientation (one of landscape, sensorLandscape, portrait or all) 53 | orientation = portrait 54 | 55 | # (list) List of service to declare 56 | #services = NAME:ENTRYPOINT_TO_PY,NAME2:ENTRYPOINT2_TO_PY 57 | 58 | # 59 | # OSX Specific 60 | # 61 | 62 | # 63 | # author = © Copyright Info 64 | 65 | # change the major version of python used by the app 66 | osx.python_version = 3 67 | 68 | # Kivy version to use 69 | osx.kivy_version = 2.0.0 70 | 71 | # 72 | # Android specific 73 | # 74 | 75 | # (bool) Indicate if the application should be fullscreen or not 76 | fullscreen = 0 77 | 78 | # (string) Presplash background color (for android toolchain) 79 | # Supported formats are: #RRGGBB #AARRGGBB or one of the following names: 80 | # red, blue, green, black, white, gray, cyan, magenta, yellow, lightgray, 81 | # darkgray, grey, lightgrey, darkgrey, aqua, fuchsia, lime, maroon, navy, 82 | # olive, purple, silver, teal. 83 | #android.presplash_color = #FFFFFF 84 | 85 | # (string) Presplash animation using Lottie format. 86 | # see https://lottiefiles.com/ for examples and https://airbnb.design/lottie/ 87 | # for general documentation. 88 | # Lottie files can be created using various tools, like Adobe After Effect or Synfig. 89 | #android.presplash_lottie = "path/to/lottie/file.json" 90 | 91 | # (str) Adaptive icon of the application (used if Android API level is 26+ at runtime) 92 | #icon.adaptive_foreground.filename = %(source.dir)s/data/icon_fg.png 93 | #icon.adaptive_background.filename = %(source.dir)s/data/icon_bg.png 94 | 95 | # (list) Permissions 96 | #android.permissions = INTERNET 97 | 98 | # (list) features (adds uses-feature -tags to manifest) 99 | #android.features = android.hardware.usb.host 100 | 101 | # (int) Target Android API, should be as high as possible. 102 | android.api = 30 103 | 104 | # (int) Minimum API your APK / AAB will support. 105 | #android.minapi = 21 106 | 107 | # (int) Android SDK version to use 108 | #android.sdk = 20 109 | 110 | # (str) Android NDK version to use 111 | #android.ndk = 19b 112 | 113 | # (int) Android NDK API to use. This is the minimum API your app will support, it should usually match android.minapi. 114 | #android.ndk_api = 21 115 | 116 | # (bool) Use --private data storage (True) or --dir public storage (False) 117 | #android.private_storage = True 118 | 119 | # (str) Android NDK directory (if empty, it will be automatically downloaded.) 120 | #android.ndk_path = 121 | 122 | # (str) Android SDK directory (if empty, it will be automatically downloaded.) 123 | #android.sdk_path = 124 | 125 | # (str) ANT directory (if empty, it will be automatically downloaded.) 126 | #android.ant_path = 127 | 128 | # (bool) If True, then skip trying to update the Android sdk 129 | # This can be useful to avoid excess Internet downloads or save time 130 | # when an update is due and you just want to test/build your package 131 | # android.skip_update = False 132 | 133 | # (bool) If True, then automatically accept SDK license 134 | # agreements. This is intended for automation only. If set to False, 135 | # the default, you will be shown the license when first running 136 | # buildozer. 137 | # android.accept_sdk_license = False 138 | 139 | # (str) Android entry point, default is ok for Kivy-based app 140 | #android.entrypoint = org.kivy.android.PythonActivity 141 | 142 | # (str) Full name including package path of the Java class that implements Android Activity 143 | # use that parameter together with android.entrypoint to set custom Java class instead of PythonActivity 144 | #android.activity_class_name = org.kivy.android.PythonActivity 145 | 146 | # (str) Extra xml to write directly inside the element of AndroidManifest.xml 147 | # use that parameter to provide a filename from where to load your custom XML code 148 | #android.extra_manifest_xml = ./src/android/extra_manifest.xml 149 | 150 | # (str) Extra xml to write directly inside the tag of AndroidManifest.xml 151 | # use that parameter to provide a filename from where to load your custom XML arguments: 152 | #android.extra_manifest_application_arguments = ./src/android/extra_manifest_application_arguments.xml 153 | 154 | # (str) Full name including package path of the Java class that implements Python Service 155 | # use that parameter to set custom Java class instead of PythonService 156 | #android.service_class_name = org.kivy.android.PythonService 157 | 158 | # (str) Android app theme, default is ok for Kivy-based app 159 | # android.apptheme = "@android:style/Theme.NoTitleBar" 160 | 161 | # (list) Pattern to whitelist for the whole project 162 | #android.whitelist = 163 | 164 | # (str) Path to a custom whitelist file 165 | #android.whitelist_src = 166 | 167 | # (str) Path to a custom blacklist file 168 | #android.blacklist_src = 169 | 170 | # (list) List of Java .jar files to add to the libs so that pyjnius can access 171 | # their classes. Don't add jars that you do not need, since extra jars can slow 172 | # down the build process. Allows wildcards matching, for example: 173 | # OUYA-ODK/libs/*.jar 174 | #android.add_jars = foo.jar,bar.jar,path/to/more/*.jar 175 | 176 | # (list) List of Java files to add to the android project (can be java or a 177 | # directory containing the files) 178 | #android.add_src = 179 | 180 | # (list) Android AAR archives to add 181 | #android.add_aars = 182 | 183 | # (list) Put these files or directories in the apk assets directory. 184 | # Either form may be used, and assets need not be in 'source.include_exts'. 185 | # 1) android.add_assets = source_asset_relative_path 186 | # 2) android.add_assets = source_asset_path:destination_asset_relative_path 187 | #android.add_assets = 188 | 189 | # (list) Gradle dependencies to add 190 | #android.gradle_dependencies = 191 | 192 | # (bool) Enable AndroidX support. Enable when 'android.gradle_dependencies' 193 | # contains an 'androidx' package, or any package from Kotlin source. 194 | # android.enable_androidx requires android.api >= 28 195 | #android.enable_androidx = False 196 | 197 | # (list) add java compile options 198 | # this can for example be necessary when importing certain java libraries using the 'android.gradle_dependencies' option 199 | # see https://developer.android.com/studio/write/java8-support for further information 200 | # android.add_compile_options = "sourceCompatibility = 1.8", "targetCompatibility = 1.8" 201 | 202 | # (list) Gradle repositories to add {can be necessary for some android.gradle_dependencies} 203 | # please enclose in double quotes 204 | # e.g. android.gradle_repositories = "maven { url 'https://kotlin.bintray.com/ktor' }" 205 | #android.add_gradle_repositories = 206 | 207 | # (list) packaging options to add 208 | # see https://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.PackagingOptions.html 209 | # can be necessary to solve conflicts in gradle_dependencies 210 | # please enclose in double quotes 211 | # e.g. android.add_packaging_options = "exclude 'META-INF/common.kotlin_module'", "exclude 'META-INF/*.kotlin_module'" 212 | #android.add_packaging_options = 213 | 214 | # (list) Java classes to add as activities to the manifest. 215 | #android.add_activities = com.example.ExampleActivity 216 | 217 | # (str) OUYA Console category. Should be one of GAME or APP 218 | # If you leave this blank, OUYA support will not be enabled 219 | #android.ouya.category = GAME 220 | 221 | # (str) Filename of OUYA Console icon. It must be a 732x412 png image. 222 | #android.ouya.icon.filename = %(source.dir)s/data/ouya_icon.png 223 | 224 | # (str) XML file to include as an intent filters in tag 225 | #android.manifest.intent_filters = 226 | 227 | # (str) launchMode to set for the main activity 228 | #android.manifest.launch_mode = standard 229 | 230 | # (list) Android additional libraries to copy into libs/armeabi 231 | #android.add_libs_armeabi = libs/android/*.so 232 | #android.add_libs_armeabi_v7a = libs/android-v7/*.so 233 | #android.add_libs_arm64_v8a = libs/android-v8/*.so 234 | #android.add_libs_x86 = libs/android-x86/*.so 235 | #android.add_libs_mips = libs/android-mips/*.so 236 | 237 | # (bool) Indicate whether the screen should stay on 238 | # Don't forget to add the WAKE_LOCK permission if you set this to True 239 | #android.wakelock = False 240 | 241 | # (list) Android application meta-data to set (key=value format) 242 | #android.meta_data = 243 | 244 | # (list) Android library project to add (will be added in the 245 | # project.properties automatically.) 246 | #android.library_references = 247 | 248 | # (list) Android shared libraries which will be added to AndroidManifest.xml using tag 249 | #android.uses_library = 250 | 251 | # (str) Android logcat filters to use 252 | #android.logcat_filters = *:S python:D 253 | 254 | # (bool) Android logcat only display log for activity's pid 255 | #android.logcat_pid_only = False 256 | 257 | # (str) Android additional adb arguments 258 | #android.adb_args = -H host.docker.internal 259 | 260 | # (bool) Copy library instead of making a libpymodules.so 261 | #android.copy_libs = 1 262 | 263 | # (list) The Android archs to build for, choices: armeabi-v7a, arm64-v8a, x86, x86_64 264 | # In past, was `android.arch` as we weren't supporting builds for multiple archs at the same time. 265 | android.archs = arm64-v8a, armeabi-v7a 266 | 267 | # (int) overrides automatic versionCode computation (used in build.gradle) 268 | # this is not the same as app version and should only be edited if you know what you're doing 269 | # android.numeric_version = 1 270 | 271 | # (bool) enables Android auto backup feature (Android API >=23) 272 | android.allow_backup = True 273 | 274 | # (str) XML file for custom backup rules (see official auto backup documentation) 275 | # android.backup_rules = 276 | 277 | # (str) If you need to insert variables into your AndroidManifest.xml file, 278 | # you can do so with the manifestPlaceholders property. 279 | # This property takes a map of key-value pairs. (via a string) 280 | # Usage example : android.manifest_placeholders = [myCustomUrl:\"org.kivy.customurl\"] 281 | # android.manifest_placeholders = [:] 282 | 283 | # (bool) disables the compilation of py to pyc/pyo files when packaging 284 | # android.no-compile-pyo = True 285 | 286 | # (str) The format used to package the app for release mode (aab or apk). 287 | android.release_artifact = aab 288 | 289 | # 290 | # Python for android (p4a) specific 291 | # 292 | 293 | # (str) python-for-android URL to use for checkout 294 | #p4a.url = 295 | 296 | # (str) python-for-android fork to use in case if p4a.url is not specified, defaults to upstream (kivy) 297 | #p4a.fork = kivy 298 | 299 | # (str) python-for-android branch to use, defaults to master 300 | #p4a.branch = master 301 | p4a.branch = develop 302 | 303 | # (str) python-for-android specific commit to use, defaults to HEAD, must be within p4a.branch 304 | #p4a.commit = HEAD 305 | 306 | # (str) python-for-android git clone directory (if empty, it will be automatically cloned from github) 307 | #p4a.source_dir = 308 | 309 | # (str) The directory in which python-for-android should look for your own build recipes (if any) 310 | #p4a.local_recipes = 311 | 312 | # (str) Filename to the hook for p4a 313 | #p4a.hook = 314 | 315 | # (str) Bootstrap to use for android builds 316 | # p4a.bootstrap = sdl2 317 | 318 | # (int) port number to specify an explicit --port= p4a argument (eg for bootstrap flask) 319 | #p4a.port = 320 | 321 | # Control passing the --use-setup-py vs --ignore-setup-py to p4a 322 | # "in the future" --use-setup-py is going to be the default behaviour in p4a, right now it is not 323 | # Setting this to false will pass --ignore-setup-py, true will pass --use-setup-py 324 | # NOTE: this is general setuptools integration, having pyproject.toml is enough, no need to generate 325 | # setup.py if you're using Poetry, but you need to add "toml" to source.include_exts. 326 | #p4a.setup_py = false 327 | 328 | # (str) extra command line arguments to pass when invoking pythonforandroid.toolchain 329 | #p4a.extra_args = 330 | 331 | 332 | # 333 | # iOS specific 334 | # 335 | 336 | # (str) Path to a custom kivy-ios folder 337 | #ios.kivy_ios_dir = ../kivy-ios 338 | # Alternately, specify the URL and branch of a git checkout: 339 | ios.kivy_ios_url = https://github.com/kivy/kivy-ios 340 | ios.kivy_ios_branch = master 341 | 342 | # Another platform dependency: ios-deploy 343 | # Uncomment to use a custom checkout 344 | #ios.ios_deploy_dir = ../ios_deploy 345 | # Or specify URL and branch 346 | ios.ios_deploy_url = https://github.com/phonegap/ios-deploy 347 | ios.ios_deploy_branch = 1.10.0 348 | 349 | # (bool) Whether or not to sign the code 350 | ios.codesign.allowed = false 351 | 352 | # (str) Name of the certificate to use for signing the debug version 353 | # Get a list of available identities: buildozer ios list_identities 354 | #ios.codesign.debug = "iPhone Developer: ()" 355 | 356 | # (str) The development team to use for signing the debug version 357 | #ios.codesign.development_team.debug = 358 | 359 | # (str) Name of the certificate to use for signing the release version 360 | #ios.codesign.release = %(ios.codesign.debug)s 361 | 362 | # (str) The development team to use for signing the release version 363 | #ios.codesign.development_team.release = 364 | 365 | # (str) URL pointing to .ipa file to be installed 366 | # This option should be defined along with `display_image_url` and `full_size_image_url` options. 367 | #ios.manifest.app_url = 368 | 369 | # (str) URL pointing to an icon (57x57px) to be displayed during download 370 | # This option should be defined along with `app_url` and `full_size_image_url` options. 371 | #ios.manifest.display_image_url = 372 | 373 | # (str) URL pointing to a large icon (512x512px) to be used by iTunes 374 | # This option should be defined along with `app_url` and `display_image_url` options. 375 | #ios.manifest.full_size_image_url = 376 | 377 | 378 | [buildozer] 379 | 380 | # (int) Log level (0 = error only, 1 = info, 2 = debug (with command output)) 381 | log_level = 2 382 | 383 | # (int) Display warning if buildozer is run as root (0 = False, 1 = True) 384 | warn_on_root = 1 385 | 386 | # (str) Path to build artifact storage, absolute or relative to spec file 387 | # build_dir = ./.buildozer 388 | 389 | # (str) Path to build output (i.e. .apk, .aab, .ipa) storage 390 | # bin_dir = ./bin 391 | 392 | # ----------------------------------------------------------------------------- 393 | # List as sections 394 | # 395 | # You can define all the "list" as [section:key]. 396 | # Each line will be considered as a option to the list. 397 | # Let's take [app] / source.exclude_patterns. 398 | # Instead of doing: 399 | # 400 | #[app] 401 | #source.exclude_patterns = license,data/audio/*.wav,data/images/original/* 402 | # 403 | # This can be translated into: 404 | # 405 | #[app:source.exclude_patterns] 406 | #license 407 | #data/audio/*.wav 408 | #data/images/original/* 409 | # 410 | 411 | 412 | # ----------------------------------------------------------------------------- 413 | # Profiles 414 | # 415 | # You can extend section / key with a profile 416 | # For example, you want to deploy a demo version of your application without 417 | # HD content. You could first change the title to add "(demo)" in the name 418 | # and extend the excluded directories to remove the HD content. 419 | # 420 | #[app@demo] 421 | #title = My Application (demo) 422 | # 423 | #[app:source.exclude_patterns@demo] 424 | #images/hd/* 425 | # 426 | # Then, invoke the command line with the "demo" profile: 427 | # 428 | #buildozer --profile demo android debug 429 | -------------------------------------------------------------------------------- /audio/main.kv: -------------------------------------------------------------------------------- 1 | #:import utils kivy.utils 2 | 3 | : 4 | canvas.before: 5 | Color: 6 | rgb: utils.get_color_from_hex('#212946') 7 | Rectangle: 8 | pos: self.pos 9 | size: self.size 10 | 11 | BoxLayout: 12 | size_hint: 1, 1 13 | orientation: 'vertical' 14 | padding: 10, 10, 0, 10 15 | 16 | ScrollView: 17 | id: view 18 | do_scroll_x: True 19 | do_scroll_y: False 20 | orientation: 'vertical' 21 | size_hint: 1, 0.5 22 | valign: 'middle' 23 | bar_width: 4 24 | bar_color: 1, 1, 1, 1 25 | bar_inactive_color: 1, 1, 1, 0.5 26 | scroll_type: ['content'] 27 | 28 | BoxLayout: 29 | orientation: 'vertical' 30 | size_hint: None, 1 31 | width: view.width*root.zoom 32 | BoxLayout: 33 | id: modulation 34 | size_hint_x: 1 35 | size_hint_y: 1 36 | 37 | BoxLayout: 38 | id: zoom 39 | orientation: 'horizontal' 40 | size_hint: 1, 0.1 41 | padding: 10 42 | 43 | Button: 44 | text: '-' 45 | size_hint_x: None 46 | width: self.height 47 | on_release: root.update_zoom(self.text) 48 | 49 | Label: 50 | text: str(int(root.zoom)) + 'x' 51 | 52 | Button: 53 | text: '+' 54 | size_hint_x: None 55 | width: self.height 56 | on_release: root.update_zoom(self.text) 57 | 58 | BoxLayout: 59 | size_hint: 1, 0.1 60 | orientation: 'vertical' 61 | 62 | Label: 63 | text: 'Frequency: ' + str(freq.value) + ' hz' 64 | 65 | Slider: 66 | id: freq 67 | min: 1 68 | max: 200 69 | step: 1 70 | on_release: 71 | on_value: 72 | root.update_plot(freq.value) 73 | root.player.set_freq(freq.value) 74 | 75 | BoxLayout: 76 | size_hint: 1, 0.3 77 | padding: 0, 20, 10, 0 78 | 79 | ToggleButton: 80 | id: play 81 | text: '[b]PLAY[b]' 82 | on_release: root.play_result() 83 | markup: True -------------------------------------------------------------------------------- /audio/main.py: -------------------------------------------------------------------------------- 1 | import threading 2 | from kivy.app import App 3 | from kivy.properties import NumericProperty 4 | from kivy.uix.boxlayout import BoxLayout 5 | from kivy_garden.graph import Graph, LinePlot 6 | import numpy as np 7 | 8 | from tools import AudioPlayer 9 | 10 | 11 | class MainApp(App): 12 | 13 | def build(self): 14 | self.app = MainGrid() 15 | return self.app 16 | 17 | def init_thread(self): 18 | self.playback_thread = threading.Thread(target=self.app.player.run) 19 | # daemon threads don't wait for main thread 20 | self.playback_thread.setDaemon(True) 21 | self.playback_thread.start() 22 | print("Playback Thread", self.playback_thread.native_id, "started") 23 | print("Main Thread", threading.main_thread().native_id) 24 | 25 | def exit_thread(self): 26 | self.playback_thread.join() 27 | print("Playback Thread", self.playback_thread.native_id, "stopped") 28 | 29 | class MainGrid(BoxLayout): 30 | 31 | zoom = NumericProperty(1) 32 | 33 | def __init__(self, **kwargs): 34 | super().__init__(**kwargs) 35 | self.samples = 512 36 | self.zoom = 1 37 | self.graph = Graph(y_ticks_major=0.5, 38 | x_ticks_major=64, 39 | border_color=[0, 1, 1, 1], 40 | tick_color=[0, 1, 1, 0.7], 41 | x_grid=True, y_grid=True, 42 | xmin=0, xmax=self.samples, 43 | ymin=-1.0, ymax=1.0, 44 | draw_border=False, 45 | x_grid_label=True, y_grid_label=False) 46 | # Mono, Sampling Rate, Chunksize 47 | self.player = AudioPlayer(1, 44100, self.samples) 48 | self.ids.modulation.add_widget(self.graph) 49 | self.plot_x = np.linspace(0, 1, self.samples) 50 | self.plot_y = np.zeros(self.samples) 51 | self.plot = LinePlot(color=[1, 1, 0, 1], line_width=1.5) 52 | self.old_freq = 0 53 | self.freq = 0 54 | # adds plot to the graph widget 55 | self.graph.add_plot(self.plot) 56 | self.update_plot(1) 57 | 58 | def update_plot(self, freq): 59 | self.plot_y = np.sin(2*np.pi*freq*self.plot_x) 60 | # draws plot 61 | self.plot.points = [(x, self.plot_y[x]) for x in range(self.samples)] 62 | 63 | def update_zoom(self, value): 64 | if value == '+' and self.zoom < 8: 65 | self.zoom *= 2 66 | self.graph.x_ticks_major /= 2 67 | elif value == '-' and self.zoom > 1: 68 | self.zoom /= 2 69 | self.graph.x_ticks_major *= 2 70 | 71 | def play_result(self): 72 | if self.ids.play.state == 'down': 73 | self.ids.play.text = '[b]STOP[/b]' 74 | App.get_running_app().init_thread() 75 | else: 76 | self.ids.play.text = '[b]PLAY[/b]' 77 | self.player.stop() 78 | App.get_running_app().exit_thread() 79 | 80 | 81 | MainApp().run() 82 | -------------------------------------------------------------------------------- /audio/tools.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from audiostream import get_output, AudioSample 3 | 4 | 5 | class AudioPlayer: 6 | def __init__(self, channels, rate, chunk_size): 7 | super().__init__() 8 | self.rate = rate 9 | self.chunk_size = chunk_size 10 | # initialize the engine and get an output device; can be initialized only once 11 | self.stream = get_output( 12 | channels=channels, rate=rate, buffersize=chunk_size, encoding=16) 13 | # create instance of AudioSample to handle the audio stream (output) e.g. play and stop 14 | self.sample = AudioSample() 15 | self.chunk = np.zeros(chunk_size) 16 | # indicator 17 | self.pos = 0 18 | self.playing = False 19 | self.freq = 20 20 | self.old_freq = self.freq 21 | 22 | def set_freq(self, freq): 23 | self.old_freq = self.freq 24 | self.freq = freq 25 | 26 | def render_audio(self, pos, freq): 27 | start = pos 28 | end = pos + self.chunk_size 29 | x_audio = np.arange(start, end) / self.rate 30 | return np.sin(2*np.pi*freq*x_audio) 31 | 32 | def fade_out(self, signal, length): 33 | amp_decrease = np.linspace(1, 0, length) 34 | signal[-length:] *= amp_decrease 35 | return signal 36 | 37 | @staticmethod 38 | def get_bytes(chunk): 39 | # chunk is scaled and converted from float32 to int16 bytes 40 | return (chunk * 32767).astype('int16').tobytes() 41 | 42 | def write_audio_data(self): 43 | self.chunk = self.get_bytes(self.chunk) 44 | # write bytes of chunk to internal ring buffer 45 | self.sample.write(self.chunk) 46 | 47 | def run(self): 48 | self.stream.add_sample(self.sample) 49 | self.sample.play() 50 | self.playing = True 51 | self.pos = 0 52 | self.freq_change = False 53 | 54 | while self.playing: 55 | self.chunk = self.render_audio(self.pos, self.old_freq) 56 | self.pos += self.chunk_size 57 | 58 | if self.freq != self.old_freq: 59 | self.chunk = self.fade_out(self.chunk, 256) 60 | self.pos = 0 61 | self.old_freq = self.freq 62 | 63 | self.write_audio_data() 64 | 65 | # self.chunk = self.fade_out( 66 | # self.render_audio(self.pos, self.old_freq), 256) 67 | # self.write_audio_data() 68 | # important for threading otherwise a new thread cannot be initialized 69 | self.sample.stop() 70 | 71 | def stop(self): 72 | self.playing = False 73 | -------------------------------------------------------------------------------- /graphs/buildozer.spec: -------------------------------------------------------------------------------- 1 | [app] 2 | 3 | # (str) Title of your application 4 | title = KivyExample 5 | 6 | # (str) Package name 7 | package.name = kivy_example 8 | 9 | # (str) Package domain (needed for android/ios packaging) 10 | package.domain = org.kivy_example 11 | 12 | # (str) Source code where the main.py live 13 | source.dir = . 14 | 15 | # (list) Source files to include (let empty to include all the files) 16 | source.include_exts = py,png,jpg,kv,atlas 17 | 18 | # (list) List of inclusions using pattern matching 19 | #source.include_patterns = assets/*,images/*.png 20 | 21 | # (list) Source files to exclude (let empty to not exclude anything) 22 | #source.exclude_exts = spec 23 | 24 | # (list) List of directory to exclude (let empty to not exclude anything) 25 | #source.exclude_dirs = tests, bin, venv 26 | 27 | # (list) List of exclusions using pattern matching 28 | # Do not prefix with './' 29 | #source.exclude_patterns = license,images/*/*.jpg 30 | 31 | # (str) Application versioning (method 1) 32 | version = 0.1 33 | 34 | # (str) Application versioning (method 2) 35 | # version.regex = __version__ = ['"](.*)['"] 36 | # version.filename = %(source.dir)s/main.py 37 | 38 | # (list) Application requirements 39 | # comma separated e.g. requirements = sqlite3,kivy 40 | requirements = python3,kivy==2.0.0rc4,kivy_garden.graph,numpy 41 | 42 | # (str) Custom source folders for requirements 43 | # Sets custom source for any requirements with recipes 44 | # requirements.source.kivy = ../../kivy 45 | 46 | # (str) Presplash of the application 47 | #presplash.filename = %(source.dir)s/data/presplash.png 48 | 49 | # (str) Icon of the application 50 | #icon.filename = %(source.dir)s/data/icon.png 51 | 52 | # (str) Supported orientation (one of landscape, sensorLandscape, portrait or all) 53 | orientation = portrait 54 | 55 | # (list) List of service to declare 56 | #services = NAME:ENTRYPOINT_TO_PY,NAME2:ENTRYPOINT2_TO_PY 57 | 58 | # 59 | # OSX Specific 60 | # 61 | 62 | # 63 | # author = © Copyright Info 64 | 65 | # change the major version of python used by the app 66 | osx.python_version = 3 67 | 68 | # Kivy version to use 69 | osx.kivy_version = 2.0.0 70 | 71 | # 72 | # Android specific 73 | # 74 | 75 | # (bool) Indicate if the application should be fullscreen or not 76 | fullscreen = 0 77 | 78 | # (string) Presplash background color (for android toolchain) 79 | # Supported formats are: #RRGGBB #AARRGGBB or one of the following names: 80 | # red, blue, green, black, white, gray, cyan, magenta, yellow, lightgray, 81 | # darkgray, grey, lightgrey, darkgrey, aqua, fuchsia, lime, maroon, navy, 82 | # olive, purple, silver, teal. 83 | #android.presplash_color = #FFFFFF 84 | 85 | # (string) Presplash animation using Lottie format. 86 | # see https://lottiefiles.com/ for examples and https://airbnb.design/lottie/ 87 | # for general documentation. 88 | # Lottie files can be created using various tools, like Adobe After Effect or Synfig. 89 | #android.presplash_lottie = "path/to/lottie/file.json" 90 | 91 | # (str) Adaptive icon of the application (used if Android API level is 26+ at runtime) 92 | #icon.adaptive_foreground.filename = %(source.dir)s/data/icon_fg.png 93 | #icon.adaptive_background.filename = %(source.dir)s/data/icon_bg.png 94 | 95 | # (list) Permissions 96 | #android.permissions = INTERNET 97 | 98 | # (list) features (adds uses-feature -tags to manifest) 99 | #android.features = android.hardware.usb.host 100 | 101 | # (int) Target Android API, should be as high as possible. 102 | android.api = 30 103 | 104 | # (int) Minimum API your APK / AAB will support. 105 | #android.minapi = 21 106 | 107 | # (int) Android SDK version to use 108 | #android.sdk = 20 109 | 110 | # (str) Android NDK version to use 111 | #android.ndk = 19b 112 | 113 | # (int) Android NDK API to use. This is the minimum API your app will support, it should usually match android.minapi. 114 | #android.ndk_api = 21 115 | 116 | # (bool) Use --private data storage (True) or --dir public storage (False) 117 | #android.private_storage = True 118 | 119 | # (str) Android NDK directory (if empty, it will be automatically downloaded.) 120 | #android.ndk_path = 121 | 122 | # (str) Android SDK directory (if empty, it will be automatically downloaded.) 123 | #android.sdk_path = 124 | 125 | # (str) ANT directory (if empty, it will be automatically downloaded.) 126 | #android.ant_path = 127 | 128 | # (bool) If True, then skip trying to update the Android sdk 129 | # This can be useful to avoid excess Internet downloads or save time 130 | # when an update is due and you just want to test/build your package 131 | # android.skip_update = False 132 | 133 | # (bool) If True, then automatically accept SDK license 134 | # agreements. This is intended for automation only. If set to False, 135 | # the default, you will be shown the license when first running 136 | # buildozer. 137 | # android.accept_sdk_license = False 138 | 139 | # (str) Android entry point, default is ok for Kivy-based app 140 | #android.entrypoint = org.kivy.android.PythonActivity 141 | 142 | # (str) Full name including package path of the Java class that implements Android Activity 143 | # use that parameter together with android.entrypoint to set custom Java class instead of PythonActivity 144 | #android.activity_class_name = org.kivy.android.PythonActivity 145 | 146 | # (str) Extra xml to write directly inside the element of AndroidManifest.xml 147 | # use that parameter to provide a filename from where to load your custom XML code 148 | #android.extra_manifest_xml = ./src/android/extra_manifest.xml 149 | 150 | # (str) Extra xml to write directly inside the tag of AndroidManifest.xml 151 | # use that parameter to provide a filename from where to load your custom XML arguments: 152 | #android.extra_manifest_application_arguments = ./src/android/extra_manifest_application_arguments.xml 153 | 154 | # (str) Full name including package path of the Java class that implements Python Service 155 | # use that parameter to set custom Java class instead of PythonService 156 | #android.service_class_name = org.kivy.android.PythonService 157 | 158 | # (str) Android app theme, default is ok for Kivy-based app 159 | # android.apptheme = "@android:style/Theme.NoTitleBar" 160 | 161 | # (list) Pattern to whitelist for the whole project 162 | #android.whitelist = 163 | 164 | # (str) Path to a custom whitelist file 165 | #android.whitelist_src = 166 | 167 | # (str) Path to a custom blacklist file 168 | #android.blacklist_src = 169 | 170 | # (list) List of Java .jar files to add to the libs so that pyjnius can access 171 | # their classes. Don't add jars that you do not need, since extra jars can slow 172 | # down the build process. Allows wildcards matching, for example: 173 | # OUYA-ODK/libs/*.jar 174 | #android.add_jars = foo.jar,bar.jar,path/to/more/*.jar 175 | 176 | # (list) List of Java files to add to the android project (can be java or a 177 | # directory containing the files) 178 | #android.add_src = 179 | 180 | # (list) Android AAR archives to add 181 | #android.add_aars = 182 | 183 | # (list) Put these files or directories in the apk assets directory. 184 | # Either form may be used, and assets need not be in 'source.include_exts'. 185 | # 1) android.add_assets = source_asset_relative_path 186 | # 2) android.add_assets = source_asset_path:destination_asset_relative_path 187 | #android.add_assets = 188 | 189 | # (list) Gradle dependencies to add 190 | #android.gradle_dependencies = 191 | 192 | # (bool) Enable AndroidX support. Enable when 'android.gradle_dependencies' 193 | # contains an 'androidx' package, or any package from Kotlin source. 194 | # android.enable_androidx requires android.api >= 28 195 | #android.enable_androidx = False 196 | 197 | # (list) add java compile options 198 | # this can for example be necessary when importing certain java libraries using the 'android.gradle_dependencies' option 199 | # see https://developer.android.com/studio/write/java8-support for further information 200 | # android.add_compile_options = "sourceCompatibility = 1.8", "targetCompatibility = 1.8" 201 | 202 | # (list) Gradle repositories to add {can be necessary for some android.gradle_dependencies} 203 | # please enclose in double quotes 204 | # e.g. android.gradle_repositories = "maven { url 'https://kotlin.bintray.com/ktor' }" 205 | #android.add_gradle_repositories = 206 | 207 | # (list) packaging options to add 208 | # see https://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.PackagingOptions.html 209 | # can be necessary to solve conflicts in gradle_dependencies 210 | # please enclose in double quotes 211 | # e.g. android.add_packaging_options = "exclude 'META-INF/common.kotlin_module'", "exclude 'META-INF/*.kotlin_module'" 212 | #android.add_packaging_options = 213 | 214 | # (list) Java classes to add as activities to the manifest. 215 | #android.add_activities = com.example.ExampleActivity 216 | 217 | # (str) OUYA Console category. Should be one of GAME or APP 218 | # If you leave this blank, OUYA support will not be enabled 219 | #android.ouya.category = GAME 220 | 221 | # (str) Filename of OUYA Console icon. It must be a 732x412 png image. 222 | #android.ouya.icon.filename = %(source.dir)s/data/ouya_icon.png 223 | 224 | # (str) XML file to include as an intent filters in tag 225 | #android.manifest.intent_filters = 226 | 227 | # (str) launchMode to set for the main activity 228 | #android.manifest.launch_mode = standard 229 | 230 | # (list) Android additional libraries to copy into libs/armeabi 231 | #android.add_libs_armeabi = libs/android/*.so 232 | #android.add_libs_armeabi_v7a = libs/android-v7/*.so 233 | #android.add_libs_arm64_v8a = libs/android-v8/*.so 234 | #android.add_libs_x86 = libs/android-x86/*.so 235 | #android.add_libs_mips = libs/android-mips/*.so 236 | 237 | # (bool) Indicate whether the screen should stay on 238 | # Don't forget to add the WAKE_LOCK permission if you set this to True 239 | #android.wakelock = False 240 | 241 | # (list) Android application meta-data to set (key=value format) 242 | #android.meta_data = 243 | 244 | # (list) Android library project to add (will be added in the 245 | # project.properties automatically.) 246 | #android.library_references = 247 | 248 | # (list) Android shared libraries which will be added to AndroidManifest.xml using tag 249 | #android.uses_library = 250 | 251 | # (str) Android logcat filters to use 252 | #android.logcat_filters = *:S python:D 253 | 254 | # (bool) Android logcat only display log for activity's pid 255 | #android.logcat_pid_only = False 256 | 257 | # (str) Android additional adb arguments 258 | #android.adb_args = -H host.docker.internal 259 | 260 | # (bool) Copy library instead of making a libpymodules.so 261 | #android.copy_libs = 1 262 | 263 | # (list) The Android archs to build for, choices: armeabi-v7a, arm64-v8a, x86, x86_64 264 | # In past, was `android.arch` as we weren't supporting builds for multiple archs at the same time. 265 | android.archs = arm64-v8a, armeabi-v7a 266 | 267 | # (int) overrides automatic versionCode computation (used in build.gradle) 268 | # this is not the same as app version and should only be edited if you know what you're doing 269 | # android.numeric_version = 1 270 | 271 | # (bool) enables Android auto backup feature (Android API >=23) 272 | android.allow_backup = True 273 | 274 | # (str) XML file for custom backup rules (see official auto backup documentation) 275 | # android.backup_rules = 276 | 277 | # (str) If you need to insert variables into your AndroidManifest.xml file, 278 | # you can do so with the manifestPlaceholders property. 279 | # This property takes a map of key-value pairs. (via a string) 280 | # Usage example : android.manifest_placeholders = [myCustomUrl:\"org.kivy.customurl\"] 281 | # android.manifest_placeholders = [:] 282 | 283 | # (bool) disables the compilation of py to pyc/pyo files when packaging 284 | # android.no-compile-pyo = True 285 | 286 | # (str) The format used to package the app for release mode (aab or apk). 287 | android.release_artifact = aab 288 | 289 | # 290 | # Python for android (p4a) specific 291 | # 292 | 293 | # (str) python-for-android URL to use for checkout 294 | #p4a.url = 295 | 296 | # (str) python-for-android fork to use in case if p4a.url is not specified, defaults to upstream (kivy) 297 | #p4a.fork = kivy 298 | 299 | # (str) python-for-android branch to use, defaults to master 300 | #p4a.branch = master 301 | p4a.branch = develop 302 | 303 | # (str) python-for-android specific commit to use, defaults to HEAD, must be within p4a.branch 304 | #p4a.commit = HEAD 305 | 306 | # (str) python-for-android git clone directory (if empty, it will be automatically cloned from github) 307 | #p4a.source_dir = 308 | 309 | # (str) The directory in which python-for-android should look for your own build recipes (if any) 310 | #p4a.local_recipes = 311 | 312 | # (str) Filename to the hook for p4a 313 | #p4a.hook = 314 | 315 | # (str) Bootstrap to use for android builds 316 | # p4a.bootstrap = sdl2 317 | 318 | # (int) port number to specify an explicit --port= p4a argument (eg for bootstrap flask) 319 | #p4a.port = 320 | 321 | # Control passing the --use-setup-py vs --ignore-setup-py to p4a 322 | # "in the future" --use-setup-py is going to be the default behaviour in p4a, right now it is not 323 | # Setting this to false will pass --ignore-setup-py, true will pass --use-setup-py 324 | # NOTE: this is general setuptools integration, having pyproject.toml is enough, no need to generate 325 | # setup.py if you're using Poetry, but you need to add "toml" to source.include_exts. 326 | #p4a.setup_py = false 327 | 328 | # (str) extra command line arguments to pass when invoking pythonforandroid.toolchain 329 | #p4a.extra_args = 330 | 331 | 332 | # 333 | # iOS specific 334 | # 335 | 336 | # (str) Path to a custom kivy-ios folder 337 | #ios.kivy_ios_dir = ../kivy-ios 338 | # Alternately, specify the URL and branch of a git checkout: 339 | ios.kivy_ios_url = https://github.com/kivy/kivy-ios 340 | ios.kivy_ios_branch = master 341 | 342 | # Another platform dependency: ios-deploy 343 | # Uncomment to use a custom checkout 344 | #ios.ios_deploy_dir = ../ios_deploy 345 | # Or specify URL and branch 346 | ios.ios_deploy_url = https://github.com/phonegap/ios-deploy 347 | ios.ios_deploy_branch = 1.10.0 348 | 349 | # (bool) Whether or not to sign the code 350 | ios.codesign.allowed = false 351 | 352 | # (str) Name of the certificate to use for signing the debug version 353 | # Get a list of available identities: buildozer ios list_identities 354 | #ios.codesign.debug = "iPhone Developer: ()" 355 | 356 | # (str) The development team to use for signing the debug version 357 | #ios.codesign.development_team.debug = 358 | 359 | # (str) Name of the certificate to use for signing the release version 360 | #ios.codesign.release = %(ios.codesign.debug)s 361 | 362 | # (str) The development team to use for signing the release version 363 | #ios.codesign.development_team.release = 364 | 365 | # (str) URL pointing to .ipa file to be installed 366 | # This option should be defined along with `display_image_url` and `full_size_image_url` options. 367 | #ios.manifest.app_url = 368 | 369 | # (str) URL pointing to an icon (57x57px) to be displayed during download 370 | # This option should be defined along with `app_url` and `full_size_image_url` options. 371 | #ios.manifest.display_image_url = 372 | 373 | # (str) URL pointing to a large icon (512x512px) to be used by iTunes 374 | # This option should be defined along with `app_url` and `display_image_url` options. 375 | #ios.manifest.full_size_image_url = 376 | 377 | 378 | [buildozer] 379 | 380 | # (int) Log level (0 = error only, 1 = info, 2 = debug (with command output)) 381 | log_level = 2 382 | 383 | # (int) Display warning if buildozer is run as root (0 = False, 1 = True) 384 | warn_on_root = 1 385 | 386 | # (str) Path to build artifact storage, absolute or relative to spec file 387 | # build_dir = ./.buildozer 388 | 389 | # (str) Path to build output (i.e. .apk, .aab, .ipa) storage 390 | # bin_dir = ./bin 391 | 392 | # ----------------------------------------------------------------------------- 393 | # List as sections 394 | # 395 | # You can define all the "list" as [section:key]. 396 | # Each line will be considered as a option to the list. 397 | # Let's take [app] / source.exclude_patterns. 398 | # Instead of doing: 399 | # 400 | #[app] 401 | #source.exclude_patterns = license,data/audio/*.wav,data/images/original/* 402 | # 403 | # This can be translated into: 404 | # 405 | #[app:source.exclude_patterns] 406 | #license 407 | #data/audio/*.wav 408 | #data/images/original/* 409 | # 410 | 411 | 412 | # ----------------------------------------------------------------------------- 413 | # Profiles 414 | # 415 | # You can extend section / key with a profile 416 | # For example, you want to deploy a demo version of your application without 417 | # HD content. You could first change the title to add "(demo)" in the name 418 | # and extend the excluded directories to remove the HD content. 419 | # 420 | #[app@demo] 421 | #title = My Application (demo) 422 | # 423 | #[app:source.exclude_patterns@demo] 424 | #images/hd/* 425 | # 426 | # Then, invoke the command line with the "demo" profile: 427 | # 428 | #buildozer --profile demo android debug 429 | -------------------------------------------------------------------------------- /graphs/main.kv: -------------------------------------------------------------------------------- 1 | #:import utils kivy.utils 2 | 3 | : 4 | canvas.before: 5 | Color: 6 | rgb: utils.get_color_from_hex('#212946') 7 | Rectangle: 8 | pos: self.pos 9 | size: self.size 10 | 11 | BoxLayout: 12 | size_hint: 1, 1 13 | orientation: 'vertical' 14 | padding: 10, 10, 0, 10 15 | 16 | ScrollView: 17 | id: view 18 | do_scroll_x: True 19 | do_scroll_y: False 20 | orientation: 'vertical' 21 | size_hint: 1, 0.5 22 | valign: 'middle' 23 | bar_width: 4 24 | bar_color: 1, 1, 1, 1 25 | bar_inactive_color: 1, 1, 1, 0.5 26 | scroll_type: ['content'] 27 | 28 | BoxLayout: 29 | orientation: 'vertical' 30 | size_hint: None, 1 31 | width: view.width*root.zoom 32 | BoxLayout: 33 | id: modulation 34 | size_hint_x: 1 35 | size_hint_y: 1 36 | 37 | # without scroll 38 | # BoxLayout: 39 | # size_hint: 1, 1 40 | # orientation: 'vertical' 41 | # padding: 10, 10, 0, 10 42 | # BoxLayout: 43 | # size_hint: 1, 0.5 44 | # id: modulation 45 | 46 | BoxLayout: 47 | id: zoom 48 | orientation: 'horizontal' 49 | size_hint: 1, 0.1 50 | padding: 10 51 | 52 | Button: 53 | text: '-' 54 | size_hint_x: None 55 | width: self.height 56 | on_release: root.update_zoom(self.text) 57 | 58 | Label: 59 | text: str(int(root.zoom)) + 'x' 60 | 61 | Button: 62 | text: '+' 63 | size_hint_x: None 64 | width: self.height 65 | on_release: root.update_zoom(self.text) 66 | 67 | BoxLayout: 68 | size_hint: 1, 0.1 69 | orientation: 'vertical' 70 | 71 | Label: 72 | text: 'Frequency: ' + str(freq.value) + ' hz' 73 | 74 | Slider: 75 | id: freq 76 | min: 1 77 | max: 100 78 | step: 0.5 79 | on_value: root.update_plot(freq.value) 80 | 81 | BoxLayout: 82 | size_hint: 1, 0.3 -------------------------------------------------------------------------------- /graphs/main.py: -------------------------------------------------------------------------------- 1 | import kivy 2 | from kivy.app import App 3 | from kivy.properties import NumericProperty 4 | from kivy.uix.boxlayout import BoxLayout 5 | from kivy_garden.graph import Graph, LinePlot 6 | import numpy as np 7 | 8 | 9 | class MainApp(App): 10 | 11 | def build(self): 12 | return MainGrid() 13 | 14 | 15 | class MainGrid(BoxLayout): 16 | 17 | zoom = NumericProperty(1) 18 | 19 | def __init__(self, **kwargs): 20 | super().__init__(**kwargs) 21 | self.samples = 512 22 | self.zoom = 1 23 | self.graph = Graph(y_ticks_major=0.5, 24 | x_ticks_major=64, 25 | border_color=[0, 1, 1, 1], 26 | tick_color=[0, 1, 1, 0.7], 27 | x_grid=True, y_grid=True, 28 | xmin=0, xmax=self.samples, 29 | ymin=-1.0, ymax=1.0, 30 | draw_border=False, 31 | x_grid_label=True, y_grid_label=False) 32 | 33 | self.ids.modulation.add_widget(self.graph) 34 | self.plot_x = np.linspace(0, 1, self.samples) 35 | self.plot_y = np.zeros(self.samples) 36 | self.plot = LinePlot(color=[1, 1, 0, 1], line_width=1.5) 37 | self.graph.add_plot(self.plot) 38 | self.update_plot(1) 39 | 40 | def update_plot(self, freq): 41 | self.plot_y = np.sin(2*np.pi*freq*self.plot_x) 42 | self.plot.points = [(x, self.plot_y[x]) for x in range(self.samples)] 43 | 44 | def update_zoom(self, value): 45 | if value == '+' and self.zoom < 8: 46 | self.zoom *= 2 47 | self.graph.x_ticks_major /= 2 48 | elif value == '-' and self.zoom > 1: 49 | self.zoom /= 2 50 | self.graph.x_ticks_major *= 2 51 | 52 | 53 | MainApp().run() 54 | -------------------------------------------------------------------------------- /multicore/buildozer.spec: -------------------------------------------------------------------------------- 1 | [app] 2 | 3 | # (str) Title of your application 4 | title = KivyExample 5 | 6 | # (str) Package name 7 | package.name = kivy_example 8 | 9 | # (str) Package domain (needed for android/ios packaging) 10 | package.domain = org.kivy_example 11 | 12 | # (str) Source code where the main.py live 13 | source.dir = . 14 | 15 | # (list) Source files to include (let empty to include all the files) 16 | source.include_exts = py,png,jpg,kv,atlas 17 | 18 | # (list) List of inclusions using pattern matching 19 | #source.include_patterns = assets/*,images/*.png 20 | 21 | # (list) Source files to exclude (let empty to not exclude anything) 22 | #source.exclude_exts = spec 23 | 24 | # (list) List of directory to exclude (let empty to not exclude anything) 25 | #source.exclude_dirs = tests, bin, venv 26 | 27 | # (list) List of exclusions using pattern matching 28 | # Do not prefix with './' 29 | #source.exclude_patterns = license,images/*/*.jpg 30 | 31 | # (str) Application versioning (method 1) 32 | version = 0.1 33 | 34 | # (str) Application versioning (method 2) 35 | # version.regex = __version__ = ['"](.*)['"] 36 | # version.filename = %(source.dir)s/main.py 37 | 38 | # (list) Application requirements 39 | # comma separated e.g. requirements = sqlite3,kivy 40 | requirements = python3,kivy==2.0.0rc4,kivy_garden.graph,numpy,audiostream 41 | 42 | # (str) Custom source folders for requirements 43 | # Sets custom source for any requirements with recipes 44 | # requirements.source.kivy = ../../kivy 45 | 46 | # (str) Presplash of the application 47 | #presplash.filename = %(source.dir)s/data/presplash.png 48 | 49 | # (str) Icon of the application 50 | #icon.filename = %(source.dir)s/data/icon.png 51 | 52 | # (str) Supported orientation (one of landscape, sensorLandscape, portrait or all) 53 | orientation = portrait 54 | 55 | # (list) List of service to declare 56 | #services = NAME:ENTRYPOINT_TO_PY,NAME2:ENTRYPOINT2_TO_PY 57 | 58 | # 59 | # OSX Specific 60 | # 61 | 62 | # 63 | # author = © Copyright Info 64 | 65 | # change the major version of python used by the app 66 | osx.python_version = 3 67 | 68 | # Kivy version to use 69 | osx.kivy_version = 2.0.0 70 | 71 | # 72 | # Android specific 73 | # 74 | 75 | # (bool) Indicate if the application should be fullscreen or not 76 | fullscreen = 0 77 | 78 | # (string) Presplash background color (for android toolchain) 79 | # Supported formats are: #RRGGBB #AARRGGBB or one of the following names: 80 | # red, blue, green, black, white, gray, cyan, magenta, yellow, lightgray, 81 | # darkgray, grey, lightgrey, darkgrey, aqua, fuchsia, lime, maroon, navy, 82 | # olive, purple, silver, teal. 83 | #android.presplash_color = #FFFFFF 84 | 85 | # (string) Presplash animation using Lottie format. 86 | # see https://lottiefiles.com/ for examples and https://airbnb.design/lottie/ 87 | # for general documentation. 88 | # Lottie files can be created using various tools, like Adobe After Effect or Synfig. 89 | #android.presplash_lottie = "path/to/lottie/file.json" 90 | 91 | # (str) Adaptive icon of the application (used if Android API level is 26+ at runtime) 92 | #icon.adaptive_foreground.filename = %(source.dir)s/data/icon_fg.png 93 | #icon.adaptive_background.filename = %(source.dir)s/data/icon_bg.png 94 | 95 | # (list) Permissions 96 | #android.permissions = INTERNET 97 | 98 | # (list) features (adds uses-feature -tags to manifest) 99 | #android.features = android.hardware.usb.host 100 | 101 | # (int) Target Android API, should be as high as possible. 102 | android.api = 30 103 | 104 | # (int) Minimum API your APK / AAB will support. 105 | #android.minapi = 21 106 | 107 | # (int) Android SDK version to use 108 | #android.sdk = 20 109 | 110 | # (str) Android NDK version to use 111 | #android.ndk = 19b 112 | 113 | # (int) Android NDK API to use. This is the minimum API your app will support, it should usually match android.minapi. 114 | #android.ndk_api = 21 115 | 116 | # (bool) Use --private data storage (True) or --dir public storage (False) 117 | #android.private_storage = True 118 | 119 | # (str) Android NDK directory (if empty, it will be automatically downloaded.) 120 | #android.ndk_path = 121 | 122 | # (str) Android SDK directory (if empty, it will be automatically downloaded.) 123 | #android.sdk_path = 124 | 125 | # (str) ANT directory (if empty, it will be automatically downloaded.) 126 | #android.ant_path = 127 | 128 | # (bool) If True, then skip trying to update the Android sdk 129 | # This can be useful to avoid excess Internet downloads or save time 130 | # when an update is due and you just want to test/build your package 131 | # android.skip_update = False 132 | 133 | # (bool) If True, then automatically accept SDK license 134 | # agreements. This is intended for automation only. If set to False, 135 | # the default, you will be shown the license when first running 136 | # buildozer. 137 | # android.accept_sdk_license = False 138 | 139 | # (str) Android entry point, default is ok for Kivy-based app 140 | #android.entrypoint = org.kivy.android.PythonActivity 141 | 142 | # (str) Full name including package path of the Java class that implements Android Activity 143 | # use that parameter together with android.entrypoint to set custom Java class instead of PythonActivity 144 | #android.activity_class_name = org.kivy.android.PythonActivity 145 | 146 | # (str) Extra xml to write directly inside the element of AndroidManifest.xml 147 | # use that parameter to provide a filename from where to load your custom XML code 148 | #android.extra_manifest_xml = ./src/android/extra_manifest.xml 149 | 150 | # (str) Extra xml to write directly inside the tag of AndroidManifest.xml 151 | # use that parameter to provide a filename from where to load your custom XML arguments: 152 | #android.extra_manifest_application_arguments = ./src/android/extra_manifest_application_arguments.xml 153 | 154 | # (str) Full name including package path of the Java class that implements Python Service 155 | # use that parameter to set custom Java class instead of PythonService 156 | #android.service_class_name = org.kivy.android.PythonService 157 | 158 | # (str) Android app theme, default is ok for Kivy-based app 159 | # android.apptheme = "@android:style/Theme.NoTitleBar" 160 | 161 | # (list) Pattern to whitelist for the whole project 162 | #android.whitelist = 163 | 164 | # (str) Path to a custom whitelist file 165 | #android.whitelist_src = 166 | 167 | # (str) Path to a custom blacklist file 168 | #android.blacklist_src = 169 | 170 | # (list) List of Java .jar files to add to the libs so that pyjnius can access 171 | # their classes. Don't add jars that you do not need, since extra jars can slow 172 | # down the build process. Allows wildcards matching, for example: 173 | # OUYA-ODK/libs/*.jar 174 | #android.add_jars = foo.jar,bar.jar,path/to/more/*.jar 175 | 176 | # (list) List of Java files to add to the android project (can be java or a 177 | # directory containing the files) 178 | #android.add_src = 179 | 180 | # (list) Android AAR archives to add 181 | #android.add_aars = 182 | 183 | # (list) Put these files or directories in the apk assets directory. 184 | # Either form may be used, and assets need not be in 'source.include_exts'. 185 | # 1) android.add_assets = source_asset_relative_path 186 | # 2) android.add_assets = source_asset_path:destination_asset_relative_path 187 | #android.add_assets = 188 | 189 | # (list) Gradle dependencies to add 190 | #android.gradle_dependencies = 191 | 192 | # (bool) Enable AndroidX support. Enable when 'android.gradle_dependencies' 193 | # contains an 'androidx' package, or any package from Kotlin source. 194 | # android.enable_androidx requires android.api >= 28 195 | #android.enable_androidx = False 196 | 197 | # (list) add java compile options 198 | # this can for example be necessary when importing certain java libraries using the 'android.gradle_dependencies' option 199 | # see https://developer.android.com/studio/write/java8-support for further information 200 | # android.add_compile_options = "sourceCompatibility = 1.8", "targetCompatibility = 1.8" 201 | 202 | # (list) Gradle repositories to add {can be necessary for some android.gradle_dependencies} 203 | # please enclose in double quotes 204 | # e.g. android.gradle_repositories = "maven { url 'https://kotlin.bintray.com/ktor' }" 205 | #android.add_gradle_repositories = 206 | 207 | # (list) packaging options to add 208 | # see https://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.PackagingOptions.html 209 | # can be necessary to solve conflicts in gradle_dependencies 210 | # please enclose in double quotes 211 | # e.g. android.add_packaging_options = "exclude 'META-INF/common.kotlin_module'", "exclude 'META-INF/*.kotlin_module'" 212 | #android.add_packaging_options = 213 | 214 | # (list) Java classes to add as activities to the manifest. 215 | #android.add_activities = com.example.ExampleActivity 216 | 217 | # (str) OUYA Console category. Should be one of GAME or APP 218 | # If you leave this blank, OUYA support will not be enabled 219 | #android.ouya.category = GAME 220 | 221 | # (str) Filename of OUYA Console icon. It must be a 732x412 png image. 222 | #android.ouya.icon.filename = %(source.dir)s/data/ouya_icon.png 223 | 224 | # (str) XML file to include as an intent filters in tag 225 | #android.manifest.intent_filters = 226 | 227 | # (str) launchMode to set for the main activity 228 | #android.manifest.launch_mode = standard 229 | 230 | # (list) Android additional libraries to copy into libs/armeabi 231 | #android.add_libs_armeabi = libs/android/*.so 232 | #android.add_libs_armeabi_v7a = libs/android-v7/*.so 233 | #android.add_libs_arm64_v8a = libs/android-v8/*.so 234 | #android.add_libs_x86 = libs/android-x86/*.so 235 | #android.add_libs_mips = libs/android-mips/*.so 236 | 237 | # (bool) Indicate whether the screen should stay on 238 | # Don't forget to add the WAKE_LOCK permission if you set this to True 239 | #android.wakelock = False 240 | 241 | # (list) Android application meta-data to set (key=value format) 242 | #android.meta_data = 243 | 244 | # (list) Android library project to add (will be added in the 245 | # project.properties automatically.) 246 | #android.library_references = 247 | 248 | # (list) Android shared libraries which will be added to AndroidManifest.xml using tag 249 | #android.uses_library = 250 | 251 | # (str) Android logcat filters to use 252 | #android.logcat_filters = *:S python:D 253 | 254 | # (bool) Android logcat only display log for activity's pid 255 | #android.logcat_pid_only = False 256 | 257 | # (str) Android additional adb arguments 258 | #android.adb_args = -H host.docker.internal 259 | 260 | # (bool) Copy library instead of making a libpymodules.so 261 | #android.copy_libs = 1 262 | 263 | # (list) The Android archs to build for, choices: armeabi-v7a, arm64-v8a, x86, x86_64 264 | # In past, was `android.arch` as we weren't supporting builds for multiple archs at the same time. 265 | android.archs = arm64-v8a, armeabi-v7a 266 | 267 | # (int) overrides automatic versionCode computation (used in build.gradle) 268 | # this is not the same as app version and should only be edited if you know what you're doing 269 | # android.numeric_version = 1 270 | 271 | # (bool) enables Android auto backup feature (Android API >=23) 272 | android.allow_backup = True 273 | 274 | # (str) XML file for custom backup rules (see official auto backup documentation) 275 | # android.backup_rules = 276 | 277 | # (str) If you need to insert variables into your AndroidManifest.xml file, 278 | # you can do so with the manifestPlaceholders property. 279 | # This property takes a map of key-value pairs. (via a string) 280 | # Usage example : android.manifest_placeholders = [myCustomUrl:\"org.kivy.customurl\"] 281 | # android.manifest_placeholders = [:] 282 | 283 | # (bool) disables the compilation of py to pyc/pyo files when packaging 284 | # android.no-compile-pyo = True 285 | 286 | # (str) The format used to package the app for release mode (aab or apk). 287 | android.release_artifact = aab 288 | 289 | # 290 | # Python for android (p4a) specific 291 | # 292 | 293 | # (str) python-for-android URL to use for checkout 294 | #p4a.url = 295 | 296 | # (str) python-for-android fork to use in case if p4a.url is not specified, defaults to upstream (kivy) 297 | #p4a.fork = kivy 298 | 299 | # (str) python-for-android branch to use, defaults to master 300 | #p4a.branch = master 301 | p4a.branch = develop 302 | 303 | # (str) python-for-android specific commit to use, defaults to HEAD, must be within p4a.branch 304 | #p4a.commit = HEAD 305 | 306 | # (str) python-for-android git clone directory (if empty, it will be automatically cloned from github) 307 | #p4a.source_dir = 308 | 309 | # (str) The directory in which python-for-android should look for your own build recipes (if any) 310 | #p4a.local_recipes = 311 | 312 | # (str) Filename to the hook for p4a 313 | #p4a.hook = 314 | 315 | # (str) Bootstrap to use for android builds 316 | # p4a.bootstrap = sdl2 317 | 318 | # (int) port number to specify an explicit --port= p4a argument (eg for bootstrap flask) 319 | #p4a.port = 320 | 321 | # Control passing the --use-setup-py vs --ignore-setup-py to p4a 322 | # "in the future" --use-setup-py is going to be the default behaviour in p4a, right now it is not 323 | # Setting this to false will pass --ignore-setup-py, true will pass --use-setup-py 324 | # NOTE: this is general setuptools integration, having pyproject.toml is enough, no need to generate 325 | # setup.py if you're using Poetry, but you need to add "toml" to source.include_exts. 326 | #p4a.setup_py = false 327 | 328 | # (str) extra command line arguments to pass when invoking pythonforandroid.toolchain 329 | #p4a.extra_args = 330 | 331 | 332 | # 333 | # iOS specific 334 | # 335 | 336 | # (str) Path to a custom kivy-ios folder 337 | #ios.kivy_ios_dir = ../kivy-ios 338 | # Alternately, specify the URL and branch of a git checkout: 339 | ios.kivy_ios_url = https://github.com/kivy/kivy-ios 340 | ios.kivy_ios_branch = master 341 | 342 | # Another platform dependency: ios-deploy 343 | # Uncomment to use a custom checkout 344 | #ios.ios_deploy_dir = ../ios_deploy 345 | # Or specify URL and branch 346 | ios.ios_deploy_url = https://github.com/phonegap/ios-deploy 347 | ios.ios_deploy_branch = 1.10.0 348 | 349 | # (bool) Whether or not to sign the code 350 | ios.codesign.allowed = false 351 | 352 | # (str) Name of the certificate to use for signing the debug version 353 | # Get a list of available identities: buildozer ios list_identities 354 | #ios.codesign.debug = "iPhone Developer: ()" 355 | 356 | # (str) The development team to use for signing the debug version 357 | #ios.codesign.development_team.debug = 358 | 359 | # (str) Name of the certificate to use for signing the release version 360 | #ios.codesign.release = %(ios.codesign.debug)s 361 | 362 | # (str) The development team to use for signing the release version 363 | #ios.codesign.development_team.release = 364 | 365 | # (str) URL pointing to .ipa file to be installed 366 | # This option should be defined along with `display_image_url` and `full_size_image_url` options. 367 | #ios.manifest.app_url = 368 | 369 | # (str) URL pointing to an icon (57x57px) to be displayed during download 370 | # This option should be defined along with `app_url` and `full_size_image_url` options. 371 | #ios.manifest.display_image_url = 372 | 373 | # (str) URL pointing to a large icon (512x512px) to be used by iTunes 374 | # This option should be defined along with `app_url` and `display_image_url` options. 375 | #ios.manifest.full_size_image_url = 376 | 377 | 378 | [buildozer] 379 | 380 | # (int) Log level (0 = error only, 1 = info, 2 = debug (with command output)) 381 | log_level = 2 382 | 383 | # (int) Display warning if buildozer is run as root (0 = False, 1 = True) 384 | warn_on_root = 1 385 | 386 | # (str) Path to build artifact storage, absolute or relative to spec file 387 | # build_dir = ./.buildozer 388 | 389 | # (str) Path to build output (i.e. .apk, .aab, .ipa) storage 390 | # bin_dir = ./bin 391 | 392 | # ----------------------------------------------------------------------------- 393 | # List as sections 394 | # 395 | # You can define all the "list" as [section:key]. 396 | # Each line will be considered as a option to the list. 397 | # Let's take [app] / source.exclude_patterns. 398 | # Instead of doing: 399 | # 400 | #[app] 401 | #source.exclude_patterns = license,data/audio/*.wav,data/images/original/* 402 | # 403 | # This can be translated into: 404 | # 405 | #[app:source.exclude_patterns] 406 | #license 407 | #data/audio/*.wav 408 | #data/images/original/* 409 | # 410 | 411 | 412 | # ----------------------------------------------------------------------------- 413 | # Profiles 414 | # 415 | # You can extend section / key with a profile 416 | # For example, you want to deploy a demo version of your application without 417 | # HD content. You could first change the title to add "(demo)" in the name 418 | # and extend the excluded directories to remove the HD content. 419 | # 420 | #[app@demo] 421 | #title = My Application (demo) 422 | # 423 | #[app:source.exclude_patterns@demo] 424 | #images/hd/* 425 | # 426 | # Then, invoke the command line with the "demo" profile: 427 | # 428 | #buildozer --profile demo android debug 429 | -------------------------------------------------------------------------------- /multicore/main.kv: -------------------------------------------------------------------------------- 1 | #:import utils kivy.utils 2 | 3 | : 4 | canvas.before: 5 | Color: 6 | rgb: utils.get_color_from_hex('#212946') 7 | Rectangle: 8 | pos: self.pos 9 | size: self.size 10 | 11 | BoxLayout: 12 | size_hint: 1, 1 13 | orientation: 'vertical' 14 | padding: 10, 10, 0, 10 15 | 16 | BoxLayout: 17 | orientation: 'vertical' 18 | size_hint: 1, 1 19 | BoxLayout: 20 | padding: 10, 10, 0, 10 21 | id: graph_top_left 22 | size_hint_x: 1 23 | size_hint_y: 1 24 | 25 | BoxLayout: 26 | padding: 10, 10, 0, 10 27 | id: graph_bottom_left 28 | size_hint_x: 1 29 | size_hint_y: 1 30 | 31 | BoxLayout: 32 | padding: 10, 10, 0, 10 33 | id: graph_top_right 34 | size_hint_x: 1 35 | size_hint_y: 1 36 | 37 | BoxLayout: 38 | padding: 10, 10, 0, 10 39 | id: graph_bottom_right 40 | size_hint_x: 1 41 | size_hint_y: 1 42 | 43 | BoxLayout: 44 | size_hint: 1, 0.1 45 | orientation: 'vertical' 46 | 47 | Label: 48 | text: 'Frequency: ' + str(freq.value) + ' hz' 49 | 50 | Slider: 51 | id: freq 52 | min: 1 53 | max: 200 54 | step: 1 55 | # on_value: root.update_plot_multi_core(freq.value) 56 | on_value: root.update_freq(freq.value) 57 | -------------------------------------------------------------------------------- /multicore/main.py: -------------------------------------------------------------------------------- 1 | from kivy.app import App 2 | from kivy.properties import NumericProperty 3 | from kivy.uix.boxlayout import BoxLayout 4 | from kivy_garden.graph import Graph, LinePlot 5 | import numpy as np 6 | import multiprocessing as mp 7 | from multiprocessing import Pool 8 | import ctypes as c 9 | 10 | 11 | samples = 4096 12 | amount_graphs = 4 13 | total_samples = samples * amount_graphs 14 | shared_array = mp.Array(c.c_double, np.zeros(total_samples), lock=False) 15 | shared_array_np = np.ndarray(total_samples, dtype=c.c_double, buffer=shared_array) 16 | # frequency 17 | shared_value = mp.Value('i', 5) 18 | plot_x = np.linspace(0, 1, total_samples) 19 | 20 | 21 | def task(): 22 | freq = shared_value.value 23 | plot_y_top_left = np.sin(2*np.pi*freq*plot_x[:samples])* 0.8 24 | plot_y_bottom_left = np.sign(np.sin(2*np.pi*freq*plot_x[samples:samples*2])) * 0.8 25 | plot_y_top_right = np.sign(np.sin(2*np.pi*freq*plot_x[samples*2:samples*3])) * 0.8 26 | plot_y_bottom_right = np.sign(np.sin(2*np.pi*freq*plot_x[samples*3:samples*4])) * 0.8 27 | 28 | array = np.zeros(samples*4) 29 | array[:samples] = plot_y_top_left 30 | array[samples:samples*2] = plot_y_bottom_left 31 | array[samples*2:samples*3] = plot_y_top_right 32 | array[samples*3:samples*4] = plot_y_bottom_right 33 | 34 | np.copyto(shared_array_np, array) 35 | print("running task") 36 | 37 | cpus = mp.cpu_count() 38 | print("Amount of CPUs", cpus) 39 | pool = Pool(cpus) 40 | 41 | 42 | class MainApp(App): 43 | 44 | def build(self): 45 | self.app = MainGrid() 46 | return self.app 47 | 48 | class MainGrid(BoxLayout): 49 | 50 | freq = NumericProperty(5) 51 | 52 | def __init__(self, **kwargs): 53 | super().__init__(**kwargs) 54 | 55 | self.samples = samples 56 | self.graph_top_left = Graph(y_ticks_major=0.5, 57 | x_ticks_major=self.samples/8, 58 | border_color=[0, 1, 1, 1], 59 | tick_color=[0, 1, 1, 0.7], 60 | x_grid=True, y_grid=True, 61 | xmin=0, xmax=self.samples, 62 | ymin=-1.0, ymax=1.0, 63 | draw_border=False, 64 | x_grid_label=True, y_grid_label=False) 65 | 66 | self.graph_bottom_left = Graph(y_ticks_major=0.5, 67 | x_ticks_major=self.samples/8, 68 | border_color=[0, 1, 1, 1], 69 | tick_color=[0, 1, 1, 0.7], 70 | x_grid=True, y_grid=True, 71 | xmin=self.samples, xmax=self.samples*2, 72 | ymin=-1.0, ymax=1.0, 73 | draw_border=False, 74 | x_grid_label=True, y_grid_label=False) 75 | 76 | self.graph_top_right = Graph(y_ticks_major=0.5, 77 | x_ticks_major=self.samples/8, 78 | border_color=[0, 1, 1, 1], 79 | tick_color=[0, 1, 1, 0.7], 80 | x_grid=True, y_grid=True, 81 | xmin=self.samples*2, xmax=self.samples*3, 82 | ymin=-1.0, ymax=1.0, 83 | draw_border=False, 84 | x_grid_label=True, y_grid_label=False) 85 | 86 | self.graph_bottom_right = Graph(y_ticks_major=0.5, 87 | x_ticks_major=self.samples/8, 88 | border_color=[0, 1, 1, 1], 89 | tick_color=[0, 1, 1, 0.7], 90 | x_grid=True, y_grid=True, 91 | xmin=self.samples*3, xmax=self.samples*4, 92 | ymin=-1.0, ymax=1.0, 93 | draw_border=False, 94 | x_grid_label=True, y_grid_label=False) 95 | 96 | # Mono, Sampling Rate, Chunksize 97 | self.ids.graph_top_left.add_widget(self.graph_top_left) 98 | self.ids.graph_bottom_left.add_widget(self.graph_bottom_left) 99 | self.ids.graph_top_right.add_widget(self.graph_top_right) 100 | self.ids.graph_bottom_right.add_widget(self.graph_bottom_right) 101 | self.plot_x = np.linspace(0, 1, self.samples*4) 102 | self.plot_y = np.zeros(self.samples) 103 | self.plot_top_left = LinePlot(color=[1, 1, 0, 1], line_width=1.5) 104 | self.plot_bottom_left = LinePlot(color=[1, 0, 1, 1], line_width=1.5) 105 | self.plot_top_right = LinePlot(color=[1, 0, 0, 1], line_width=1.5) 106 | self.plot_bottom_right = LinePlot(color=[1, 1, 0, 1], line_width=1.5) 107 | 108 | 109 | self.graph_top_left.add_plot(self.plot_top_left) 110 | self.graph_bottom_left.add_plot(self.plot_bottom_left) 111 | self.graph_top_right.add_plot(self.plot_top_right) 112 | self.graph_bottom_right.add_plot(self.plot_bottom_right) 113 | 114 | self.update_freq(4) 115 | 116 | def update_plot_multi_core(self, freq): 117 | pool.apply(task) 118 | self.plot_top_left.points = [(x, shared_array_np[x]) for x in range(self.samples)] 119 | self.plot_bottom_left.points = [(x, shared_array_np[x]) for x in range(self.samples, self.samples*2)] 120 | self.plot_top_right.points = [(x, shared_array_np[x]) for x in range(self.samples*2, self.samples*3)] 121 | self.plot_bottom_right.points = [(x, shared_array_np[x]) for x in range(self.samples*3, self.samples*4)] 122 | 123 | def update_freq(self, value): 124 | # with shared_value.get_lock(): 125 | shared_value.value = value 126 | self.update_plot_multi_core(shared_value.value) 127 | 128 | 129 | MainApp().run() 130 | --------------------------------------------------------------------------------