pax_global_header00006660000000000000000000000064146207261300014513gustar00rootroot0000000000000052 comment=a2f314df4b6c6bf8b6800124ed185b5a2ef50288 cava-0.10.2/000077500000000000000000000000001462072613000125055ustar00rootroot00000000000000cava-0.10.2/.clang-format000066400000000000000000000001351462072613000150570ustar00rootroot00000000000000BasedOnStyle: LLVM --- Language: Cpp PointerAlignment: Right ColumnLimit: 100 IndentWidth: 4 cava-0.10.2/.github/000077500000000000000000000000001462072613000140455ustar00rootroot00000000000000cava-0.10.2/.github/ISSUE_TEMPLATE/000077500000000000000000000000001462072613000162305ustar00rootroot00000000000000cava-0.10.2/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000017041462072613000207240ustar00rootroot00000000000000--- name: Bug report about: Create a report to help us improve title: '' labels: '' assignees: '' --- **READ THIS BEFORE CREATING NEW ISSUE** Are you using cava from a package repository, like AUR? If so, clone the master branch from here, build and run. Is your issue already resolved? Don't know how to clone or compile source code? File report to package maintainer instead! **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: 1. Set config parameter to 2. run 3. do something 4. See error **Expected behavior** A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - OS: [e.g. macOS, Ubuntu] - Version [e.g. 22] **Terminal emulator** - name - version **Additional context** Add any other context about the problem here. cava-0.10.2/.github/ISSUE_TEMPLATE/feature_request.md000066400000000000000000000011231462072613000217520ustar00rootroot00000000000000--- name: Feature request about: Suggest an idea for this project title: '' labels: '' assignees: '' --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots about the feature request here. cava-0.10.2/.github/workflows/000077500000000000000000000000001462072613000161025ustar00rootroot00000000000000cava-0.10.2/.github/workflows/build-and-test.yml000066400000000000000000000043751462072613000214520ustar00rootroot00000000000000name: build-and-test on: [push, pull_request] jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - uses: DoozyX/clang-format-lint-action@v0.5 with: source: '.' exclude: './third_party' extensions: 'h,c' build-linux: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - name: Install dependencies run: | sudo apt-get update sudo apt-get install libfftw3-dev libasound2-dev libncursesw5-dev libpulse-dev libtool automake autoconf-archive libiniparser-dev portaudio19-dev libsndio-dev libsdl2-2.0-0 libsdl2-dev squeezelite pulseaudio libpipewire-0.3-dev - name: Generate configure run: ./autogen.sh - name: Run ./configure run: ./configure - name: Run make run: make CFLAGS='-Werror' - name: Prepare tests run: | pulseaudio -D squeezelite -o pulse -v -m 51:fb:32:f8:e6:9f -z - name: run non zero test run: ./cava -p example_files/test_configs/non_zero_test > /dev/null - name: run pulseaudio test run: ./cava -p example_files/test_configs/pulse_zero_test > /dev/null - name: run fifo test run: ./cava -p example_files/test_configs/fifo_zero_test > /dev/null - name: run shmem test run: ./cava -p example_files/test_configs/shmem_zero_test > /dev/null - name: build cavacore test application run: gcc -c -g cavacore_test.c - name: link cavacore test application run: gcc -o cavacore_test cavacore_test.o cava-cavacore.o -lm -lfftw3 - name: run cavacore test application run: ./cavacore_test build-macos: runs-on: macos-latest steps: - uses: actions/checkout@v1 - name: Install dependencies run: | brew install fftw ncurses libtool automake autoconf-archive portaudio iniparser sdl2 ln -s /usr/local/bin/glibtoolize /usr/local/bin/libtoolize - name: Generate configure run: PATH="/opt/homebrew/opt/libtool/libexec/gnubin:$PATH" ./autogen.sh - name: Run ./configure run: LDFLAGS="-L/opt/homebrew/lib" CPPFLAGS="-I/opt/homebrew/include" ./configure - name: Run make run: make CFLAGS='-Werror' - name: run non zero test run: ./cava -p example_files/test_configs/non_zero_test > /dev/null cava-0.10.2/.gitignore000066400000000000000000000003411462072613000144730ustar00rootroot00000000000000*.so.0 *.o *.a .deps/ .libs/ Makefile Makefile.in aclocal.m4 ar-lib autom4te.cache/ compile config.guess config.log config.status config.sub configure depcomp install-sh libtool ltmain.sh m4/ missing version config_file.h .* cava-0.10.2/CAVACORE.md000066400000000000000000000036101462072613000142120ustar00rootroot00000000000000cavacore ========= Core processing engine of cava. # How it works cava core works as a wrapper around [fftw](http://www.fftw.org/). While fftw does the job with the discrete Fourier transform which transforms the audio from the time domain (series of samples) to the frequency domain (series of frequencies), the raw output data from fftw will not look very nice when used directly in a visualization. The cavacore engine does several things to improve the look of the visualization: ## adjustable bandwith Theoretically the human ear can hear frequencies up to 20kHz, but the information above 10k is hard to separate from eachother and does not give much feedback by itself when visualizing audio. Similarly audio down to 20Hz can be heard, but the frequencies below 50Hz does not directly provide anything to the visualizing of the audio. ## spread the output logarithmically The human ear hears different frequencies logarithmically, so notes that are 2x and 4x higher than eachother, will be preceived as beeing a fixed amount higher than eachother. Therefore cavacore outputs the frequencies logarithmically. Cavacore will also group the output in the desired number of samples. ## noise reduction the raw output of fftw is very noisy, cavacore processes the output signal in two ways to provide a smooth output: * an integral filter calculates a weighted average of the last values * fall off filter, when values is lower than last value it uses a fall down effect instead of the new value This feature can be adjusted. ## real-time sensitivity adjustment The range of an input signal can vary a lot. cavacore can keep the output signal within range in real-time. This feature can be disabled. # Building use the root CMakeLists.txt to build it: ``` mkdir build cd build cmake .. cmake --build . ``` # Usage See cavacore.h for documentation and the cavacore_test.c application for how to use. cava-0.10.2/CMakeLists.txt000077500000000000000000000003321462072613000152460ustar00rootroot00000000000000# This is only for the cavacore lib, see CAVACORE.md for details # to build cava don't use this, use the automake stuff cmake_minimum_required(VERSION 3.13.0) project(cavacore) add_library(cavacore STATIC cavacore.c) cava-0.10.2/CONTRIBUTING.md000066400000000000000000000014011462072613000147320ustar00rootroot00000000000000# How to contribute Thank you for wanting to contribute to this project. In order to get the development of this project to run as smooth as possible, we will encourage all contributions to follw this simple process: 1. Before any pull request is submitted a github issue must be created for the task. 2. The new github task is to be opened for suggestions from other contributors. 3. A pull request is published. 4. Contributors code review pull request and approve/reject pull request. 5. Pull request either gets approved or rejected. 5. Github task is updated and everyone is notified. # Coding conventions * 4 spaces for indents * curly braces on same line as if, while, for statements Generally please try to keep the style consistent with the code as it is. cava-0.10.2/LICENSE000066400000000000000000000020721462072613000135130ustar00rootroot00000000000000Copyright (c) 2015 Karl Stavestrand Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. cava-0.10.2/Makefile.am000066400000000000000000000027201462072613000145420ustar00rootroot00000000000000AUTOMAKE_OPTIONS = foreign ACLOCAL_AMFLAGS = -I m4 bin_PROGRAMS = cava cava_SOURCES = cava.c cavacore.c config.c input/common.c input/fifo.c input/shmem.c \ output/terminal_noncurses.c output/raw.c output/noritake.c cava_CPPFLAGS = -DPACKAGE=\"$(PACKAGE)\" -DVERSION=\"$(VERSION)\" \ -D_POSIX_SOURCE -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE_EXTENDED \ -DFONTDIR=\"@FONT_DIR@\" -DFONTFILE=\"@FONT_FILE@\" cava_CFLAGS = -std=c99 -Wall -Wextra -Wno-unused-result -Wno-unknown-warning-option -Wno-maybe-uninitialized -Wno-vla-parameter if OSX cava_CFLAGS += -DNORT cava_LDADD = else cava_LDADD = -lrt cava_font_dir = @FONT_DIR@ cava_font__DATA = @FONT_FILE@ endif if FREEBSD if CAVAFONT CLEANFILES = cava.bdf cava.fnt cava.fnt: ${srcdir}/cava.psf ${PSF2BDF} --fontname="-gnu-cava-medium-r-normal--16-160-75-75-c-80-iso10646-1" ${srcdir}/cava.psf cava.bdf ${VTFONTCVT} -o cava.fnt cava.bdf endif endif if ALSA cava_SOURCES += input/alsa.c endif if PORTAUDIO cava_SOURCES += input/portaudio.c endif if PIPEWIRE cava_SOURCES += input/pipewire.c endif if PULSE cava_SOURCES += input/pulse.c endif if SNDIO cava_SOURCES += input/sndio.c endif if OSS cava_SOURCES += input/oss.c endif if JACK cava_SOURCES += input/jack.c endif if NCURSES cava_SOURCES += output/terminal_ncurses.c endif if SDL cava_SOURCES += output/sdl_cava.c endif if SDL_GLSL cava_SOURCES += output/sdl_glsl.c endif cava-0.10.2/README.md000066400000000000000000000654021462072613000137730ustar00rootroot00000000000000CAVA [![Build Status](https://github.com/karlstav/cava/workflows/build-and-test/badge.svg)](https://github.com/karlstav/cava/actions) ==================== **C**ross-platform **A**udio **V**isu**a**lizer by [Karl Stavestrand](mailto:karl@stavestrand.no) Get it on Google Play ![spectrum](https://github.com/karlstav/cava/blob/master/example_files/cava.gif "spectrum") [Demo video](https://youtu.be/9PSp8VA6yjU) - [What it is](#what-it-is) - [Installing](#installing) - [From Source](#from-source) - [Package managers](#package-managers) - [Capturing audio](#capturing-audio) - [Pulseaudio](#pulseaudio) - [Pipewire](#pipewire) - [ALSA](#alsa) - [MPD](#mpd) - [Sndio](#sndio) - [OSS](#oss) - [JACK](#jack) - [squeezelite](#squeezelite) - [macOS](#macos-1) - [Windows](#windows) - [Running via ssh](#running-via-ssh) - [Troubleshooting](#troubleshooting) - [Usage](#usage) - [Controls](#controls) - [Configuration](#configuration) - [Using cava in other applications](#using-cava-in-other-applications) - [cavacore](#cavacore-library) - [Raw Output](#raw-output) - [Contribution](#contribution) What it is ---------- Cava is a bar spectrum audio visualizer for terminal (ncurses) or desktop (SDL). works on: * Linux * FreeBSD * macOS * Windows This program is not intended for scientific use. It's written to look responsive and aesthetic when used to visualize music. Installing ------------------ ### From Source #### Installing Build Requirements Required components: * [FFTW](http://www.fftw.org/) * libtool * automake * autoconf-archive (needed for setting up OpenGL) * pkgconf * build-essentials * [iniparser](https://github.com/ndevilla/iniparser) Recomended components: The development lib of one of these audio frameworks, depending on your distro: * ALSA * Pulseaudio * Pipewire * Portaudio * Sndio * JACK Optional components: * SDL2 dev files * [ncursesw dev files](http://www.gnu.org/software/ncurses/) (bundled in ncurses in arch) Only FFTW, iniparser and the build tools are actually required for CAVA to compile, but this will only give you the ability to read from fifo files. To capture audio directlty from your system pipewire, pulseaudio, alsa, sndio, jack or portaudio dev files are required (depending on what audio system you are using). Ncurses can be used as an alternative output method if you have issues with the default one. But it is not required. All the requirements can be installed easily in all major distros: FreeBSD pkg install autoconf autoconf-archive automake fftw3 iniparser jackit libglvnd libtool pkgconf psftools sdl2 sndio Additionally, run these commands on FreeBSD before building: export CFLAGS="-I/usr/local/include" export LDFLAGS="-L/usr/local/lib" Debian/Ubuntu: sudo apt install build-essential libfftw3-dev libasound2-dev libncursesw5-dev libpulse-dev libtool automake autoconf-archive libiniparser-dev libsdl2-2.0-0 libsdl2-dev libpipewire-0.3-dev libjack-jackd2-dev pkgconf ArchLinux: pacman -S base-devel fftw ncurses alsa-lib iniparser pulseaudio autoconf-archive pkgconf openSUSE: zypper install alsa-devel ncurses-devel fftw3-devel libpulse-devel libtool autoconf-archive pkgconf Fedora: dnf install alsa-lib-devel ncurses-devel fftw3-devel pulseaudio-libs-devel libtool autoconf-archive iniparser-devel pkgconf macOS: First install homebrew if you have't already: /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" Then install prerequisites: brew install fftw ncurses libtool automake autoconf-archive pkgconf portaudio iniparser The installation location for Homebrew packages is different between Intel Macs and Apple Silicon Macs. As such, the commands will be a little bit different. You can find out which type you have [here](https://support.apple.com/en-us/HT211814#:~:text=To%20open%20About%20This%20Mac,as%20an%20Intel%2Dbased%20Mac.) For both machines, run these commands to fix macOS not finding libtool and ncursesw: export LIBTOOL=`which glibtool` export LIBTOOLIZE=`which glibtoolize` ln -s `which glibtoolize` /usr/local/bin/libtoolize On an Intel Mac, run the following command as well: ln -s /usr/lib/libncurses.dylib /usr/local/lib/libncursesw.dylib On an Apple Silicon Mac, run this command instead: ln -s /opt/homebrew/lib/lib/libncursesw.6.dylib /usr/local/lib/libncursesw.dylib Note that the file name may be a little bit different depending on the versions, but the directory should be the same. Additionally, run these commands on Apple Silicon Macs so that ./configure can find the Homebrew packages: export LDFLAGS="-L/opt/homebrew/lib" export CPPFLAGS="-I/opt/homebrew/include" Intel Mac instructions tested on macOS Big Sur. Apple Silicon instructions tested on macOS Ventura. Windows: see separate readme in `cava_win` folder. #### Building First of all clone this repo and cd in to it, then run: ./autogen.sh ./configure make If you have a recommended component installed, but do not wish to use it (perhaps if building a binary on one machine to be used on another), then the corresponding feature can be disabled during configuration (see configure --help for details). For windows there is a VS solution file in the `cava_win` folder. #### Installing Install `cava` to default `/usr/local`: make install Or you can change `PREFIX`, for example: ./configure --prefix=PREFIX #### Uninstalling make uninstall ### Package managers All distro specific instalation sources might be out of date. Please check version before reporting any issues here. #### FreeBSD pkg install cava #### openSUSE Tumbleweed users have cava in their repo. They can just use: zypper in cava Leap users need to add the multimedia:apps repository first: zypper ar -f obs://multimedia:apps/openSUSE_Leap_42.2 multimedia If you use another version just replace *openSUSE_Leap_42.2* with *openSUSE_13.2*, adjust it to your version. #### Fedora Cava is available in Fedora 26 and later. You can install Cava by running: dnf install cava #### Arch Cava is in [AUR](https://aur.archlinux.org/packages/cava/). pacaur -S cava #### Ubuntu/Debian ##### Ubuntu 20.10 or more recent / Debian (unstable) sudo apt install cava ##### Older Ubuntu Harshal Sheth has added CAVA to his PPA, it can be installed with: add-apt-repository ppa:hsheth2/ppa apt update apt install cava #### macOS cava is in homebrew. brew install cava Capturing audio --------------- ### Pulseaudio Just make sure you have installed pulseaudio dev files and that cava has been built with pulseaudio support (it should be automatically if the dev files are found). If you're lucky all you have to do is to run cava. If nothing happens you might have to use a different source than the default. The default might also be your microphone. Look at the [config](#configuration) file for help. ### Pipewire Set method = pipewire The default source is `auto` and will most likely be your currently selected output. If you run wireplumber you can use `wpctl` to get the `object.path` or `object.serial` of the desired device to visualize. e.g. source = alsa:pcm:3:front:3:playback ### ALSA Set method = alsa in the [config](#configuration) file. ALSA can be difficult because there is no native way to grab audio from an output. If you want to capture audio straight fom the output (not just mic or line-in), you must create an ALSA loopback interface, then output the audio simultaneously to both the loopback and your normal interface. To create a loopback interface simply run: `sudo modprobe snd_aloop` Hopefully your `aplay -l` should now contain a loopback interface. To make it persistent across boot add the line `snd-aloop` to "/etc/modules". To keep it from being loaded as the first soundcard add the line `options snd-aloop index=1` to "/etc/modprobe.d/alsa-base.conf", this will load it at '1'. You can replace '1' with whatever makes most sense in your audio setup. Playing the audio through your Loopback interface makes it possible for cava to capture it, but there will be no sound in your speakers. In order to play audio on the loopback interface and your actual interface you must make use of the ALSA multi channel. Look at the included example file `example_files/etc/asound.conf` on how to use the multi channel. I was able to make this work with a HDA Intel PCH sound card, but I had no luck with the an USB DAC. Read more about the ALSA method [here](http://stackoverflow.com/questions/12984089/capture-playback-on-play-only-sound-card-with-alsa). If you are having problems with the alsa method on Rasberry PI, try enabling `mmap` by adding the following line to `/boot/config.txt` and reboot: ``` dtoverlay=i2s-mmap ``` #### dmix @reluekiss, was able to make cava work with dmix. Check out the example config in `example_files/etc/asound_dmix.conf` and issue [534](https://github.com/karlstav/cava/issues/534). ### mpd Add these lines in mpd: audio_output { type "fifo" name "my_fifo" path "/tmp/mpd.fifo" format "44100:16:2" } Uncomment and change input method to `fifo` in the [config](#configuration) file. The path of the fifo can be specified with the `source` parameter. I had some trouble with sync (the visualizer was ahead of the sound). Reducing the ALSA buffer in mpd fixed it: audio_output { type "alsa" name "My ALSA" buffer_time "50000" # (50ms); default is 500000 microseconds (0.5s) } ### Sndio Set method = sndio Sndio is the audio framework used on OpenBSD, but it's also available on FreeBSD, NetBSD and Linux. So far this is only tested on FreeBSD, but it's probably very similar on other operating systems. The following example demonstrates how to setup CAVA for sndio on FreeBSD (please consult the [OSS](#oss) section for a deeper explanation of the various `pcmX` sound devices and the corresponding `/dev/dspX` audio devices in this example). ```sh $ cat /dev/sndstat Installed devices: pcm0: (play/rec) default pcm1: (rec) pcm2: (play/rec) No devices installed from userspace. ``` Sndio operates on device descriptors. In general for every `/dev/dspX` audio device there is a corresponding `rsnd/X` sndio raw device descriptor. In this example there are `rsnd/0`, `rsnd/1` and `rsnd/2` (they are not listed in `/dev`, sndio uses these descriptors to access the corresponding audio devices internally). Sndio also handles the implicit `default` device descriptor, which acts like a symlink to the raw device descriptor corresponding to the default audio device `/dev/dsp`. In this example it acts like a symlink to `rsnd/0` because the default audio device `/dev/dsp` symlinks to `/dev/dsp0`. Sndio also evaluates the environment variables `AUDIODEVICE` and `AUDIORECDEVICE`. If one of these is set (`AUDIORECDEVICE` overrides `AUDIODEVICE` if both are set) and a sndio-aware program tries to open the `default` device descriptor or an unspecified device descriptor, then the program will use the device descriptor specified in the environment variable. Now in order to visualize the mic input in CAVA, the `source` value in the configuration file must be set to the corresponding audio descriptor: source = default # default; symlink to rsnd/0 in this example; AUDIORECDEVICE and AUDIODEVICE evaluation source = # unspecified device descriptor; same as default above source = rsnd/0 # for the pcm0 mic on the rear source = rsnd/1 # for the pcm1 mic on the front source = rsnd/2 # for the pcm2 mic on the USB headset With `source = default` one can switch the visualization on the commandline without changing the configuration file again: ```sh $ AUDIODEVICE=rsnd/0 cava $ AUDIODEVICE=rsnd/1 cava $ AUDIODEVICE=rsnd/2 cava ``` Sndio can't record the played back audio with just the raw device descriptors, i.e. the sounds from a music player or a browser which play on the external stereo speakers through `rsnd/0` are not visualized in CAVA. For this to work the sndio server has to be started and a monitoring sub-device has to be created. The following example shows how to start the server and create a monitoring sub-device `snd/0` from `rsnd/0` and then start CAVA with `AUDIODEVICE` pointing to the new monitoring sub-device: ```sh $ sndiod -f rsnd/0 -m play,mon $ AUDIODEVICE=snd/0 cava ``` Switch between the speakers and the USB headset: ```sh $ sndiod -f rsnd/2 -m play,mon -s usb -f rsnd/0 -m play,mon -s speakers $ AUDIODEVICE=snd/usb cava $ AUDIODEVICE=snd/speakers cava ``` Consult the manpage `sndiod(8)` for further information regarding configuration and startup of a sndio server. ### OSS Set method = oss The audio system used on FreeBSD is the Open Sound System (OSS). The following example demonstrates how to setup CAVA for OSS on FreeBSD: ```sh $ cat /dev/sndstat Installed devices: pcm0: (play/rec) default pcm1: (rec) pcm2: (play/rec) No devices installed from userspace. ``` The system has three `pcm` sound devices, `pcm0`, `pcm1` and `pcm2`. `pcm0` corresponds to the analog output jack on the rear, in which external stereo speakers are plugged in, and the analog input jack, in which one could plug in a microphone. Because it encapsulates both, output and input, it is marked as `play/rec`. It is also set as the `default` sound device. `pcm1` corresponds to another analog input jack for a mic on the front side and is marked `rec`. A USB headset with an integrated mic is plugged in an USB port and the system has created the `pcm2` sound device with `play/rec` capabilities for it. In general for every `pcmX` device there is a corresponding `/dev/dspX` audio device. In this example there are `/dev/dsp0`, `/dev/dsp1` and `/dev/dsp2` (the system creates them when needed, they are not listed via `ls /dev` if they are currently not in use). The system also creates an implicit `/dev/dsp`, which acts like a symlink to the `default` audio device, in this example to `/dev/dsp0`. Now in order to visualize the mic input in CAVA, the `source` value in the configuration file must be set to the corresponding audio device: source = /dev/dsp # default; symlink to /dev/dsp0 in this example source = /dev/dsp0 # for the pcm0 mic on the rear source = /dev/dsp1 # for the pcm1 mic on the front source = /dev/dsp2 # for the pcm2 mic on the USB headset OSS can't record the outgoing audio on its own, i.e. the sounds from a music player or a browser which play on the external stereo speakers through `/dev/dsp0` are not visualized in CAVA. A solution is to use Virtual OSS. It can create virtual audio devices from existing audio devices, in particular it can create a loopback audio device from `/dev/dsp0` and from which the played back audio can be fed into CAVA: ```sh $ doas pkg install virtual_oss $ doas virtual_oss -r44100 -b16 -c2 -s4ms -O /dev/dsp0 -R /dev/null -T /dev/sndstat -l dsp.cava $ cat /dev/sndstat Installed devices: pcm0: (play/rec) default pcm1: (rec) pcm2: (play/rec) Installed devices from userspace: dsp.cava: (play/rec) ``` It created a virtual loopback device `/dev/dsp.cava` from `/dev/dsp0`. Now the audio is visualized in CAVA with `source = /dev/dsp.cava` in the configuration file. The playback program must have a configuration to use the `/dev/dsp.cava` device. For programs where this is not possible, e.g. which always use `/dev/dsp`, replace `-l dsp.cava` with `-l dsp`. Virtual OSS can be configured and started as a service on FreeBSD. ### JACK Set method = jack The JACK Audio Connection Kit (JACK) is a professional sound server API which is available on several operating systems, e.g. FreeBSD and Linux. CAVA is a JACK client with the base client name `cava` and adheres to the standard server start and stop behaviour, i.e. CAVA starts a JACK server if none is already running and the environment variable `JACK_START_SERVER` is defined, in which case the server also stops when all clients have exited. The `source` in the CAVA configuration file specifies the name of the JACK server to which CAVA tries to connect to. The default value is `default`, which is also the default JACK server name. The value can be empty, in which case it implies `default`. Therefore the following three entries are equivalent: ; source = default source = default source = One exception is the combination of an empty `source` entry and the environment variable `JACK_DEFAULT_SERVER`. If the environment variable is defined, e.g. `export JACK_DEFAULT_SERVER=foo`, then the following entries are equivalent: source = foo source = Consult the manpage `jackd(1)` for further information regarding configuration and startup of a JACK server. CAVA creates terminal audio-typed (so no MIDI support) input ports. These ports can connect to output ports of other JACK clients, e.g. connect to the output ports of a music player and CAVA will visualize the music. Currently CAVA supports up to two input ports, i.e. it supports mono and stereo. The number of input ports can be controlled via the `channels` option in the input section of the configuration file: channels = 1 # one input port, mono channels = 2 # two input ports, stereo (default) The port's short name is simply `M` for mono, and `L` and `R` for stereo. The full name of the input port according to the base client name is `cava:M` for mono, and `cava:L` and `cava:R` for stereo. The option `autoconnect` controls the connection strategy for CAVA's ports to other client's ports: autoconnect = 0 # don't connect to other ports automatically autoconnect = 1 # only connect to other ports during startup autoconnect = 2 # reconnect to new ports regularly (default) The automatic connection strategies scan the physical terminal input-ports, i.e. the real audio device which actually outputs the sound, and applies the same connections to CAVA's ports. In this way CAVA visualizes the played back audio from JACK clients by default. In order to control and manage the connection between CAVA's ports and ports of other client programs, there are connection management programs for JACK. Some well known connection managers with a graphical user interface are QjackCtl and Cadence. The JACK package itself often comes with CLI tools. Depending on the operating system it could be necessary to install them separately, e.g. on FreeBSD: ```sh $ doas pkg install jack-example-tools ``` Among the tools are the programs `jack_lsp` and `jack_connect`. These two tools are enough to list and connect ports on the commandline. The following example demonstrates how to setup connections with these tools: ```sh $ jack_lsp system:capture_1 system:capture_2 system:playback_1 system:playback_2 cava:L moc:output0 moc:output1 cava:R ``` This listing shows all full port names that are currently available. These correspond to two external JACK clients, `cava` and `moc`, and one internal JACK client `system`. The types and current active connections between the ports can be listed with the `-p` and `-c` switches for `jack_lsp`. In order to connect the ports of CAVA and MOC, `jack_connect` is used: ```sh $ jack_connect cava:L moc:output0 $ jack_connect cava:R moc:output1 ``` Now CAVA visualizes the outgoing audio from MOC. ### squeezelite [squeezelite](https://en.wikipedia.org/wiki/Squeezelite) is one of several software clients available for the Logitech Media Server. Squeezelite can export its audio data as shared memory, which is what this input module uses. Just adapt your [config](#configuration): ``` method = shmem source = /squeezelite-AA:BB:CC:DD:EE:FF ``` where `AA:BB:CC:DD:EE:FF` is squeezelite's MAC address (check the LMS Web GUI (Settings>Information) if unsure). Note: squeezelite must be started with the `-v` flag to enable visualizer support. ### macOS Note: Cava doesn't render correctly within the default macOS terminal. In order to achieve an optimal display, install [Kitty](https://sw.kovidgoyal.net/kitty/index.html). Beware that you may run in to the issue presented in #109; however, it can be resolved with [this](https://stackoverflow.com/questions/7165108/in-os-x-lion-lang-is-not-set-to-utf-8-how-to-fix-it). **Background Music** Install [Background Music](https://github.com/kyleneideck/BackgroundMusic) which provides a loopback interface automatically. Once installed and running just edit your [config](#configuration) to use this interface with portaudio: ``` method = portaudio source = "Background Music" ``` **Sound Flower** [Soundflower](https://github.com/mattingalls/Soundflower) also works to create a loopback interface. Use Audio MIDI Setup to configure a virtual interface that outputs audio to both your speakers and the loopback interface, following [this](https://github.com/RogueAmoeba/Soundflower-Original/issues/44#issuecomment-151586106) recipe. By creating a multi-output device you lose the ability to control the volume on your keyboard. Because of this, we recommend the Background Music app which still gives you keyboard controls. Then edit your [config](#configuration) to use this interface with portaudio: ``` method = portaudio source = "Soundflower (2ch)" ``` ### Windows Should capture the audio from the default output device automatically. Running via ssh --------------- To run via ssh to an external monitor, redirect output to `/dev/console`: ~# ./cava <> /dev/console >&0 2>&1 exit with ctrl+z then run 'bg' to keep it running after you log out. (You must be root to redirect to console. Simple sudo is not enough: Run `sudo su` first.) ## Troubleshooting ### No bars in terminal Most likley issue [#399](https://github.com/karlstav/cava/issues/399). Locale settings need to be set correctly in order for cava to work. ### Visualizer reacts to microphone instead of output This is a known issue with pipewire. Try the workaround described [here](https://github.com/karlstav/cava/issues/422#issuecomment-994270910) ### Vertical lines in bars This is either an issue with the font, or line spacing being enabled in the terminal emulator. Try to change font or disable line spacing. ### Low resolution Since the graphics are simply based on characters, try decreasing the font size. ### Low frame rate Some terminal emulators are just slow. Cava will look best in a GPU based terminal like kitty or alacritty. You can also try to increase the font size ### Font is changed in ttys after exit If you run cava in a TTY (like ctrl+alt+F2) the program will change the font to the included `cava.psf` (actually a slightly modified "unifont"). In console fonts it seems that only 256 Unicode characters are supported, probably because they are bitmap fonts. I could not find a font with Unicode characters 2581-2587 (the 1/8 - 7/8 blocks used on the top of each bar to increase resolution). So in `cava.psf`, the characters 1-7 are actually replaced by Unicode characters 2581-2587. When cava exits, it changes the font back. If cava exits abnormally and you notice that 1-7 are replaced by partial blocks, just change the font with `setfont`. Actually, `setfont` is supposed to return the default font, but this usually isn't set. I haven't found another way to get the current font. So cava sets the font to "Lat2-Fixed16" when interrupted. All major distros should have it. It will revert to your default font at reboot. ### Gradient not working in Konsole Konsole simply does not support this. #194 Usage ----- Usage : cava [options] Visualize audio input in terminal. Options: -p path to config file -v print version Exit with ctrl+c or q. If cava quits unexpectedly or is force killed, echo must be turned on manually with `stty -echo`. ### Controls NOTE: only works in ncurses output mode. | Key | Description | | --- | ----------- | | up / down| increase/decrease sensitivity | | left / right| increase/decrease bar width | | f / b| change foreground/background color | | r | Reload configuration | | c | Reload colors only | | q or CTRL-C| Quit C.A.V.A. | Configuration ------------- As of version 0.4.0 all options are done in the config file, no more command-line arguments! By default a configuration file is created upon first launch in `$XDG_CONFIG_HOME/cava/config` or `$HOME/.config/cava/config`, but cava can also be made to use a different file with the `-p` option. Sending cava a SIGUSR1 signal, will force cava to reload its configuration file. Thus, it behaves as if the user pressed r in the terminal. One might send a SIGUSR1 signal using `pkill` or `killall`. For example: ``` $ pkill -USR1 cava ``` Similarly, sending cava a SIGUSR2 signal will only reload the colors from the configuration file, which is the same as pressing c in the terminal. This is slightly faster than reloading the entire config as the audio processing does not need to reinitialize. ``` $ pkill -USR2 cava ``` **Examples on how the equalizer works:** [eq] 1=0 2=1 3=0 4=1 5=0 ![3_138](https://cloud.githubusercontent.com/assets/6376571/8670183/a54a851e-29e8-11e5-9eff-346bf6ed91e0.png) [eq] 1=2 2=2 3=1 4=1 5=0.5 ![3_139](https://cloud.githubusercontent.com/assets/6376571/8670181/9db0ef50-29e8-11e5-81bc-3e2bb9892da0.png) Using cava in other applications -------------------------------- ### cavacore library The core processing engine in cava has been split into a separate library `cavacore`. See CAVACORE.md for details. ### Raw Output You can also use Cava's output for other programs by using raw output mode, which will write bar data to `STDOUT` that can be piped into other processes. More information on this option is documented in [the example config file](/example_files/config). A useful starting point example script written in python that consumes raw data can be found [here](https://github.com/karlstav/cava/issues/123#issuecomment-307891020). Contribution ------ Please read CONTRIBUTING.md before opening a pull request. Thanks to: * [CelestialWalrus](https://github.com/CelestialWalrus) * [anko](https://github.com/anko) * [livibetter](https://github.com/livibetter) for major contributions in the early development of this project. Also thanks to [dpayne](https://github.com/dpayne/) for figuring out how to find the pulseaudio default sink name. cava-0.10.2/SHADERS.md000066400000000000000000000013351462072613000141220ustar00rootroot00000000000000custom shaders ============== Write your own shaders for cava! cava can use SDL/OpenGL to render custom glsl shaders. The shader files must be placed in $HOME/.config/cava/shaders under [output] set `method` to 'sdl_glsl' use the config options `vertex_shader` and `fragment_shader` to select file. look in the `bar_spectrum.frag` shader for how the shaders interact with cava. the custom shaders will use some of the same config parameters as the other output modes, like number of bars. feel free to commit your own shaders (or improvements to the sdl_glsl output mode) and create pull request. To add a shader to the cava repo put it under output/shaders here, and add it to the INCTXT at the top of the config.c file. cava-0.10.2/autogen.sh000077500000000000000000000003221462072613000145030ustar00rootroot00000000000000#!/bin/sh if [ -d .git ]; then git describe --always --tags --dirty > version # get version from git else echo 0.10.2 > version # hard coded versions fi libtoolize aclocal autoconf automake --add-missing cava-0.10.2/cava.c000066400000000000000000001264061462072613000135740ustar00rootroot00000000000000#include #ifdef HAVE_ALLOCA_H #include #else #include #endif #include #include #ifndef M_PI #define M_PI 3.1415926535897932385 #endif #include #include #ifndef _MSC_VER #include #include #include #include #include #include #endif #ifdef _MSC_VER #include "input/winscap.h" #include #define PATH_MAX 260 #define PACKAGE "cava" #define _CRT_SECURE_NO_WARNINGS 1 #endif // _MSC_VER #include #include #include #include #include #include "cavacore.h" #include "config.h" #include "debug.h" #include "util.h" #ifdef SDL #include "output/sdl_cava.h" #endif #ifdef SDL_GLSL #include "output/sdl_glsl.h" #endif #include "input/common.h" #include "output/terminal_noncurses.h" #ifndef _MSC_VER #ifdef NCURSES #include "output/terminal_bcircle.h" #include "output/terminal_ncurses.h" #include #endif #include "output/noritake.h" #include "output/raw.h" #include "input/alsa.h" #include "input/fifo.h" #include "input/jack.h" #include "input/oss.h" #include "input/pipewire.h" #include "input/portaudio.h" #include "input/pulse.h" #include "input/shmem.h" #include "input/sndio.h" #endif #ifdef __GNUC__ // curses.h or other sources may already define #undef GCC_UNUSED #define GCC_UNUSED __attribute__((unused)) #else #define GCC_UNUSED /* nothing */ #endif // used by sig handler // needs to know output mode in order to clean up terminal int output_mode; // whether we should reload the config or not int should_reload = 0; // whether we should only reload colors or not int reload_colors = 0; // whether we should quit int should_quit = 0; // these variables are used only in main, but making them global // will allow us to not free them on exit without ASan complaining struct config_params p; // general: cleanup void cleanup(void) { if (output_mode == OUTPUT_NCURSES) { #ifdef NCURSES cleanup_terminal_ncurses(); #else ; #endif } else if (output_mode == OUTPUT_NONCURSES) { cleanup_terminal_noncurses(); } else if (output_mode == OUTPUT_SDL) { #ifdef SDL cleanup_sdl(); #else ; #endif #ifdef SDL_GLSL } else if (output_mode == OUTPUT_SDL_GLSL) { cleanup_sdl_glsl(); #else ; #endif } } // general: handle signals void sig_handler(int sig_no) { #ifndef _MSC_VER if (sig_no == SIGUSR1) { should_reload = 1; return; } if (sig_no == SIGUSR2) { reload_colors = 1; return; } #endif cleanup(); if (sig_no == SIGINT) { printf("CTRL-C pressed -- goodbye\n"); } signal(sig_no, SIG_DFL); raise(sig_no); } #ifdef ALSA static bool is_loop_device_for_sure(const char *text) { const char *const LOOPBACK_DEVICE_PREFIX = "hw:Loopback,"; return strncmp(text, LOOPBACK_DEVICE_PREFIX, strlen(LOOPBACK_DEVICE_PREFIX)) == 0; } static bool directory_exists(const char *path) { DIR *const dir = opendir(path); if (dir == NULL) return false; closedir(dir); return true; } #endif float *monstercat_filter(float *bars, int number_of_bars, int waves, double monstercat) { int z; // process [smoothing]: monstercat-style "average" int m_y, de; if (waves > 0) { for (z = 0; z < number_of_bars; z++) { // waves bars[z] = bars[z] / 1.25; // if (bars[z] < 1) bars[z] = 1; for (m_y = z - 1; m_y >= 0; m_y--) { de = z - m_y; bars[m_y] = max(bars[z] - pow(de, 2), bars[m_y]); } for (m_y = z + 1; m_y < number_of_bars; m_y++) { de = m_y - z; bars[m_y] = max(bars[z] - pow(de, 2), bars[m_y]); } } } else if (monstercat > 0) { for (z = 0; z < number_of_bars; z++) { // if (bars[z] < 1)bars[z] = 1; for (m_y = z - 1; m_y >= 0; m_y--) { de = z - m_y; bars[m_y] = max(bars[z] / pow(monstercat * 1.5, de), bars[m_y]); } for (m_y = z + 1; m_y < number_of_bars; m_y++) { de = m_y - z; bars[m_y] = max(bars[z] / pow(monstercat * 1.5, de), bars[m_y]); } } } return bars; } // general: entry point int main(int argc, char **argv) { #ifndef _MSC_VER // general: console title printf("%c]0;%s%c", '\033', PACKAGE, '\007'); #endif // !_MSC_VER // general: handle command-line arguments char configPath[PATH_MAX]; configPath[0] = '\0'; #ifdef _MSC_VER if (!SetConsoleCtrlHandler(sig_handler, TRUE)) { fprintf(stderr, "ERROR: Could not set control handler"); exit(EXIT_FAILURE); } #else // general: handle Ctrl+C struct sigaction action; memset(&action, 0, sizeof(action)); action.sa_handler = &sig_handler; sigaction(SIGINT, &action, NULL); sigaction(SIGTERM, &action, NULL); sigaction(SIGUSR1, &action, NULL); sigaction(SIGUSR2, &action, NULL); #endif char *usage = "\n\ Usage : " PACKAGE " [options]\n\ Visualize audio input in terminal. \n\ \n\ Options:\n\ -p path to config file\n\ -v print version\n\ \n\ Keys:\n\ Up Increase sensitivity\n\ Down Decrease sensitivity\n\ Left Decrease number of bars\n\ Right Increase number of bars\n\ r Reload config\n\ c Reload colors only\n\ f Cycle foreground color\n\ b Cycle background color\n\ q Quit\n\ \n\ as of 0.4.0 all options are specified in config file, see in '/home/username/.config/cava/' \n"; #ifndef _MSC_VER int c; while ((c = getopt(argc, argv, "p:vh")) != -1) { switch (c) { case 'p': // argument: fifo path snprintf(configPath, sizeof(configPath), "%s", optarg); break; case 'h': // argument: print usage printf("%s", usage); return 1; case '?': // argument: print usage printf("%s", usage); return 1; case 'v': // argument: print version printf(PACKAGE " " VERSION "\n"); return 0; default: // argument: no arguments; exit abort(); } } #else if (argc > 1) snprintf(configPath, sizeof(configPath), "%s", argv[1]); #endif // general: main loop while (1) { debug("loading config\n"); // config: load struct error_s error; error.length = 0; if (!load_config(configPath, &p, 0, &error)) { fprintf(stderr, "Error loading config. %s", error.message); exit(EXIT_FAILURE); } int inAtty = 0; output_mode = p.output; #ifndef _MSC_VER if (output_mode == OUTPUT_NCURSES || output_mode == OUTPUT_NONCURSES) { // Check if we're running in a tty if (strncmp(ttyname(0), "/dev/tty", 8) == 0 || strcmp(ttyname(0), "/dev/console") == 0) inAtty = 1; // in macos vitual terminals are called ttys(xyz) and there are no ttys if (strncmp(ttyname(0), "/dev/ttys", 9) == 0) inAtty = 0; if (inAtty) { #ifdef CAVAFONT // checking if cava psf font is installed in FONTDIR FILE *font_file; font_file = fopen(FONTDIR "/" FONTFILE, "r"); if (font_file) { fclose(font_file); #ifdef __FreeBSD__ system("vidcontrol -f " FONTDIR "/" FONTFILE " >/dev/null 2>&1"); #else system("setfont " FONTDIR "/" FONTFILE " >/dev/null 2>&1"); #endif } else { // if not it might still be available, we dont know, must try #ifdef __FreeBSD__ system("vidcontrol -f " FONTFILE " >/dev/null 2>&1"); #else system("setfont " FONTFILE " >/dev/null 2>&1"); #endif } #endif // CAVAFONT #ifndef __FreeBSD__ if (p.disable_blanking) system("setterm -blank 0"); #endif } // We use unicode block characters to draw the bars and // the locale var LANG must be set to use unicode chars. // For some reason this var can't be retrieved with // setlocale(LANG, NULL), so we get it with getenv. // Also we can't set it with setlocale(LANG "") so we // must set LC_ALL instead. // Attempting to set to en_US if not set, if that lang // is not installed and LANG is not set there will be // no output, for more info see #109 #344 if (!getenv("LANG")) setlocale(LC_ALL, "en_US.utf8"); else setlocale(LC_ALL, ""); } #endif // input: init struct audio_data audio; memset(&audio, 0, sizeof(audio)); audio.source = malloc(1 + strlen(p.audio_source)); strcpy(audio.source, p.audio_source); audio.format = -1; audio.rate = 0; audio.samples_counter = 0; audio.channels = 2; audio.IEEE_FLOAT = 0; audio.autoconnect = 0; audio.input_buffer_size = BUFFER_SIZE * audio.channels; audio.cava_buffer_size = audio.input_buffer_size * 8; audio.cava_in = (double *)malloc(audio.cava_buffer_size * sizeof(double)); memset(audio.cava_in, 0, sizeof(int) * audio.cava_buffer_size); audio.threadparams = 0; // most input threads don't adjust the parameters audio.terminate = 0; debug("starting audio thread\n"); pthread_t p_thread; int timeout_counter = 0; int total_bar_height = 0; struct timespec timeout_timer = {.tv_sec = 0, .tv_nsec = 1000000}; int thr_id GCC_UNUSED; pthread_mutex_init(&audio.lock, NULL); switch (p.input) { #ifndef _MSC_VER #ifdef ALSA case INPUT_ALSA: if (is_loop_device_for_sure(audio.source)) { if (directory_exists("/sys/")) { if (!directory_exists("/sys/module/snd_aloop/")) { cleanup(); fprintf(stderr, "Linux kernel module \"snd_aloop\" does not seem to be loaded.\n" "Maybe run \"sudo modprobe snd_aloop\".\n"); exit(EXIT_FAILURE); } } } thr_id = pthread_create(&p_thread, NULL, input_alsa, (void *)&audio); break; #endif case INPUT_FIFO: audio.rate = p.samplerate; audio.format = p.samplebits; thr_id = pthread_create(&p_thread, NULL, input_fifo, (void *)&audio); break; #ifdef PULSE case INPUT_PULSE: audio.format = 16; audio.rate = 44100; if (strcmp(audio.source, "auto") == 0) { getPulseDefaultSink((void *)&audio); } thr_id = pthread_create(&p_thread, NULL, input_pulse, (void *)&audio); break; #endif #ifdef SNDIO case INPUT_SNDIO: audio.format = p.samplebits; audio.rate = p.samplerate; audio.channels = p.channels; audio.threadparams = 1; // Sndio can adjust parameters thr_id = pthread_create(&p_thread, NULL, input_sndio, (void *)&audio); break; #endif #ifdef OSS case INPUT_OSS: audio.format = p.samplebits; audio.rate = p.samplerate; audio.channels = p.channels; audio.threadparams = 1; // OSS can adjust parameters thr_id = pthread_create(&p_thread, NULL, input_oss, (void *)&audio); break; #endif #ifdef JACK case INPUT_JACK: audio.channels = p.channels; audio.autoconnect = p.autoconnect; audio.threadparams = 1; // JACK server provides parameters thr_id = pthread_create(&p_thread, NULL, input_jack, (void *)&audio); break; #endif case INPUT_SHMEM: audio.format = 16; thr_id = pthread_create(&p_thread, NULL, input_shmem, (void *)&audio); break; #ifdef PORTAUDIO case INPUT_PORTAUDIO: audio.format = 16; audio.rate = 44100; thr_id = pthread_create(&p_thread, NULL, input_portaudio, (void *)&audio); break; #endif #ifdef PIPEWIRE case INPUT_PIPEWIRE: audio.format = p.samplebits; audio.rate = p.samplerate; thr_id = pthread_create(&p_thread, NULL, input_pipewire, (void *)&audio); break; #endif #endif #ifdef _MSC_VER case INPUT_WINSCAP: thr_id = pthread_create(&p_thread, NULL, input_winscap, (void *)&audio); break; #endif default: exit(EXIT_FAILURE); // Can't happen. } timeout_counter = 0; while (true) { #ifdef _MSC_VER Sleep(1); #else nanosleep(&timeout_timer, NULL); #endif pthread_mutex_lock(&audio.lock); if ((audio.threadparams == 0) && (audio.format != -1) && (audio.rate != 0)) break; pthread_mutex_unlock(&audio.lock); timeout_counter++; if (timeout_counter > 2000) { cleanup(); fprintf(stderr, "could not get rate and/or format, problems with audio thread? " "quiting...\n"); exit(EXIT_FAILURE); } } pthread_mutex_unlock(&audio.lock); debug("got format: %d and rate %d\n", audio.format, audio.rate); int audio_channels = audio.channels; if (p.upper_cut_off > audio.rate / 2) { cleanup(); fprintf(stderr, "higher cutoff frequency can't be higher than sample rate / 2"); exit(EXIT_FAILURE); } int *bars; int *previous_frame; float *bars_left, *bars_right; double *cava_out; float *bars_raw; int height, lines, width, remainder, fp; int *dimension_bar, *dimension_value; if (p.orientation == ORIENT_LEFT || p.orientation == ORIENT_RIGHT) { dimension_bar = &height; dimension_value = &width; } else { dimension_bar = &width; dimension_value = &height; } #ifdef SDL // output: start sdl mode if (output_mode == OUTPUT_SDL) { init_sdl_window(p.sdl_width, p.sdl_height, p.sdl_x, p.sdl_y, p.sdl_full_screen); height = p.sdl_height; width = p.sdl_width; } #endif #ifdef SDL_GLSL if (output_mode == OUTPUT_SDL_GLSL) { init_sdl_glsl_window(p.sdl_width, p.sdl_height, p.sdl_x, p.sdl_y, p.sdl_full_screen, p.vertex_shader, p.fragment_shader); height = p.sdl_height; width = p.sdl_width; } #endif bool reloadConf = false; while (!reloadConf) { // jumping back to this loop means that you resized the screen // frequencies on x axis require a bar width of four or more if (p.xaxis == FREQUENCY && p.bar_width < 4) p.bar_width = 4; switch (output_mode) { #ifdef NCURSES // output: start ncurses mode case OUTPUT_NCURSES: init_terminal_ncurses(p.color, p.bcolor, p.col, p.bgcol, p.gradient, p.gradient_count, p.gradient_colors, &width, &lines); if (p.xaxis != NONE) lines--; height = lines; *dimension_value *= 8; // we have 8 times as much height due to using 1/8 block characters break; #endif #ifdef SDL // output: get sdl window size case OUTPUT_SDL: init_sdl_surface(&width, &height, p.color, p.bcolor, p.gradient, p.gradient_count, p.gradient_colors); break; #endif #ifdef SDL_GLSL // output: get sdl window size case OUTPUT_SDL_GLSL: init_sdl_glsl_surface(&width, &height, p.color, p.bcolor, p.bar_width, p.bar_spacing, p.gradient, p.gradient_count, p.gradient_colors); break; #endif case OUTPUT_NONCURSES: get_terminal_dim_noncurses(&width, &lines); if (p.xaxis != NONE) lines--; init_terminal_noncurses(inAtty, p.color, p.bcolor, p.col, p.bgcol, p.gradient, p.gradient_count, p.gradient_colors, width, lines, p.bar_width); height = lines * 8; break; #ifndef _MSC_VER case OUTPUT_RAW: case OUTPUT_NORITAKE: if (strcmp(p.raw_target, "/dev/stdout") != 0) { int fptest; // checking if file exists if (access(p.raw_target, F_OK) != -1) { // file exists, testopening in case it's a fifo fptest = open(p.raw_target, O_RDONLY | O_NONBLOCK, 0644); if (fptest == -1) { fprintf(stderr, "could not open file %s for writing\n", p.raw_target); exit(1); } } else { printf("creating fifo %s\n", p.raw_target); if (mkfifo(p.raw_target, 0664) == -1) { fprintf(stderr, "could not create fifo %s\n", p.raw_target); exit(1); } // fifo needs to be open for reading in order to write to it fptest = open(p.raw_target, O_RDONLY | O_NONBLOCK, 0644); } fp = open(p.raw_target, O_WRONLY | O_NONBLOCK | O_CREAT, 0644); } else { fp = fileno(stdout); } if (fp == -1) { fprintf(stderr, "could not open file %s for writing\n", p.raw_target); exit(1); } #ifndef NDEBUG debug("open file %s for writing raw output\n", p.raw_target); #endif // width must be hardcoded for raw output. width = 512; p.bar_width = 1; // not used p.bar_spacing = 1; if (strcmp(p.data_format, "ascii") != 0) { // "binary" or "noritake" height = pow(2, p.bit_format) - 1; } else { height = p.ascii_range; } break; #endif default: exit(EXIT_FAILURE); // Can't happen. } // handle for user setting too many bars if (p.fixedbars) { p.autobars = 0; if (p.fixedbars * p.bar_width + p.fixedbars * p.bar_spacing - p.bar_spacing > width) p.autobars = 1; } // getting numbers of bars int number_of_bars = p.fixedbars; if (p.autobars == 1) number_of_bars = (*dimension_bar + p.bar_spacing) / (p.bar_width + p.bar_spacing); if (number_of_bars <= 1) { number_of_bars = 1; // must have at least 1 bars if (p.stereo) { number_of_bars = 2; // stereo have at least 2 bars } } if (number_of_bars > 512) number_of_bars = 512; // cant have more than 512 bars on 44100 rate int output_channels = 1; if (p.stereo) { // stereo must have even numbers of bars if (audio.channels == 1) { fprintf(stderr, "stereo output configured, but only one channel in audio input.\n"); exit(1); } output_channels = 2; if (number_of_bars % 2 != 0) number_of_bars--; } int raw_number_of_bars = (number_of_bars / output_channels) * audio_channels; if (p.waveform) { raw_number_of_bars = number_of_bars; } // checks if there is stil extra room, will use this to center remainder = (*dimension_bar - number_of_bars * p.bar_width - number_of_bars * p.bar_spacing + p.bar_spacing) / 2; if (remainder < 0) remainder = 0; #ifndef NDEBUG debug("height: %d width: %d dimension_bar: %d dimension_value: %d bars:%d bar width: " "%d remainder: %d\n", height, width, *dimension_bar, *dimension_value, number_of_bars, p.bar_width, remainder); #endif double userEQ_keys_to_bars_ratio; if (p.userEQ_enabled && (number_of_bars / output_channels > 0)) { userEQ_keys_to_bars_ratio = (double)(((double)p.userEQ_keys) / ((double)(number_of_bars / output_channels))); } struct cava_plan *plan = cava_init(number_of_bars / output_channels, audio.rate, audio.channels, p.autosens, p.noise_reduction, p.lower_cut_off, p.upper_cut_off); if (plan->status == -1) { cleanup(); fprintf(stderr, "Error initalizing cava . %s", plan->error_message); exit(EXIT_FAILURE); } bars_left = (float *)malloc(number_of_bars / output_channels * sizeof(float)); bars_right = (float *)malloc(number_of_bars / output_channels * sizeof(float)); memset(bars_left, 0, sizeof(float) * number_of_bars / output_channels); memset(bars_right, 0, sizeof(float) * number_of_bars / output_channels); bars = (int *)malloc(number_of_bars * sizeof(int)); bars_raw = (float *)malloc(number_of_bars * sizeof(float)); previous_frame = (int *)malloc(number_of_bars * sizeof(int)); cava_out = (double *)malloc(number_of_bars * audio.channels / output_channels * sizeof(double)); memset(bars, 0, sizeof(int) * number_of_bars); memset(bars_raw, 0, sizeof(float) * number_of_bars); memset(previous_frame, 0, sizeof(int) * number_of_bars); memset(cava_out, 0, sizeof(double) * number_of_bars * audio.channels / output_channels); int x_axis_info = 0; // process: calculate x axis values if (p.xaxis != NONE) { x_axis_info = 1; double cut_off_frequency; if (output_mode == OUTPUT_NONCURSES) { printf("\r\033[%dB", lines + 1); if (remainder) printf("\033[%dC", remainder); } for (int n = 0; n < number_of_bars; n++) { if (p.stereo) { if (n < number_of_bars / 2) cut_off_frequency = plan->cut_off_frequency[number_of_bars / 2 - 1 - n]; else cut_off_frequency = plan->cut_off_frequency[n - number_of_bars / 2]; } else { cut_off_frequency = plan->cut_off_frequency[n]; } float freq_kilohz = cut_off_frequency / 1000; int freq_floor = cut_off_frequency; if (output_mode == OUTPUT_NCURSES) { #ifdef NCURSES if (cut_off_frequency < 1000) mvprintw(lines, n * (p.bar_width + p.bar_spacing) + remainder, "%-4d", freq_floor); else if (cut_off_frequency > 1000 && cut_off_frequency < 10000) mvprintw(lines, n * (p.bar_width + p.bar_spacing) + remainder, "%.2f", freq_kilohz); else mvprintw(lines, n * (p.bar_width + p.bar_spacing) + remainder, "%.1f", freq_kilohz); #endif } else if (output_mode == OUTPUT_NONCURSES) { if (cut_off_frequency < 1000) printf("%-4d", freq_floor); else if (cut_off_frequency > 1000 && cut_off_frequency < 10000) printf("%.2f", freq_kilohz); else printf("%.1f", freq_kilohz); if (n < number_of_bars - 1) printf("\033[%dC", p.bar_width + p.bar_spacing - 4); } } printf("\r\033[%dA", lines + 1); } bool resizeTerminal = false; int frame_time_msec = (1 / (float)p.framerate) * 1000; struct timespec framerate_timer = {.tv_sec = 0, .tv_nsec = 0}; if (p.framerate <= 1) { framerate_timer.tv_sec = frame_time_msec / 1000; } else { framerate_timer.tv_sec = 0; framerate_timer.tv_nsec = frame_time_msec * 1e6; } #ifdef _MSC_VER LARGE_INTEGER frequency; // ticks per second LARGE_INTEGER t1, t2; // ticks double elapsedTime; QueryPerformanceFrequency(&frequency); #endif // _MSC_VER int sleep_counter = 0; bool silence = false; char ch = '\0'; #ifndef NDEBUG int maxvalue = 0; int minvalue = 0; #endif struct timespec sleep_mode_timer = {.tv_sec = 1, .tv_nsec = 0}; int total_frames = 0; while (!resizeTerminal) { // general: keyboard controls #ifdef NCURSES if (output_mode == OUTPUT_NCURSES) ch = getch(); #endif #ifndef _MSC_VER if (output_mode == OUTPUT_NONCURSES) read(0, &ch, sizeof(ch)); #endif switch (ch) { case 65: // key up p.sens = p.sens * 1.05; break; case 66: // key down p.sens = p.sens * 0.95; break; case 68: // key right p.bar_width++; resizeTerminal = true; break; case 67: // key left if (p.bar_width > 1) p.bar_width--; resizeTerminal = true; break; case 'r': // reload config should_reload = 1; break; case 'c': // reload colors reload_colors = 1; break; case 'f': // change forground color if (p.col < 7) p.col++; else p.col = 0; resizeTerminal = true; break; case 'b': // change backround color if (p.bgcol < 7) p.bgcol++; else p.bgcol = 0; resizeTerminal = true; break; case 'q': should_reload = 1; should_quit = 1; } ch = 0; if (should_reload) { reloadConf = true; resizeTerminal = true; should_reload = 0; } if (reload_colors) { struct error_s error; error.length = 0; if (!load_config(configPath, (void *)&p, 1, &error)) { cleanup(); fprintf(stderr, "Error loading config. %s", error.message); exit(EXIT_FAILURE); } resizeTerminal = true; reload_colors = 0; } #ifndef NDEBUG // clear(); #ifndef _MSC_VER refresh(); #endif #endif // process: check if input is present silence = true; for (int n = 0; n < audio.input_buffer_size * 4; n++) { if (audio.cava_in[n]) { silence = false; break; } } #ifndef _MSC_VER if (output_mode != OUTPUT_SDL) { if (p.sleep_timer) { if (silence && sleep_counter <= p.framerate * p.sleep_timer) sleep_counter++; else if (!silence) sleep_counter = 0; if (sleep_counter > p.framerate * p.sleep_timer) { #ifndef NDEBUG printw("no sound detected for 30 sec, going to sleep mode\n"); #endif nanosleep(&sleep_mode_timer, NULL); continue; } } } #endif // !_MSC_VER // process: execute cava pthread_mutex_lock(&audio.lock); if (p.waveform) { for (int n = 0; n < audio.samples_counter; n++) { for (int i = number_of_bars - 1; i > 0; i--) { cava_out[i] = cava_out[i - 1]; } if (audio_channels == 2) { cava_out[0] = p.sens * (audio.cava_in[n] / 2 + audio.cava_in[n + 1] / 2); n++; } else { cava_out[0] = p.sens * audio.cava_in[n]; } } } else { cava_execute(audio.cava_in, audio.samples_counter, cava_out, plan); } if (audio.samples_counter > 0) { audio.samples_counter = 0; } pthread_mutex_unlock(&audio.lock); for (int n = 0; n < raw_number_of_bars; n++) { if (!p.waveform) { cava_out[n] *= p.sens; } else { if (cava_out[n] > 1.0) p.sens *= 0.999; else p.sens *= 1.00001; cava_out[n] = (cava_out[n] + 1.0) / 2.0; } if (output_mode == OUTPUT_SDL_GLSL) { if (cava_out[n] > 1.0) cava_out[n] = 1.0; else if (cava_out[n] < 0.0) cava_out[n] = 0.0; } else { cava_out[n] *= *dimension_value; } if (p.waveform) { bars_raw[n] = cava_out[n]; } } if (!p.waveform) { if (audio_channels == 2) { for (int n = 0; n < number_of_bars / output_channels; n++) { if (p.userEQ_enabled) cava_out[n] *= p.userEQ[(int)floor(((double)n) * userEQ_keys_to_bars_ratio)]; bars_left[n] = cava_out[n]; } for (int n = 0; n < number_of_bars / output_channels; n++) { if (p.userEQ_enabled) cava_out[n + number_of_bars / output_channels] *= p.userEQ[(int)floor(((double)n) * userEQ_keys_to_bars_ratio)]; bars_right[n] = cava_out[n + number_of_bars / output_channels]; } } else { for (int n = 0; n < number_of_bars; n++) { if (p.userEQ_enabled) cava_out[n] *= p.userEQ[(int)floor(((double)n) * userEQ_keys_to_bars_ratio)]; bars_raw[n] = cava_out[n]; } } // process [filter] if (p.monstercat) { if (audio_channels == 2) { bars_left = monstercat_filter( bars_left, number_of_bars / output_channels, p.waves, p.monstercat); bars_right = monstercat_filter(bars_right, number_of_bars / output_channels, p.waves, p.monstercat); } else { bars_raw = monstercat_filter(bars_raw, number_of_bars, p.waves, p.monstercat); } } if (audio_channels == 2) { if (p.stereo) { // mirroring stereo channels for (int n = 0; n < number_of_bars; n++) { if (n < number_of_bars / 2) { if (p.reverse) { bars_raw[n] = bars_left[n]; } else { bars_raw[n] = bars_left[number_of_bars / 2 - n - 1]; } } else { if (p.reverse) { bars_raw[n] = bars_right[number_of_bars - n - 1]; } else { bars_raw[n] = bars_right[n - number_of_bars / 2]; } } } } else { // stereo mono output for (int n = 0; n < number_of_bars; n++) { if (p.reverse) { if (p.mono_opt == AVERAGE) { bars_raw[number_of_bars - n - 1] = (bars_left[n] + bars_right[n]) / 2; } else if (p.mono_opt == LEFT) { bars_raw[number_of_bars - n - 1] = bars_left[n]; } else if (p.mono_opt == RIGHT) { bars_raw[number_of_bars - n - 1] = bars_right[n]; } } else { if (p.mono_opt == AVERAGE) { bars_raw[n] = (bars_left[n] + bars_right[n]) / 2; } else if (p.mono_opt == LEFT) { bars_raw[n] = bars_left[n]; } else if (p.mono_opt == RIGHT) { bars_raw[n] = bars_right[n]; } } } } } } #ifdef SDL_GLSL int re_paint = 0; #endif for (int n = 0; n < number_of_bars; n++) { bars[n] = bars_raw[n]; // show idle bar heads if (output_mode != OUTPUT_RAW && output_mode != OUTPUT_NORITAKE && bars[n] < 1 && p.waveform == 0 && p.show_idle_bar_heads == 1) bars[n] = 1; #ifdef SDL_GLSL if (output_mode == OUTPUT_SDL_GLSL) bars[n] = bars_raw[n] * 1000; // values are 0-1, only used to check for changes if (bars[n] != previous_frame[n]) re_paint = 1; #endif #ifndef NDEBUG mvprintw(n, 0, "%d: f:%f->%f (%d->%d), eq:\ %15e, peak:%d \n", n, plan->cut_off_frequency[n], plan->cut_off_frequency[n + 1], plan->FFTbuffer_lower_cut_off[n], plan->FFTbuffer_upper_cut_off[n], plan->eq[n], bars[n]); if (bars[n] < minvalue) { minvalue = bars[n]; debug("min value: %d\n", minvalue); // checking maxvalue 10000 } if (bars[n] > maxvalue) { maxvalue = bars[n]; } if (bars[n] < 0) { debug("negative bar value!! %d\n", bars[n]); // exit(EXIT_FAILURE); // Can't happen. } #endif } #ifndef NDEBUG mvprintw(number_of_bars + 1, 0, "sensitivity %.10e", p.sens); mvprintw(number_of_bars + 2, 0, "min value: %d\n", minvalue); // checking maxvalue 10000 mvprintw(number_of_bars + 3, 0, "max value: %d\n", maxvalue); // checking maxvalue 10000 #ifndef _MSC_VER (void)x_axis_info; #endif // !_MSC_VER #endif // output: draw processed input #ifdef NDEBUG if (p.sync_updates) { printf("\033P=1s\033\\"); fflush(stdout); } int rc; #ifdef _MSC_VER QueryPerformanceCounter(&t1); #endif switch (output_mode) { #ifdef SDL case OUTPUT_SDL: rc = draw_sdl(number_of_bars, p.bar_width, p.bar_spacing, remainder, *dimension_value, bars, previous_frame, frame_time_msec, p.orientation, p.gradient); break; #endif #ifdef SDL_GLSL case OUTPUT_SDL_GLSL: rc = draw_sdl_glsl(number_of_bars, bars_raw, frame_time_msec, re_paint, p.continuous_rendering); break; #endif case OUTPUT_NONCURSES: rc = draw_terminal_noncurses(inAtty, lines, width, number_of_bars, p.bar_width, p.bar_spacing, remainder, bars, previous_frame, p.gradient, x_axis_info); break; case OUTPUT_NCURSES: #ifdef NCURSES rc = draw_terminal_ncurses(inAtty, *dimension_value / 8, *dimension_bar, number_of_bars, p.bar_width, p.bar_spacing, remainder, bars, previous_frame, p.gradient, x_axis_info, p.orientation); break; #endif #ifndef _MSC_VER case OUTPUT_RAW: rc = print_raw_out(number_of_bars, fp, p.raw_format, p.bit_format, p.ascii_range, p.bar_delim, p.frame_delim, bars); break; case OUTPUT_NORITAKE: rc = print_ntk_out(number_of_bars, fp, p.bit_format, p.bar_width, p.bar_spacing, p.bar_height, bars); break; #endif // !_MSC_VER default: exit(EXIT_FAILURE); // Can't happen. } if (p.sync_updates) { printf("\033P=2s\033\\"); fflush(stdout); } // terminal has been resized breaking to recalibrating values if (rc == -1) resizeTerminal = true; if (rc == -2) { resizeTerminal = true; reloadConf = true; should_quit = true; } #endif memcpy(previous_frame, bars, number_of_bars * sizeof(int)); // checking if audio thread has exited unexpectedly pthread_mutex_lock(&audio.lock); if (audio.terminate == 1) { cleanup(); fprintf(stderr, "Audio thread exited unexpectedly. %s\n", audio.error_message); exit(EXIT_FAILURE); } pthread_mutex_unlock(&audio.lock); #ifdef _MSC_VER QueryPerformanceCounter(&t2); elapsedTime = (t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart; int fps_sync_time = frame_time_msec; if (elapsedTime < 1.0) fps_sync_time = frame_time_msec; else if ((int)elapsedTime > frame_time_msec) fps_sync_time = 0; else fps_sync_time = (frame_time_msec - (int)elapsedTime) / 2; #endif if (output_mode != OUTPUT_SDL && output_mode != OUTPUT_SDL_GLSL) { #ifdef _MSC_VER Sleep(fps_sync_time); #else nanosleep(&framerate_timer, NULL); #endif } if (p.draw_and_quit > 0) { total_frames++; if (total_frames >= p.draw_and_quit) { for (int n = 0; n < number_of_bars; n++) { if (output_mode != OUTPUT_RAW && output_mode != OUTPUT_NORITAKE && bars[n] == 1) { bars[n] = 0; } total_bar_height += bars[n]; } resizeTerminal = true; reloadConf = true; should_quit = true; break; } } } // resize terminal cava_destroy(plan); free(plan); if (audio_channels == 2) { free(bars_left); free(bars_right); } free(cava_out); free(bars); free(bars_raw); free(previous_frame); } // reloading config //**telling audio thread to terminate**// pthread_mutex_lock(&audio.lock); audio.terminate = 1; pthread_mutex_unlock(&audio.lock); pthread_join(p_thread, NULL); if (p.userEQ_enabled) free(p.userEQ); free(audio.source); free(audio.cava_in); cleanup(); if (should_quit) { if (p.zero_test && total_bar_height > 0) { fprintf(stderr, "Test mode: expected total bar height to be zero, but was: %d\n", total_bar_height); return EXIT_FAILURE; } else if (p.non_zero_test && total_bar_height == 0) { fprintf(stderr, "Test mode: expected total bar height to be non-zero, but was zero\n"); return EXIT_FAILURE; } else { return EXIT_SUCCESS; } } // fclose(fp); } } cava-0.10.2/cava.psf000066400000000000000000000113461462072613000141360ustar00rootroot00000000000000rµJ† ~BBBBBBBB~ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ$$ÿÿÿÿÿÿçÛÛçÿÿÿÿÿÿ 8DDDD88DDDD8|>"> À~B~BBBBBBD€’T8î8T’ÀðüÿüðÀ?ÿ?8TT8$$$$$$$$$~’’’’r8D@0HDD$D8~~~~8TT8|8TT8þ @þ@ @@@@@~$BÿB$88||þþþþ||88$$$$$$~$$~$$$|’|’|d”h ,RL$$0JDDD:   $~$| ~ @@8  @ ~~@  @BBB>@@@|BBBBB|BBBBB>BBBBB><@@@|BBBBBB08 DD8@@@BDHpHDB08ü’’’’’’|BBBBBBBBBBB>^`@@@@@>@@<||BBBBBB>BBB$$‚‚’’’’|BB$$BBBBBBBB><~ @~   00b’Œ(D‚‚‚‚þÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿDDD$ 2L2L >  |`$$$<|(((((((((((((((($$BBB><@@|BBBBB|BBBBBB?>BBBBB><$BBBBBB>BDHpHDB"""""B‚ƪ’‚‚‚BBB~BBBBB>"B|BBBBB|@@@<’’T8T’’8DDH|BBBB|@@xDDDx‚‚òŠŠŠò` <"""<ÿÿÿÿ(((((((/((((((((((((((/ ?? /(((((((((((((ïÿÿï(((((((((((((/ /(((((((ÿÿ((((((ïï(((((((ÿÿ(((((((ÿ88DD88(((((((?BBBB> "B|BBBB|@@@@<’’’T8T’’’’|BBB|BBBB|@@@|BBBBB|‚‚‚òŠŠŠŠŠòÀ@@|BBBBB|�ÿÿÿÿÿÿÿÿÿâ—‹ÿâ—™ÿ♂ÿ♀ÿ♪ÿ♫♬ÿ☼ÿâ–¶â–ºÿ◀◄ÿ↕ÿ‼ÿ¶ÿ§ÿâ–¬ÿ↨ÿ↑ÿ↓ÿ→ÿâ†ÿ∟ÿ↔ÿâ–²ÿâ–¼ÿ ÿ!ÿ"ÿ#ÿ$ÿ%ÿ&ÿ'ÿ(ÿ)ÿ*ÿ+ÿ,ÿ-ÿ.ÿ/ÿ0ÿ1ÿ2ÿ3ÿ4ÿ5ÿ6ÿ7ÿ8ÿ9ÿ:ÿ;ÿ<ÿ=ÿ>ÿ?ÿ@ÿÿÿÿÿÿÿÿÿIÿJÿKÿLÿMÿNÿOÿPÿQÿRÿSÿTÿUÿVÿWÿXÿYÿZÿ[ÿ\ÿ]ÿ^ÿ_ÿ`ÿaÿbÿcÿdÿeÿfÿgÿhÿiÿjÿkÿlÿmÿnÿoÿpÿqÿrÿsÿtÿuÿvÿwÿxÿyÿzÿ{ÿ|ÿ}ÿ~ÿ⌂ÿ│ÿÿÿÿÿÿÿÿÿ√ÿ≈ÿ≤ÿ≥ÿ ÿ⌡ÿ°ÿ²ÿ·ÿ÷ÿâ•‘ÿÑ‘ÿÑ–ÿÑ—ÿâ•—ÿâ•›ÿÒ‘ÿâ•ÿâ•¡ÿÐÿЄÿâ•£ÿ©ÿÑŽÿаÿбÿцÿдÿеÿÑ„ÿгÿÑ…ÿиÿйÿкÿлÿмÿнÿоÿпπÿÑÿÑ€ÿÑÿÑ‚ÿуÿжÿвÿÑŒÿÑ‹ÿзÿшÿÑÿщÿчÿÑŠÿâ””ÿâ”´ÿ┬ÿ├ÿ─ÿ┼ÿ╞ÿ╟ÿ╚ÿâ•”ÿâ•©ÿ╦ÿâ• ÿâ•ÿ╬ÿâ•§ÿ╨ÿІÿЇÿâ•™ÿ╘ÿâ•’ÿÑ”ÿÒÿ╪ÿ┘ÿ┌ÿâ–ˆÿâ–„ÿâ–Œÿâ–ÿâ–€ÿЮÿÐÿБÿЦÿДÿЕÿФÿГÿÐ¥ÿИÿЙÿКÿЛÿМÿÐÿОÿПÿЯÿРÿСÿТÿУÿЖÿÐ’ÿЬÿЫÿЗÿШÿЭÿЩÿЧÿЪÿcava-0.10.2/cava_win/000077500000000000000000000000001462072613000142745ustar00rootroot00000000000000cava-0.10.2/cava_win/INSTALL.txt000066400000000000000000000005741462072613000161510ustar00rootroot00000000000000You will need the following dlls: * fftw3.dll * glew.dll * libpthread.dll * SDL2.dll (should be added in the .zip bin package when/if I make one) Install Visual C++ Redistributable for Visual Studio 2012 (maybe also a newer one) was needed when I first ran it. Not sure why we need that old one. copy the config file and the shaders folder to `C:\Users\"username"\.config\cava`cava-0.10.2/cava_win/README.md000066400000000000000000000006051462072613000155540ustar00rootroot00000000000000# cava on windows All dependencies should install themselves via the NuGet thing: * SDL2 * FFTW * pthreads * glew include paths are configured relatively to the project so linking and including should work automatically with the nugets, but might stop working at some point. The Visual C++ Redistributable for Visual Studio 2012 (maybe also a newer one) was needed when I first ran it. cava-0.10.2/cava_win/cava/000077500000000000000000000000001462072613000152065ustar00rootroot00000000000000cava-0.10.2/cava_win/cava/cava.vcxproj000066400000000000000000000274611462072613000175470ustar00rootroot00000000000000 Debug Win32 Release Win32 Debug x64 Release x64 16.0 Win32Proj {b4567c59-36a3-4119-80a9-bfcd2feb89d4} cava 10.0 Application true v143 Unicode Application false v143 true Unicode Application true v143 MultiByte false Application false v143 true MultiByte Level3 true WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true Console true Level3 true true true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true Console true true true Level3 true _DEBUG;_CONSOLE;%(PreprocessorDefinitions);SDL;SDL_GLSL;_CRT_SECURE_NO_WARNINGS;_TIMESPEC_DEFINED;NDEBUG true $(SolutionDir)..\;%(AdditionalIncludeDirectories) Console true opengl32.lib;$(SolutionDir)\packages\glew.1.9.0.1\build\native\lib\v110\x64\Debug\dynamic\glew.lib;$(SolutionDir)\packages\pthreads.2.9.1.4\build\native\lib\v110\x64\Debug\dynamic\cdecl\libpthread.lib;%(AdditionalDependencies) %(AdditionalLibraryDirectories) Level3 true true true NDEBUG;_CONSOLE;%(PreprocessorDefinitions);SDL;SDL_GLSL;_CRT_SECURE_NO_WARNINGS;_TIMESPEC_DEFINED;NDEBUG true $(SolutionDir)..\;%(AdditionalIncludeDirectories) Console true true true opengl32.lib;$(SolutionDir)\packages\glew.1.9.0.1\build\native\lib\v110\x64\Release\dynamic\glew.lib;$(SolutionDir)\packages\pthreads.2.9.1.4\build\native\lib\v110\x64\Release\dynamic\cdecl\libpthread.lib;%(AdditionalDependencies) %(AdditionalLibraryDirectories) This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. cava-0.10.2/cava_win/cava/cava.vcxproj.user000066400000000000000000000016671462072613000205240ustar00rootroot00000000000000 PATH=%PATH%;$(SolutionDir)packages\glew.redist.1.9.0.1\build\native\bin\v110\x64\Release\dynamic\;$(SolutionDir)packages\pthreads.redist.2.9.1.4\build\native\bin\v110\x64\Release\dynamic\cdecl\ WindowsLocalDebugger PATH=%PATH%;$(SolutionDir)packages\glew.redist.1.9.0.1\build\native\bin\v110\x64\Release\dynamic\;$(SolutionDir)packages\pthreads.redist.2.9.1.4\build\native\bin\v110\x64\Release\dynamic\cdecl\ WindowsLocalDebugger cava-0.10.2/cava_win/cava/packages.config000066400000000000000000000010721462072613000201530ustar00rootroot00000000000000 cava-0.10.2/cava_win/cava_win.sln000066400000000000000000000025721462072613000166070ustar00rootroot00000000000000 Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.3.32929.385 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cava", "cava\cava.vcxproj", "{B4567C59-36A3-4119-80A9-BFCD2FEB89D4}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {B4567C59-36A3-4119-80A9-BFCD2FEB89D4}.Debug|x64.ActiveCfg = Debug|x64 {B4567C59-36A3-4119-80A9-BFCD2FEB89D4}.Debug|x64.Build.0 = Debug|x64 {B4567C59-36A3-4119-80A9-BFCD2FEB89D4}.Debug|x86.ActiveCfg = Debug|Win32 {B4567C59-36A3-4119-80A9-BFCD2FEB89D4}.Debug|x86.Build.0 = Debug|Win32 {B4567C59-36A3-4119-80A9-BFCD2FEB89D4}.Release|x64.ActiveCfg = Release|x64 {B4567C59-36A3-4119-80A9-BFCD2FEB89D4}.Release|x64.Build.0 = Release|x64 {B4567C59-36A3-4119-80A9-BFCD2FEB89D4}.Release|x86.ActiveCfg = Release|Win32 {B4567C59-36A3-4119-80A9-BFCD2FEB89D4}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {48C25AC5-A81D-449F-A6CE-8A0CEC1EE695} EndGlobalSection EndGlobal cava-0.10.2/cavacore.c000066400000000000000000000533641462072613000144470ustar00rootroot00000000000000#include "cavacore.h" #ifndef M_PI #define M_PI 3.1415926535897932385 #endif #include #include #include #include struct cava_plan *cava_init(int number_of_bars, unsigned int rate, int channels, int autosens, double noise_reduction, int low_cut_off, int high_cut_off) { struct cava_plan *p = malloc(sizeof(struct cava_plan)); p->status = 0; // sanity checks: if (channels < 1 || channels > 2) { snprintf(p->error_message, 1024, "cava_init called with illegal number of channels: %d, number of channels " "supported are " "1 and 2", channels); p->status = -1; return p; } if (rate < 1 || rate > 384000) { snprintf(p->error_message, 1024, "cava_init called with illegal sample rate: %d\n", rate); p->status = -1; return p; } int treble_buffer_size = 128; if (rate > 8125 && rate <= 16250) treble_buffer_size *= 2; else if (rate > 16250 && rate <= 32500) treble_buffer_size *= 4; else if (rate > 32500 && rate <= 75000) treble_buffer_size *= 8; else if (rate > 75000 && rate <= 150000) treble_buffer_size *= 16; else if (rate > 150000 && rate <= 300000) treble_buffer_size *= 32; else if (rate > 300000) treble_buffer_size *= 64; if (number_of_bars < 1) { snprintf(p->error_message, 1024, "cava_init called with illegal number of bars: %d, number of channels must be " "positive integer\n", number_of_bars); p->status = -1; return p; } if (number_of_bars > treble_buffer_size / 2 + 1) { snprintf(p->error_message, 1024, "cava_init called with illegal number of bars: %d, for %d sample rate number of " "bars can't be more than %d\n", number_of_bars, rate, treble_buffer_size / 2 + 1); p->status = -1; return p; } if (low_cut_off < 1 || high_cut_off < 1) { snprintf(p->error_message, 1024, "low_cut_off must be a positive value\n"); p->status = -1; return p; } if (low_cut_off >= high_cut_off) { snprintf(p->error_message, 1024, "high_cut_off must be a higher than low_cut_off\n"); p->status = -1; return p; } if ((unsigned int)high_cut_off > rate / 2) { snprintf(p->error_message, 1024, "high_cut_off can't be higher than sample rate / 2. (Nyquist Sampling Theorem)\n"); p->status = -1; return p; } p->number_of_bars = number_of_bars; p->audio_channels = channels; p->rate = rate; p->autosens = 1; p->sens_init = 1; p->sens = 1.0; p->autosens = autosens; p->framerate = 75; p->frame_skip = 1; p->noise_reduction = noise_reduction; p->FFTbassbufferSize = treble_buffer_size * 8; p->FFTmidbufferSize = treble_buffer_size * 4; p->FFTtreblebufferSize = treble_buffer_size; p->input_buffer_size = p->FFTbassbufferSize * channels; p->input_buffer = (double *)malloc(p->input_buffer_size * sizeof(double)); p->FFTbuffer_lower_cut_off = (int *)malloc((number_of_bars + 1) * sizeof(int)); p->FFTbuffer_upper_cut_off = (int *)malloc((number_of_bars + 1) * sizeof(int)); p->eq = (double *)malloc((number_of_bars + 1) * sizeof(double)); p->cut_off_frequency = (float *)malloc((number_of_bars + 1) * sizeof(float)); p->cava_fall = (double *)malloc(number_of_bars * channels * sizeof(double)); p->cava_mem = (double *)malloc(number_of_bars * channels * sizeof(double)); p->cava_peak = (double *)malloc(number_of_bars * channels * sizeof(double)); p->prev_cava_out = (double *)malloc(number_of_bars * channels * sizeof(double)); // Hann Window calculate multipliers p->bass_multiplier = (double *)malloc(p->FFTbassbufferSize * sizeof(double)); p->mid_multiplier = (double *)malloc(p->FFTmidbufferSize * sizeof(double)); p->treble_multiplier = (double *)malloc(p->FFTtreblebufferSize * sizeof(double)); for (int i = 0; i < p->FFTbassbufferSize; i++) { p->bass_multiplier[i] = 0.5 * (1 - cos(2 * M_PI * i / (p->FFTbassbufferSize - 1))); } for (int i = 0; i < p->FFTmidbufferSize; i++) { p->mid_multiplier[i] = 0.5 * (1 - cos(2 * M_PI * i / (p->FFTmidbufferSize - 1))); } for (int i = 0; i < p->FFTtreblebufferSize; i++) { p->treble_multiplier[i] = 0.5 * (1 - cos(2 * M_PI * i / (p->FFTtreblebufferSize - 1))); } // BASS p->in_bass_l = fftw_alloc_real(p->FFTbassbufferSize); p->in_bass_l_raw = fftw_alloc_real(p->FFTbassbufferSize); p->out_bass_l = fftw_alloc_complex(p->FFTbassbufferSize / 2 + 1); p->p_bass_l = fftw_plan_dft_r2c_1d(p->FFTbassbufferSize, p->in_bass_l, p->out_bass_l, FFTW_MEASURE); // MID p->in_mid_l = fftw_alloc_real(p->FFTmidbufferSize); p->in_mid_l_raw = fftw_alloc_real(p->FFTmidbufferSize); p->out_mid_l = fftw_alloc_complex(p->FFTmidbufferSize / 2 + 1); p->p_mid_l = fftw_plan_dft_r2c_1d(p->FFTmidbufferSize, p->in_mid_l, p->out_mid_l, FFTW_MEASURE); // TREBLE p->in_treble_l = fftw_alloc_real(p->FFTtreblebufferSize); p->in_treble_l_raw = fftw_alloc_real(p->FFTtreblebufferSize); p->out_treble_l = fftw_alloc_complex(p->FFTtreblebufferSize / 2 + 1); p->p_treble_l = fftw_plan_dft_r2c_1d(p->FFTtreblebufferSize, p->in_treble_l, p->out_treble_l, FFTW_MEASURE); memset(p->in_bass_l, 0, sizeof(double) * p->FFTbassbufferSize); memset(p->in_mid_l, 0, sizeof(double) * p->FFTmidbufferSize); memset(p->in_treble_l, 0, sizeof(double) * p->FFTtreblebufferSize); memset(p->in_bass_l_raw, 0, sizeof(double) * p->FFTbassbufferSize); memset(p->in_mid_l_raw, 0, sizeof(double) * p->FFTmidbufferSize); memset(p->in_treble_l_raw, 0, sizeof(double) * p->FFTtreblebufferSize); memset(p->out_bass_l, 0, (p->FFTbassbufferSize / 2 + 1) * sizeof(fftw_complex)); memset(p->out_mid_l, 0, (p->FFTmidbufferSize / 2 + 1) * sizeof(fftw_complex)); memset(p->out_treble_l, 0, (p->FFTtreblebufferSize / 2 + 1) * sizeof(fftw_complex)); if (p->audio_channels == 2) { // BASS p->in_bass_r = fftw_alloc_real(p->FFTbassbufferSize); p->in_bass_r_raw = fftw_alloc_real(p->FFTbassbufferSize); p->out_bass_r = fftw_alloc_complex(p->FFTbassbufferSize / 2 + 1); p->p_bass_r = fftw_plan_dft_r2c_1d(p->FFTbassbufferSize, p->in_bass_r, p->out_bass_r, FFTW_MEASURE); // MID p->in_mid_r = fftw_alloc_real(p->FFTmidbufferSize); p->in_mid_r_raw = fftw_alloc_real(p->FFTmidbufferSize); p->out_mid_r = fftw_alloc_complex(p->FFTmidbufferSize / 2 + 1); p->p_mid_r = fftw_plan_dft_r2c_1d(p->FFTmidbufferSize, p->in_mid_r, p->out_mid_r, FFTW_MEASURE); // TREBLE p->in_treble_r = fftw_alloc_real(p->FFTtreblebufferSize); p->in_treble_r_raw = fftw_alloc_real(p->FFTtreblebufferSize); p->out_treble_r = fftw_alloc_complex(p->FFTtreblebufferSize / 2 + 1); p->p_treble_r = fftw_plan_dft_r2c_1d(p->FFTtreblebufferSize, p->in_treble_r, p->out_treble_r, FFTW_MEASURE); memset(p->in_bass_r, 0, sizeof(double) * p->FFTbassbufferSize); memset(p->in_mid_r, 0, sizeof(double) * p->FFTmidbufferSize); memset(p->in_treble_r, 0, sizeof(double) * p->FFTtreblebufferSize); memset(p->in_bass_r_raw, 0, sizeof(double) * p->FFTbassbufferSize); memset(p->in_mid_r_raw, 0, sizeof(double) * p->FFTmidbufferSize); memset(p->in_treble_r_raw, 0, sizeof(double) * p->FFTtreblebufferSize); memset(p->out_bass_r, 0, (p->FFTbassbufferSize / 2 + 1) * sizeof(fftw_complex)); memset(p->out_mid_r, 0, (p->FFTmidbufferSize / 2 + 1) * sizeof(fftw_complex)); memset(p->out_treble_r, 0, (p->FFTtreblebufferSize / 2 + 1) * sizeof(fftw_complex)); } memset(p->input_buffer, 0, sizeof(double) * p->input_buffer_size); memset(p->cava_fall, 0, sizeof(int) * number_of_bars * channels); memset(p->cava_mem, 0, sizeof(double) * number_of_bars * channels); memset(p->cava_peak, 0, sizeof(double) * number_of_bars * channels); memset(p->prev_cava_out, 0, sizeof(double) * number_of_bars * channels); // process: calculate cutoff frequencies and eq int lower_cut_off = low_cut_off; int upper_cut_off = high_cut_off; int bass_cut_off = 100; int treble_cut_off = 500; // calculate frequency constant (used to distribute bars across the frequency band) double frequency_constant = log10((float)lower_cut_off / (float)upper_cut_off) / (1 / ((float)p->number_of_bars + 1) - 1); float *relative_cut_off = (float *)malloc((p->number_of_bars + 1) * sizeof(float)); p->bass_cut_off_bar = -1; p->treble_cut_off_bar = -1; int first_bar = 1; int first_treble_bar = 0; int *bar_buffer = (int *)malloc((p->number_of_bars + 1) * sizeof(int)); for (int n = 0; n < p->number_of_bars + 1; n++) { double bar_distribution_coefficient = frequency_constant * (-1); bar_distribution_coefficient += ((float)n + 1) / ((float)p->number_of_bars + 1) * frequency_constant; p->cut_off_frequency[n] = upper_cut_off * pow(10, bar_distribution_coefficient); if (n > 0) { if (p->cut_off_frequency[n - 1] >= p->cut_off_frequency[n] && p->cut_off_frequency[n - 1] > bass_cut_off) p->cut_off_frequency[n] = p->cut_off_frequency[n - 1] + (p->cut_off_frequency[n - 1] - p->cut_off_frequency[n - 2]); } relative_cut_off[n] = p->cut_off_frequency[n] / (p->rate / 2); // remember nyquist!, per my calculations this should be rate/2 // and nyquist freq in M/2 but testing shows it is not... // or maybe the nq freq is in M/4 p->eq[n] = pow(p->cut_off_frequency[n], 1); // the numbers that come out of the FFT are verry high // the EQ is used to "normalize" them by dividing with this very huge number p->eq[n] /= pow(2, 29); p->eq[n] /= log2(p->FFTbassbufferSize); if (p->cut_off_frequency[n] < bass_cut_off) { // BASS bar_buffer[n] = 1; p->FFTbuffer_lower_cut_off[n] = relative_cut_off[n] * (p->FFTbassbufferSize / 2); p->bass_cut_off_bar++; p->treble_cut_off_bar++; if (p->bass_cut_off_bar > 0) first_bar = 0; if (p->FFTbuffer_lower_cut_off[n] > p->FFTbassbufferSize / 2) { p->FFTbuffer_lower_cut_off[n] = p->FFTbassbufferSize / 2; } } else if (p->cut_off_frequency[n] > bass_cut_off && p->cut_off_frequency[n] < treble_cut_off) { // MID bar_buffer[n] = 2; p->FFTbuffer_lower_cut_off[n] = relative_cut_off[n] * (p->FFTmidbufferSize / 2); p->treble_cut_off_bar++; if ((p->treble_cut_off_bar - p->bass_cut_off_bar) == 1) { first_bar = 1; if (n > 0) { p->FFTbuffer_upper_cut_off[n - 1] = relative_cut_off[n] * (p->FFTbassbufferSize / 2); } } else { first_bar = 0; } if (p->FFTbuffer_lower_cut_off[n] > p->FFTmidbufferSize / 2) { p->FFTbuffer_lower_cut_off[n] = p->FFTmidbufferSize / 2; } } else { // TREBLE bar_buffer[n] = 3; p->FFTbuffer_lower_cut_off[n] = relative_cut_off[n] * (p->FFTtreblebufferSize / 2); first_treble_bar++; if (first_treble_bar == 1) { first_bar = 1; if (n > 0) { p->FFTbuffer_upper_cut_off[n - 1] = relative_cut_off[n] * (p->FFTmidbufferSize / 2); } } else { first_bar = 0; } if (p->FFTbuffer_lower_cut_off[n] > p->FFTtreblebufferSize / 2) { p->FFTbuffer_lower_cut_off[n] = p->FFTtreblebufferSize / 2; } } if (n > 0) { if (!first_bar) { p->FFTbuffer_upper_cut_off[n - 1] = p->FFTbuffer_lower_cut_off[n] - 1; // pushing the spectrum up if the exponential function gets "clumped" in the // bass and caluclating new cut off frequencies if (p->FFTbuffer_lower_cut_off[n] <= p->FFTbuffer_lower_cut_off[n - 1]) { // check if there is room for more first int room_for_more = 0; if (bar_buffer[n] == 1) { if (p->FFTbuffer_lower_cut_off[n - 1] + 1 < p->FFTbassbufferSize / 2 + 1) room_for_more = 1; } else if (bar_buffer[n] == 2) { if (p->FFTbuffer_lower_cut_off[n - 1] + 1 < p->FFTmidbufferSize / 2 + 1) room_for_more = 1; } else if (bar_buffer[n] == 3) { if (p->FFTbuffer_lower_cut_off[n - 1] + 1 < p->FFTtreblebufferSize / 2 + 1) room_for_more = 1; } if (room_for_more) { // push the spectrum up p->FFTbuffer_lower_cut_off[n] = p->FFTbuffer_lower_cut_off[n - 1] + 1; p->FFTbuffer_upper_cut_off[n - 1] = p->FFTbuffer_lower_cut_off[n] - 1; // calculate new cut off frequency if (bar_buffer[n] == 1) relative_cut_off[n] = (float)(p->FFTbuffer_lower_cut_off[n]) / ((float)p->FFTbassbufferSize / 2); else if (bar_buffer[n] == 2) relative_cut_off[n] = (float)(p->FFTbuffer_lower_cut_off[n]) / ((float)p->FFTmidbufferSize / 2); else if (bar_buffer[n] == 3) relative_cut_off[n] = (float)(p->FFTbuffer_lower_cut_off[n]) / ((float)p->FFTtreblebufferSize / 2); p->cut_off_frequency[n] = relative_cut_off[n] * ((float)p->rate / 2); } } } else { if (p->FFTbuffer_upper_cut_off[n - 1] <= p->FFTbuffer_lower_cut_off[n - 1]) p->FFTbuffer_upper_cut_off[n - 1] = p->FFTbuffer_lower_cut_off[n - 1] + 1; } } } free(bar_buffer); free(relative_cut_off); return p; } void cava_execute(double *cava_in, int new_samples, double *cava_out, struct cava_plan *p) { // do not overflow if (new_samples > p->input_buffer_size) { new_samples = p->input_buffer_size; } int silence = 1; if (new_samples > 0) { p->framerate -= p->framerate / 64; p->framerate += (double)((p->rate * p->audio_channels * p->frame_skip) / new_samples) / 64; p->frame_skip = 1; // shifting input buffer for (uint16_t n = p->input_buffer_size - 1; n >= new_samples; n--) { p->input_buffer[n] = p->input_buffer[n - new_samples]; } // fill the input buffer for (uint16_t n = 0; n < new_samples; n++) { p->input_buffer[new_samples - n - 1] = cava_in[n]; if (cava_in[n]) { silence = 0; } } } else { p->frame_skip++; } // fill the bass, mid and treble buffers for (uint16_t n = 0; n < p->FFTbassbufferSize; n++) { if (p->audio_channels == 2) { p->in_bass_r_raw[n] = p->input_buffer[n * 2]; p->in_bass_l_raw[n] = p->input_buffer[n * 2 + 1]; } else { p->in_bass_l_raw[n] = p->input_buffer[n]; } } for (uint16_t n = 0; n < p->FFTmidbufferSize; n++) { if (p->audio_channels == 2) { p->in_mid_r_raw[n] = p->input_buffer[n * 2]; p->in_mid_l_raw[n] = p->input_buffer[n * 2 + 1]; } else { p->in_mid_l_raw[n] = p->input_buffer[n]; } } for (uint16_t n = 0; n < p->FFTtreblebufferSize; n++) { if (p->audio_channels == 2) { p->in_treble_r_raw[n] = p->input_buffer[n * 2]; p->in_treble_l_raw[n] = p->input_buffer[n * 2 + 1]; } else { p->in_treble_l_raw[n] = p->input_buffer[n]; } } // Hann Window for (int i = 0; i < p->FFTbassbufferSize; i++) { p->in_bass_l[i] = p->bass_multiplier[i] * p->in_bass_l_raw[i]; if (p->audio_channels == 2) p->in_bass_r[i] = p->bass_multiplier[i] * p->in_bass_r_raw[i]; } for (int i = 0; i < p->FFTmidbufferSize; i++) { p->in_mid_l[i] = p->mid_multiplier[i] * p->in_mid_l_raw[i]; if (p->audio_channels == 2) p->in_mid_r[i] = p->mid_multiplier[i] * p->in_mid_r_raw[i]; } for (int i = 0; i < p->FFTtreblebufferSize; i++) { p->in_treble_l[i] = p->treble_multiplier[i] * p->in_treble_l_raw[i]; if (p->audio_channels == 2) p->in_treble_r[i] = p->treble_multiplier[i] * p->in_treble_r_raw[i]; } // process: execute FFT and sort frequency bands fftw_execute(p->p_bass_l); fftw_execute(p->p_mid_l); fftw_execute(p->p_treble_l); if (p->audio_channels == 2) { fftw_execute(p->p_bass_r); fftw_execute(p->p_mid_r); fftw_execute(p->p_treble_r); } // process: separate frequency bands for (int n = 0; n < p->number_of_bars; n++) { double temp_l = 0; double temp_r = 0; // process: add upp FFT values within bands for (int i = p->FFTbuffer_lower_cut_off[n]; i <= p->FFTbuffer_upper_cut_off[n]; i++) { if (n <= p->bass_cut_off_bar) { temp_l += hypot(p->out_bass_l[i][0], p->out_bass_l[i][1]); if (p->audio_channels == 2) temp_r += hypot(p->out_bass_r[i][0], p->out_bass_r[i][1]); } else if (n > p->bass_cut_off_bar && n <= p->treble_cut_off_bar) { temp_l += hypot(p->out_mid_l[i][0], p->out_mid_l[i][1]); if (p->audio_channels == 2) temp_r += hypot(p->out_mid_r[i][0], p->out_mid_r[i][1]); } else if (n > p->treble_cut_off_bar) { temp_l += hypot(p->out_treble_l[i][0], p->out_treble_l[i][1]); if (p->audio_channels == 2) temp_r += hypot(p->out_treble_r[i][0], p->out_treble_r[i][1]); } } // getting average multiply with eq temp_l /= p->FFTbuffer_upper_cut_off[n] - p->FFTbuffer_lower_cut_off[n] + 1; temp_l *= p->eq[n]; cava_out[n] = temp_l; if (p->audio_channels == 2) { temp_r /= p->FFTbuffer_upper_cut_off[n] - p->FFTbuffer_lower_cut_off[n] + 1; temp_r *= p->eq[n]; cava_out[n + p->number_of_bars] = temp_r; } } // applying sens or getting max value if (p->autosens) { for (int n = 0; n < p->number_of_bars * p->audio_channels; n++) { cava_out[n] *= p->sens; } } // process [smoothing] int overshoot = 0; double gravity_mod = pow((60 / p->framerate), 2.5) * 1.54 / p->noise_reduction; if (gravity_mod < 1) gravity_mod = 1; for (int n = 0; n < p->number_of_bars * p->audio_channels; n++) { // process [smoothing]: falloff if (cava_out[n] < p->prev_cava_out[n] && p->noise_reduction > 0.1) { cava_out[n] = p->cava_peak[n] * (1.0 - (p->cava_fall[n] * p->cava_fall[n] * gravity_mod)); if (cava_out[n] < 0.0) cava_out[n] = 0.0; p->cava_fall[n] += 0.028; } else { p->cava_peak[n] = cava_out[n]; p->cava_fall[n] = 0.0; } p->prev_cava_out[n] = cava_out[n]; // process [smoothing]: integral cava_out[n] = p->cava_mem[n] * p->noise_reduction + cava_out[n]; p->cava_mem[n] = cava_out[n]; if (p->autosens) { // check if we overshoot target height if (cava_out[n] > 1.0) { overshoot = 1; } } } // calculating automatic sense adjustment if (p->autosens) { if (overshoot) { p->sens = p->sens * 0.98; p->sens_init = 0; } else { if (!silence) { p->sens = p->sens * 1.002; if (p->sens_init) p->sens = p->sens * 1.1; } } } } void cava_destroy(struct cava_plan *p) { free(p->input_buffer); free(p->bass_multiplier); free(p->mid_multiplier); free(p->treble_multiplier); free(p->eq); free(p->cut_off_frequency); free(p->FFTbuffer_lower_cut_off); free(p->FFTbuffer_upper_cut_off); free(p->cava_fall); free(p->cava_mem); free(p->cava_peak); free(p->prev_cava_out); fftw_free(p->in_bass_l); fftw_free(p->in_bass_l_raw); fftw_free(p->out_bass_l); fftw_destroy_plan(p->p_bass_l); fftw_free(p->in_mid_l); fftw_free(p->in_mid_l_raw); fftw_free(p->out_mid_l); fftw_destroy_plan(p->p_mid_l); fftw_free(p->in_treble_l); fftw_free(p->in_treble_l_raw); fftw_free(p->out_treble_l); fftw_destroy_plan(p->p_treble_l); if (p->audio_channels == 2) { fftw_free(p->in_bass_r); fftw_free(p->in_bass_r_raw); fftw_free(p->out_bass_r); fftw_destroy_plan(p->p_bass_r); fftw_free(p->in_mid_r); fftw_free(p->in_mid_r_raw); fftw_free(p->out_mid_r); fftw_destroy_plan(p->p_mid_r); fftw_free(p->in_treble_r); fftw_free(p->out_treble_r); fftw_free(p->in_treble_r_raw); fftw_destroy_plan(p->p_treble_r); } } cava-0.10.2/cavacore.h000066400000000000000000000121121462072613000144360ustar00rootroot00000000000000/* Copyright (c) 2022 Karl Stavestrand Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifdef __cplusplus extern "C" { #endif #pragma once #include #include // cava_plan, parameters used internally by cavacore, do not modify these directly // only the cut off frequencies is of any potential interest to read out, // the rest should most likley be hidden somehow struct cava_plan { int FFTbassbufferSize; int FFTmidbufferSize; int FFTtreblebufferSize; int number_of_bars; int audio_channels; int input_buffer_size; int rate; int bass_cut_off_bar; int treble_cut_off_bar; int sens_init; int autosens; int frame_skip; int status; char error_message[1024]; double sens; double framerate; double noise_reduction; fftw_plan p_bass_l, p_bass_r; fftw_plan p_mid_l, p_mid_r; fftw_plan p_treble_l, p_treble_r; fftw_complex *out_bass_l, *out_bass_r; fftw_complex *out_mid_l, *out_mid_r; fftw_complex *out_treble_l, *out_treble_r; double *bass_multiplier; double *mid_multiplier; double *treble_multiplier; double *in_bass_r_raw, *in_bass_l_raw; double *in_mid_r_raw, *in_mid_l_raw; double *in_treble_r_raw, *in_treble_l_raw; double *in_bass_r, *in_bass_l; double *in_mid_r, *in_mid_l; double *in_treble_r, *in_treble_l; double *prev_cava_out, *cava_mem; double *input_buffer, *cava_peak; double *eq; float *cut_off_frequency; int *FFTbuffer_lower_cut_off; int *FFTbuffer_upper_cut_off; double *cava_fall; }; // cava_init, initialize visualization, takes the following parameters: // number_of_bars, number of wanted bars per channel // rate, sample rate of input signal // channels, number of interleaved channels in input // autosens, toggle automatic sensitivity adjustment 1 = on, 0 = off // on, gives a dynamically adjusted output signal from 0 to 1 // the output is continously adjusted to use the entire range // off, will pass the raw values from cava directly to the output // the max values will then be dependent on the input // noise_reduction, adjust noise reduciton filters. 0 - 1, recomended 0.77 // the raw visualization is very noisy, this factor adjusts the integral // and gravity filters inside cavacore to keep the signal smooth // 1 will be very slow and smooth, 0 will be fast but noisy. // low_cut_off, high_cut_off cut off frequencies for visualization in Hz // recomended: 50, 10000 // returns a cava_plan to be used by cava_execute. If cava_plan.status is 0 all is OK. // If cava_plan.status is -1, cava_init was called with an illegal paramater, see error string in // cava_plan.error_message extern struct cava_plan *cava_init(int number_of_bars, unsigned int rate, int channels, int autosens, double noise_reduction, int low_cut_off, int high_cut_off); // cava_execute, executes visualization // cava_in, input buffer can be any size. internal buffers in cavacore is // 4096 * number of channels at 44100 samples rate, if new_samples is greater // then samples will be discarded. However it is recomended to use less // new samples per execution as this determines your framerate. // 512 samples at 44100 sample rate mono, gives about 86 frames per second. // new_samples, the number of samples in cava_in to be processed per execution // in case of async reading of data this number is allowed to vary from execution to execution // cava_out, output buffer. Size must be number of bars * number of channels. Bars will // be sorted from lowest to highest frequency. If stereo input channels are configured // then all left channel bars will be first then the right. // plan, the cava_plan struct returned from cava_init // cava_execute assumes cava_in samples to be interleaved if more than one channel // only up to two channels are supported. extern void cava_execute(double *cava_in, int new_samples, double *cava_out, struct cava_plan *plan); // cava_destroy, destroys the plan, frees up memory extern void cava_destroy(struct cava_plan *plan); #ifdef __cplusplus } #endif cava-0.10.2/cavacore_test.c000066400000000000000000000072151462072613000155000ustar00rootroot00000000000000// cavacore standalone test app, build cavacore lib first and compile with: // gcc -c -g cavacore_test.c // gcc -o cavacore_test cavacore_test.o build/libcavacore.a -lm -lfftw3 #include "cavacore.h" #include #include #include #define PI 3.141592654 void main() { printf("welcome to cavacore standalone test app\n"); int bars_per_channel = 10; int channels = 2; int buffer_size = 512 * channels; // number of samples per cava execute int rate = 44100; double noise_reduction = 0.77; int low_cut_off = 50; int high_cut_off = 10000; double blueprint_2000MHz[10] = {0, 0, 0, 0, 0, 0, 0.493, 0.446, 0, 0}; double blueprint_200MHz[10] = {0, 0, 0.978, 0.008, 0, 0.001, 0, 0, 0, 0}; printf("planning visualization with %d bars per channel, %d rate, %d channels, autosens, " "%.2f noise reduction, %d - %d MHz bandwith.\n", bars_per_channel, rate, channels, noise_reduction, low_cut_off, high_cut_off); struct cava_plan *plan = cava_init(bars_per_channel, rate, channels, 1, noise_reduction, low_cut_off, high_cut_off); if (plan->status < 0) { fprintf(stderr, "Error: %s\n", plan->error_message); exit(1); } printf("got lower cut off frequencies:\n"); for (int i = 0; i < bars_per_channel; i++) { printf("%.0f \t", plan->cut_off_frequency[i]); } printf("MHz\n\n"); printf("allocating buffers and generating sine wave for test\n\n"); double *cava_out; double *cava_in; cava_out = (double *)malloc(bars_per_channel * channels * sizeof(double)); cava_in = (double *)malloc(buffer_size * sizeof(double)); for (int i = 0; i < bars_per_channel * channels; i++) { cava_out[i] = 0; } printf("running cava execute 300 times (simulating about 3.5 seconds run time)\n\n"); for (int k = 0; k < 300; k++) { // filling up 512*2 samples at a time, making sure the sinus wave is unbroken // 200MHz in left channel, 2000MHz in right // if we where using a proper audio source this would be replaced by a simple read function for (int n = 0; n < buffer_size / 2; n++) { cava_in[n * 2] = sin(2 * PI * 200 / rate * (n + (k * buffer_size / 2))) * 20000; cava_in[n * 2 + 1] = sin(2 * PI * 2000 / rate * (n + (k * buffer_size / 2))) * 20000; } cava_execute(cava_in, buffer_size, cava_out, plan); } // rounding last output to nearst 1/1000th for (int i = 0; i < bars_per_channel * 2; i++) { cava_out[i] = (double)round(cava_out[i] * 1000) / 1000; } printf("\nlast output left, max value should be at 200Hz:\n"); for (int i = 0; i < bars_per_channel; i++) { printf("%.3f \t", cava_out[i]); } printf("MHz\n"); printf("last output right, max value should be at 2000Hz:\n"); for (int i = 0; i < bars_per_channel; i++) { printf("%.3f \t", cava_out[i + bars_per_channel]); } printf("MHz\n\n"); // checking if within 2% of blueprint int bp_ok = 1; for (int i = 0; i < bars_per_channel; i++) { if (cava_out[i] > blueprint_200MHz[i] * 1.02 || cava_out[i] < blueprint_200MHz[i] * 0.98) bp_ok = 0; } for (int i = 0; i < bars_per_channel; i++) { if (cava_out[i + bars_per_channel] > blueprint_2000MHz[i] * 1.02 || cava_out[i + bars_per_channel] < blueprint_2000MHz[i] * 0.98) bp_ok = 0; } cava_destroy(plan); free(plan); free(cava_in); free(cava_out); if (bp_ok == 1) { printf("matching blueprint\n"); exit(0); } else { printf("not matching blueprint\n"); exit(1); } } cava-0.10.2/config.c000066400000000000000000000764161462072613000141340ustar00rootroot00000000000000#include "config.h" #include "util.h" #include #ifndef _MSC_VER #include #endif #include #ifdef SNDIO #include #endif #include #include #include #include #define NUMBER_OF_SHADERS 3 #ifdef _MSC_VER #include "Windows.h" #define PATH_MAX 260 #define PACKAGE "cava" #define _CRT_SECURE_NO_WARNINGS 1 #else #define INCBIN_SILENCE_BITCODE_WARNING #include "third_party/incbin.h" INCTXT(ConfigFile, "example_files/config"); // add your custom shaders to be installed here INCTXT(bar_spectrum, "output/shaders/bar_spectrum.frag"); INCTXT(northern_lightsfrag, "output/shaders/northern_lights.frag"); INCTXT(pass_throughvert, "output/shaders/pass_through.vert"); // INCTXT will create a char gData const char *default_shader_data[NUMBER_OF_SHADERS] = {gnorthern_lightsfragData, gpass_throughvertData, gbar_spectrumData}; #endif // _MSC_VER // name of the installed shader file, technically does not have to be the same as in the source const char *default_shader_name[NUMBER_OF_SHADERS] = {"northern_lights.frag", "pass_through.vert", "bar_spectrum.frag"}; double smoothDef[5] = {1, 1, 1, 1, 1}; enum input_method default_methods[] = { INPUT_FIFO, INPUT_PORTAUDIO, INPUT_ALSA, INPUT_SNDIO, INPUT_JACK, INPUT_PULSE, INPUT_PIPEWIRE, INPUT_WINSCAP, INPUT_OSS, }; char *outputMethod, *orientation, *channels, *xaxisScale, *monoOption, *fragmentShader, *vertexShader; const char *input_method_names[] = { "fifo", "portaudio", "pipewire", "alsa", "pulse", "sndio", "oss", "jack", "shmem", "winscap", }; const bool has_input_method[] = { HAS_FIFO, /** Always have at least FIFO and shmem input. */ HAS_PORTAUDIO, HAS_PIPEWIRE, HAS_ALSA, HAS_PULSE, HAS_SNDIO, HAS_OSS, HAS_JACK, HAS_SHMEM, HAS_WINSCAP, }; enum input_method input_method_by_name(const char *str) { for (int i = 0; i < INPUT_MAX; i++) { if (!strcmp(str, input_method_names[i])) { return (enum input_method)i; } } return INPUT_MAX; } void write_errorf(void *err, const char *fmt, ...) { struct error_s *error = (struct error_s *)err; va_list args; va_start(args, fmt); error->length += vsnprintf((char *)error->message + error->length, MAX_ERROR_LEN - error->length, fmt, args); va_end(args); } int validate_color(char *checkColor, void *params, void *err) { struct config_params *p = (struct config_params *)params; struct error_s *error = (struct error_s *)err; int validColor = 0; if (checkColor[0] == '#' && strlen(checkColor) == 7) { for (int i = 1; checkColor[i]; ++i) { if (!isdigit(checkColor[i])) { if (tolower(checkColor[i]) >= 'a' && tolower(checkColor[i]) <= 'f') { validColor = 1; } else { validColor = 0; break; } } else { validColor = 1; } } } else { if (p->output == OUTPUT_SDL) { write_errorf(error, "SDL only supports setting color in html format\n"); return 0; } if ((strcmp(checkColor, "black") == 0) || (strcmp(checkColor, "red") == 0) || (strcmp(checkColor, "green") == 0) || (strcmp(checkColor, "yellow") == 0) || (strcmp(checkColor, "blue") == 0) || (strcmp(checkColor, "magenta") == 0) || (strcmp(checkColor, "cyan") == 0) || (strcmp(checkColor, "white") == 0) || (strcmp(checkColor, "default") == 0)) validColor = 1; } return validColor; } bool validate_colors(void *params, void *err) { struct config_params *p = (struct config_params *)params; struct error_s *error = (struct error_s *)err; // validate: color if (!validate_color(p->color, p, error)) { write_errorf(error, "The value for 'foreground' is invalid. It can be either one of the 7 " "named colors or a HTML color of the form '#xxxxxx'.\n"); return false; } // validate: background color if (!validate_color(p->bcolor, p, error)) { write_errorf(error, "The value for 'background' is invalid. It can be either one of the 7 " "named colors or a HTML color of the form '#xxxxxx'.\n"); return false; } if (p->gradient) { if (p->gradient_count < 2) { write_errorf(error, "\nAtleast two colors must be given as gradient!\n"); return false; } if (p->gradient_count > 8) { write_errorf(error, "\nMaximum 8 colors can be specified as gradient!\n"); return false; } for (int i = 0; i < p->gradient_count; i++) { if (!validate_color(p->gradient_colors[i], p, error)) { write_errorf( error, "Gradient color %d is invalid. It must be HTML color of the form '#xxxxxx'.\n", i + 1); return false; } } } // In case color is not html format set bgcol and col to predefinedint values p->col = -1; if (strcmp(p->color, "black") == 0) p->col = 0; if (strcmp(p->color, "red") == 0) p->col = 1; if (strcmp(p->color, "green") == 0) p->col = 2; if (strcmp(p->color, "yellow") == 0) p->col = 3; if (strcmp(p->color, "blue") == 0) p->col = 4; if (strcmp(p->color, "magenta") == 0) p->col = 5; if (strcmp(p->color, "cyan") == 0) p->col = 6; if (strcmp(p->color, "white") == 0) p->col = 7; if (p->color[0] == '#') p->col = 8; // default if invalid // validate: background color if (strcmp(p->bcolor, "black") == 0) p->bgcol = 0; if (strcmp(p->bcolor, "red") == 0) p->bgcol = 1; if (strcmp(p->bcolor, "green") == 0) p->bgcol = 2; if (strcmp(p->bcolor, "yellow") == 0) p->bgcol = 3; if (strcmp(p->bcolor, "blue") == 0) p->bgcol = 4; if (strcmp(p->bcolor, "magenta") == 0) p->bgcol = 5; if (strcmp(p->bcolor, "cyan") == 0) p->bgcol = 6; if (strcmp(p->bcolor, "white") == 0) p->bgcol = 7; if (p->bcolor[0] == '#') p->bgcol = 8; // default if invalid return true; } bool validate_config(struct config_params *p, struct error_s *error) { // validate: output method p->output = OUTPUT_NOT_SUPORTED; if (strcmp(outputMethod, "ncurses") == 0) { p->output = OUTPUT_NCURSES; p->bgcol = -1; #ifndef NCURSES write_errorf(error, "cava was built without ncurses support, install ncursesw dev files " "and run make clean && ./configure && make again\n"); return false; #endif } if (strcmp(outputMethod, "sdl") == 0) { p->output = OUTPUT_SDL; #ifndef SDL write_errorf(error, "cava was built without sdl support, install sdl dev files " "and run make clean && ./configure && make again\n"); return false; #endif } if (strcmp(outputMethod, "sdl_glsl") == 0) { p->output = OUTPUT_SDL_GLSL; #ifndef SDL_GLSL write_errorf(error, "cava was built without opengl support, install opengl dev files " "and run make clean && ./configure && make again\n"); return false; #endif } if (strcmp(outputMethod, "noncurses") == 0) { p->output = OUTPUT_NONCURSES; p->bgcol = 0; } if (strcmp(outputMethod, "noritake") == 0) { p->output = OUTPUT_NORITAKE; p->raw_format = FORMAT_NTK3000; // only format supported now } if (strcmp(outputMethod, "raw") == 0) { // raw: p->output = OUTPUT_RAW; p->bar_spacing = 0; p->bar_width = 1; // checking data format p->raw_format = -1; if (strcmp(p->data_format, "binary") == 0) { p->raw_format = FORMAT_BINARY; // checking bit format: if (p->bit_format != 8 && p->bit_format != 16) { write_errorf( error, "bit format %d is not supported, supported data formats are: '8' and '16'\n", p->bit_format); return false; } } else if (strcmp(p->data_format, "ascii") == 0) { p->raw_format = FORMAT_ASCII; if (p->ascii_range < 1) { write_errorf(error, "ascii max value must be a positive integer\n"); return false; } } else { write_errorf(error, "data format %s is not supported, supported data formats are: 'binary' " "and 'ascii'\n", p->data_format); return false; } } if (p->output == OUTPUT_NOT_SUPORTED) { char supportedOutput[1024] = "'noncurses', 'raw', 'noritake'"; #ifdef NCURSES strcat(supportedOutput, ", 'ncurses'"); #endif #ifdef SDL strcat(supportedOutput, ", 'sdl'"); #endif #ifdef SDL_GLSL strcat(supportedOutput, ", 'sdl_glsl'"); #endif write_errorf(error, "output method %s is not supported, supported methods are: %s\n", outputMethod, supportedOutput); return false; } p->orientation = ORIENT_BOTTOM; if (p->output == OUTPUT_SDL || p->output == OUTPUT_NCURSES) { if (strcmp(orientation, "top") == 0) { p->orientation = ORIENT_TOP; } if (strcmp(orientation, "left") == 0) { p->orientation = ORIENT_LEFT; } if (strcmp(orientation, "right") == 0) { p->orientation = ORIENT_RIGHT; } } p->xaxis = NONE; if (strcmp(xaxisScale, "none") == 0) { p->xaxis = NONE; } if (strcmp(xaxisScale, "frequency") == 0) { p->xaxis = FREQUENCY; } if (strcmp(xaxisScale, "note") == 0) { p->xaxis = NOTE; } // validate: output channels p->stereo = -1; if (strcmp(channels, "mono") == 0) { p->stereo = 0; if (strcmp(monoOption, "average") == 0) { p->mono_opt = AVERAGE; } else if (strcmp(monoOption, "left") == 0) { p->mono_opt = LEFT; } else if (strcmp(monoOption, "right") == 0) { p->mono_opt = RIGHT; } else { write_errorf(error, "mono option %s is not supported, supported options are: 'average', " "'left' or 'right'\n", monoOption); return false; } } if (strcmp(channels, "stereo") == 0) p->stereo = 1; if (p->stereo == -1) { write_errorf( error, "output channels %s is not supported, supported channels are: 'mono' and 'stereo'\n", channels); return false; } // validate: bars p->autobars = 1; if (p->fixedbars > 0) p->autobars = 0; if (p->bar_width < 1) p->bar_width = 1; // validate: framerate if (p->framerate < 0) { write_errorf(error, "framerate can't be negative!\n"); return false; } // validate: colors if (!validate_colors(p, error)) { return false; } // validate: gravity p->gravity = p->gravity / 100; if (p->gravity < 0) { p->gravity = 0; } // validate: integral p->integral = p->integral / 100; if (p->integral < 0) { p->integral = 0; } else if (p->integral > 1) { p->integral = 1; } // validate: noise_reduction p->noise_reduction /= 100; if (p->noise_reduction < 0) { p->noise_reduction = 0; } else if (p->noise_reduction > 1) { p->noise_reduction = 1; } // validate: cutoff if (p->lower_cut_off == 0) p->lower_cut_off++; if (p->lower_cut_off > p->upper_cut_off) { write_errorf(error, "lower cutoff frequency can't be higher than higher cutoff frequency\n"); return false; } // setting sens if (p->sens < 1) { write_errorf(error, "Sensitivity needs to be at least 1%%\n"); return false; } p->sens = p->sens / 100; // validate: channels if (p->channels <= 1) p->channels = 1; else p->channels = 2; return validate_colors(p, error); } bool load_config(char configPath[PATH_MAX], struct config_params *p, bool colorsOnly, struct error_s *error) { FILE *fp; char cava_config_home[PATH_MAX / 2]; // config: creating path to default config file char *configHome = getenv("XDG_CONFIG_HOME"); if (configHome != NULL) { sprintf(cava_config_home, "%s/%s/", configHome, PACKAGE); mkdir(cava_config_home, 0777); } else { #ifndef _MSC_VER configHome = getenv("HOME"); #else configHome = getenv("userprofile"); #endif if (configHome != NULL) { sprintf(cava_config_home, "%s/%s/", configHome, ".config"); mkdir(cava_config_home, 0777); sprintf(cava_config_home, "%s/%s/%s/", configHome, ".config", PACKAGE); mkdir(cava_config_home, 0777); } else { #ifndef _MSC_VER sprintf(cava_config_home, "/tmp/%s/", PACKAGE); mkdir(cava_config_home, 0777); #else write_errorf(error, "No HOME found (ERR_HOMELESS), exiting..."); return false; #endif } } if (configPath[0] == '\0') { // config: adding default filename file strcat(configPath, cava_config_home); strcat(configPath, "config"); // open file or create file if it does not exist fp = fopen(configPath, "ab+"); if (fp) { fseek(fp, 0, SEEK_END); if (ftell(fp) == 0) { #ifndef _MSC_VER printf("config file is empty, creating default config file\n"); fwrite(gConfigFileData, gConfigFileSize - 1, sizeof(char), fp); #else printf( "WARNING: config file is empty, windows does not support automatic default " "config " "generation.\n An empty file was created at %s, overwrite with the default " "config from the source to get a complete and documented list of options.\n\n", configPath); #endif } fclose(fp); } else { // try to open file read only fp = fopen(configPath, "rb"); if (fp) { fclose(fp); } else { write_errorf(error, "Unable to open or create file '%s', exiting...\n", configPath); return false; } } } else { // opening specified file fp = fopen(configPath, "rb"); if (fp) { fclose(fp); } else { write_errorf(error, "Unable to open file '%s', exiting...\n", configPath); return false; } } // create default shader files if they do not exist char *shaderPath = malloc(sizeof(char) * PATH_MAX); sprintf(shaderPath, "%s/shaders", cava_config_home); mkdir(shaderPath, 0777); for (int i = 0; i < NUMBER_OF_SHADERS; i++) { char *shaderFile = malloc(sizeof(char) * PATH_MAX); sprintf(shaderFile, "%s/%s", shaderPath, default_shader_name[i]); fp = fopen(shaderFile, "ab+"); if (fp) { fseek(fp, 0, SEEK_END); if (ftell(fp) == 0) { #ifndef _MSC_VER printf("shader file is empty, creating default shader file\n"); fwrite(default_shader_data[i], strlen(default_shader_data[i]), sizeof(char), fp); #else printf( "WARNING: shader file is empty, windows does not support automatic default " "shader " "generation.\n In order to use the shader copy the file %s from the source to " "%s\n\n", default_shader_name[i], shaderPath); #endif } fclose(fp); free(shaderFile); } } free(shaderPath); p->gradient_colors = (char **)malloc(sizeof(char *) * 8 * 9); for (int i = 0; i < 8; ++i) { p->gradient_colors[i] = (char *)malloc(sizeof(char *) * 9); } p->vertex_shader = malloc(sizeof(char) * PATH_MAX); p->fragment_shader = malloc(sizeof(char) * PATH_MAX); #ifndef _MSC_VER // config: parse ini dictionary *ini; ini = iniparser_load(configPath); free(p->color); free(p->bcolor); p->color = strdup(iniparser_getstring(ini, "color:foreground", "default")); p->bcolor = strdup(iniparser_getstring(ini, "color:background", "default")); p->gradient = iniparser_getint(ini, "color:gradient", 0); p->gradient_count = iniparser_getint(ini, "color:gradient_count", 8); for (int i = 0; i < 8; ++i) { free(p->gradient_colors[i]); } free(p->gradient_colors); p->gradient_colors = (char **)malloc(sizeof(char *) * p->gradient_count * 9); p->gradient_colors[0] = strdup(iniparser_getstring(ini, "color:gradient_color_1", "#59cc33")); p->gradient_colors[1] = strdup(iniparser_getstring(ini, "color:gradient_color_2", "#80cc33")); p->gradient_colors[2] = strdup(iniparser_getstring(ini, "color:gradient_color_3", "#a6cc33")); p->gradient_colors[3] = strdup(iniparser_getstring(ini, "color:gradient_color_4", "#cccc33")); p->gradient_colors[4] = strdup(iniparser_getstring(ini, "color:gradient_color_5", "#cca633")); p->gradient_colors[5] = strdup(iniparser_getstring(ini, "color:gradient_color_6", "#cc8033")); p->gradient_colors[6] = strdup(iniparser_getstring(ini, "color:gradient_color_7", "#cc5933")); p->gradient_colors[7] = strdup(iniparser_getstring(ini, "color:gradient_color_8", "#cc3333")); #else outputMethod = malloc(sizeof(char) * 32); p->color = malloc(sizeof(char) * 14); p->bcolor = malloc(sizeof(char) * 14); p->audio_source = malloc(sizeof(char) * 129); xaxisScale = malloc(sizeof(char) * 32); channels = malloc(sizeof(char) * 32); monoOption = malloc(sizeof(char) * 32); p->raw_target = malloc(sizeof(char) * 129); p->data_format = malloc(sizeof(char) * 32); orientation = malloc(sizeof(char) * 32); vertexShader = malloc(sizeof(char) * PATH_MAX / 2); fragmentShader = malloc(sizeof(char) * PATH_MAX / 2); GetPrivateProfileString("color", "foreground", "default", p->color, 9, configPath); GetPrivateProfileString("color", "background", "default", p->bcolor, 9, configPath); p->gradient = GetPrivateProfileInt("color", "gradient", 0, configPath); p->gradient_count = GetPrivateProfileInt("color", "gradient_count", 8, configPath); GetPrivateProfileString("color", "gradient_color_1", "#59cc33", p->gradient_colors[0], 9, configPath); GetPrivateProfileString("color", "gradient_color_2", "#80cc33", p->gradient_colors[1], 9, configPath); GetPrivateProfileString("color", "gradient_color_3", "#a6cc33", p->gradient_colors[2], 9, configPath); GetPrivateProfileString("color", "gradient_color_4", "#cccc33", p->gradient_colors[3], 9, configPath); GetPrivateProfileString("color", "gradient_color_5", "#cca633", p->gradient_colors[4], 9, configPath); GetPrivateProfileString("color", "gradient_color_6", "#cc8033", p->gradient_colors[5], 9, configPath); GetPrivateProfileString("color", "gradient_color_7", "#cc5933", p->gradient_colors[6], 9, configPath); GetPrivateProfileString("color", "gradient_color_8", "#cc3333", p->gradient_colors[7], 9, configPath); #endif if (colorsOnly) { return validate_colors(p, error); } #ifndef _MSC_VER outputMethod = strdup(iniparser_getstring(ini, "output:method", "noncurses")); orientation = strdup(iniparser_getstring(ini, "output:orientation", "bottom")); xaxisScale = strdup(iniparser_getstring(ini, "output:xaxis", "none")); p->monstercat = iniparser_getdouble(ini, "smoothing:monstercat", 0); p->waves = iniparser_getint(ini, "smoothing:waves", 0); p->integral = iniparser_getdouble(ini, "smoothing:integral", 77); p->gravity = iniparser_getdouble(ini, "smoothing:gravity", 100); p->ignore = iniparser_getdouble(ini, "smoothing:ignore", 0); p->noise_reduction = iniparser_getdouble(ini, "smoothing:noise_reduction", 77); p->fixedbars = iniparser_getint(ini, "general:bars", 0); p->bar_width = iniparser_getint(ini, "general:bar_width", 2); p->bar_spacing = iniparser_getint(ini, "general:bar_spacing", 1); p->bar_height = iniparser_getint(ini, "general:bar_height", 32); p->framerate = iniparser_getint(ini, "general:framerate", 60); p->sens = iniparser_getint(ini, "general:sensitivity", 100); p->autosens = iniparser_getint(ini, "general:autosens", 1); p->overshoot = iniparser_getint(ini, "general:overshoot", 20); p->lower_cut_off = iniparser_getint(ini, "general:lower_cutoff_freq", 50); p->upper_cut_off = iniparser_getint(ini, "general:higher_cutoff_freq", 10000); p->sleep_timer = iniparser_getint(ini, "general:sleep_timer", 0); // hidden test features // draw this many frames and quit, used for testing p->draw_and_quit = iniparser_getint(ini, "general:draw_and_quit", 0); // expect combined values of bar height in last frame to be 0 p->zero_test = iniparser_getint(ini, "general:zero_test", 0); // or not 0 p->non_zero_test = iniparser_getint(ini, "general:non_zero_test", 0); // config: output free(channels); free(monoOption); free(p->raw_target); free(p->data_format); free(vertexShader); free(fragmentShader); channels = strdup(iniparser_getstring(ini, "output:channels", "stereo")); monoOption = strdup(iniparser_getstring(ini, "output:mono_option", "average")); p->reverse = iniparser_getint(ini, "output:reverse", 0); p->raw_target = strdup(iniparser_getstring(ini, "output:raw_target", "/dev/stdout")); p->data_format = strdup(iniparser_getstring(ini, "output:data_format", "binary")); p->bar_delim = (char)iniparser_getint(ini, "output:bar_delimiter", 59); p->frame_delim = (char)iniparser_getint(ini, "output:frame_delimiter", 10); p->ascii_range = iniparser_getint(ini, "output:ascii_max_range", 1000); p->bit_format = iniparser_getint(ini, "output:bit_format", 16); p->sdl_width = iniparser_getint(ini, "output:sdl_width", 1000); p->sdl_height = iniparser_getint(ini, "output:sdl_height", 500); p->sdl_x = iniparser_getint(ini, "output:sdl_x", -1); p->sdl_y = iniparser_getint(ini, "output:sdl_y", -1); p->sdl_full_screen = iniparser_getint(ini, "output:sdl_full_screen", 0); if (strcmp(outputMethod, "sdl") == 0 || strcmp(outputMethod, "sdl_glsl") == 0) { free(p->color); free(p->bcolor); p->color = strdup(iniparser_getstring(ini, "color:foreground", "#33cccc")); p->bcolor = strdup(iniparser_getstring(ini, "color:background", "#111111")); p->bar_width = iniparser_getint(ini, "general:bar_width", 20); p->bar_spacing = iniparser_getint(ini, "general:bar_spacing", 5); } p->continuous_rendering = iniparser_getint(ini, "output:continuous_rendering", 0); p->disable_blanking = iniparser_getint(ini, "output:disable_blanking", 0); p->show_idle_bar_heads = iniparser_getint(ini, "output:show_idle_bar_heads", 1); p->waveform = iniparser_getint(ini, "output:waveform", 0); p->sync_updates = iniparser_getint(ini, "output:alacritty_sync", 0); vertexShader = strdup(iniparser_getstring(ini, "output:vertex_shader", "pass_through.vert")); fragmentShader = strdup(iniparser_getstring(ini, "output:fragment_shader", "bar_spectrum.frag")); // read & validate: eq p->userEQ_keys = iniparser_getsecnkeys(ini, "eq"); if (p->userEQ_keys > 0) { p->userEQ_enabled = 1; p->userEQ = (double *)calloc(p->userEQ_keys + 1, sizeof(double)); #ifndef LEGACYINIPARSER const char *keys[p->userEQ_keys]; iniparser_getseckeys(ini, "eq", keys); #endif #ifdef LEGACYINIPARSER char **keys = iniparser_getseckeys(ini, "eq"); #endif for (int sk = 0; sk < p->userEQ_keys; sk++) { p->userEQ[sk] = iniparser_getdouble(ini, keys[sk], 1); } } else { p->userEQ_enabled = 0; } free(p->audio_source); p->samplerate = iniparser_getint(ini, "input:sample_rate", 44100); p->samplebits = iniparser_getint(ini, "input:sample_bits", 16); p->channels = iniparser_getint(ini, "input:channels", 2); p->autoconnect = iniparser_getint(ini, "input:autoconnect", 2); enum input_method default_input = INPUT_FIFO; for (size_t i = 0; i < ARRAY_SIZE(default_methods); i++) { enum input_method method = default_methods[i]; if (has_input_method[method]) { default_input = default_methods[i]; } } char *input_method_name = strdup(iniparser_getstring(ini, "input:method", input_method_names[default_input])); p->input = input_method_by_name(input_method_name); switch (p->input) { #ifdef ALSA case INPUT_ALSA: p->audio_source = strdup(iniparser_getstring(ini, "input:source", "hw:Loopback,1")); break; #endif case INPUT_FIFO: p->audio_source = strdup(iniparser_getstring(ini, "input:source", "/tmp/mpd.fifo")); break; #ifdef PULSE case INPUT_PULSE: p->audio_source = strdup(iniparser_getstring(ini, "input:source", "auto")); break; #endif #ifdef PIPEWIRE case INPUT_PIPEWIRE: p->audio_source = strdup(iniparser_getstring(ini, "input:source", "auto")); break; #endif #ifdef SNDIO case INPUT_SNDIO: p->audio_source = strdup(iniparser_getstring(ini, "input:source", SIO_DEVANY)); break; #endif #ifdef OSS case INPUT_OSS: p->audio_source = strdup(iniparser_getstring(ini, "input:source", "/dev/dsp")); break; #endif #ifdef JACK case INPUT_JACK: p->audio_source = strdup(iniparser_getstring(ini, "input:source", "default")); break; #endif case INPUT_SHMEM: p->audio_source = strdup(iniparser_getstring(ini, "input:source", "/squeezelite-00:00:00:00:00:00")); break; #ifdef PORTAUDIO case INPUT_PORTAUDIO: p->audio_source = strdup(iniparser_getstring(ini, "input:source", "auto")); break; #endif case INPUT_MAX: { char supported_methods[255] = ""; for (int i = 0; i < INPUT_MAX; i++) { if (has_input_method[i]) { strcat(supported_methods, "'"); strcat(supported_methods, input_method_names[i]); strcat(supported_methods, "' "); } } write_errorf(error, "input method '%s' is not supported, supported methods are: %s\n", input_method_name, supported_methods); return false; } default: write_errorf(error, "cava was built without '%s' input support\n", input_method_names[p->input]); return false; } free(input_method_name); iniparser_freedict(ini); #else GetPrivateProfileString("output", "method", "noncurses", outputMethod, 16, configPath); p->waves = GetPrivateProfileInt("smoothing", "waves", 0, configPath); p->monstercat = GetPrivateProfileInt("smoothing", "monstercat", 0, configPath); p->noise_reduction = GetPrivateProfileInt("smoothing", "noise_reduction", 77, configPath); GetPrivateProfileString("output", "xaxis", "none", xaxisScale, 16, configPath); GetPrivateProfileString("output", "orientation", "bottom", orientation, 16, configPath); p->fixedbars = GetPrivateProfileInt("general", "bars", 0, configPath); p->bar_width = GetPrivateProfileInt("general", "bar_width", 2, configPath); p->bar_spacing = GetPrivateProfileInt("general", "bar_spacing", 1, configPath); p->bar_height = GetPrivateProfileInt("general", "bar_height", 32, configPath); p->framerate = GetPrivateProfileInt("general", "framerate", 60, configPath); p->sens = GetPrivateProfileInt("general", "sensitivity", 100, configPath); p->autosens = GetPrivateProfileInt("general", "autosens", 1, configPath); p->overshoot = GetPrivateProfileInt("general", "overshoot", 20, configPath); p->lower_cut_off = GetPrivateProfileInt("general", "lower_cutoff_freq", 50, configPath); p->upper_cut_off = GetPrivateProfileInt("general", "higher_cutoff_freq", 10000, configPath); p->sleep_timer = GetPrivateProfileInt("general", "sleep_timer", 0, configPath); GetPrivateProfileString("output", "channels", "stereo", channels, 16, configPath); GetPrivateProfileString("output", "mono_option", "average", monoOption, 16, configPath); p->reverse = GetPrivateProfileInt("output", "reverse", 0, configPath); GetPrivateProfileString("output", "raw_target", "stdout", p->raw_target, 64, configPath); GetPrivateProfileString("output", "data_format", "binary", p->data_format, 16, configPath); p->bar_delim = (char)GetPrivateProfileInt("output", "bar_delimiter", 50, configPath); p->frame_delim = (char)GetPrivateProfileInt("output", "frame_delimiter", 10, configPath); p->ascii_range = GetPrivateProfileInt("output", "ascii_max_range", 1000, configPath); p->bit_format = GetPrivateProfileInt("output", "bit_format", 16, configPath); p->sdl_width = GetPrivateProfileInt("output", "sdl_width", 1000, configPath); p->sdl_height = GetPrivateProfileInt("output", "sdl_height", 500, configPath); p->sdl_x = GetPrivateProfileInt("output", "sdl_x", -1, configPath); p->sdl_y = GetPrivateProfileInt("output", "sdl_y", -1, configPath); p->sync_updates = GetPrivateProfileInt("output", "alacritty_sync", 0, configPath); p->show_idle_bar_heads = GetPrivateProfileInt("output", "show_idle_bar_heads", 1, configPath); p->waveform = GetPrivateProfileInt("output", "waveform", 0, configPath); p->userEQ_enabled = 0; p->input = GetPrivateProfileInt("input", "method", INPUT_WINSCAP, configPath); if (p->input != INPUT_WINSCAP) { write_errorf(error, "cava was built without '%s' input support\n", input_method_names[p->input]); return false; } GetPrivateProfileString("input", "source", "auto", p->audio_source, 64, configPath); if (strcmp(outputMethod, "sdl") == 0 || strcmp(outputMethod, "sdl_glsl") == 0) { p->bar_width = GetPrivateProfileInt("general", "bar_width", 20, configPath); p->bar_spacing = GetPrivateProfileInt("general", "bar_spacing", 5, configPath); GetPrivateProfileString("color", "foreground", "#33cccc", p->color, 9, configPath); GetPrivateProfileString("color", "background", "#111111", p->bcolor, 9, configPath); } p->continuous_rendering = GetPrivateProfileInt("output", "continuous_rendering", 0, configPath); GetPrivateProfileString("output", "vertex_shader", "pass_through.vert", vertexShader, 64, configPath); GetPrivateProfileString("output", "fragment_shader", "bar_spectrum.frag", fragmentShader, 64, configPath); #endif sprintf(p->vertex_shader, "%s/shaders/%s", cava_config_home, vertexShader); sprintf(p->fragment_shader, "%s/shaders/%s", cava_config_home, fragmentShader); bool result = validate_config(p, error); return result; } cava-0.10.2/config.h000066400000000000000000000054261462072613000141320ustar00rootroot00000000000000#pragma once #include #include #include #include #define MAX_ERROR_LEN 1024 #ifdef PORTAUDIO #define HAS_PORTAUDIO true #else #define HAS_PORTAUDIO false #endif #ifdef ALSA #define HAS_ALSA true #else #define HAS_ALSA false #endif #ifdef PULSE #define HAS_PULSE true #else #define HAS_PULSE false #endif #ifdef PIPEWIRE #define HAS_PIPEWIRE true #else #define HAS_PIPEWIRE false #endif #ifdef SNDIO #define HAS_SNDIO true #else #define HAS_SNDIO false #endif #ifdef OSS #define HAS_OSS true #else #define HAS_OSS false #endif #ifdef JACK #define HAS_JACK true #else #define HAS_JACK false #endif #ifdef _MSC_VER #define HAS_WINSCAP true #define SDL true #define HAS_FIFO false #define HAS_SHMEM false #define PATH_MAX 260 #else #define HAS_WINSCAP false #define HAS_FIFO true #define HAS_SHMEM true #endif // These are in order of least-favourable to most-favourable choices, in case // multiple are supported and configured. enum input_method { INPUT_FIFO, INPUT_PORTAUDIO, INPUT_PIPEWIRE, INPUT_ALSA, INPUT_PULSE, INPUT_SNDIO, INPUT_OSS, INPUT_JACK, INPUT_SHMEM, INPUT_WINSCAP, INPUT_MAX, }; enum output_method { OUTPUT_NCURSES, OUTPUT_NONCURSES, OUTPUT_RAW, OUTPUT_SDL, OUTPUT_SDL_GLSL, OUTPUT_NORITAKE, OUTPUT_NOT_SUPORTED }; enum mono_option { LEFT, RIGHT, AVERAGE }; enum data_format { FORMAT_ASCII = 0, FORMAT_BINARY = 1, FORMAT_NTK3000 = 2 }; enum xaxis_scale { NONE, FREQUENCY, NOTE }; enum orientation { ORIENT_BOTTOM, ORIENT_TOP, ORIENT_LEFT, ORIENT_RIGHT }; struct config_params { char *color, *bcolor, *raw_target, *audio_source, /**gradient_color_1, *gradient_color_2,*/ **gradient_colors, *data_format, *vertex_shader, *fragment_shader; char bar_delim, frame_delim; double monstercat, integral, gravity, ignore, sens, noise_reduction; unsigned int lower_cut_off, upper_cut_off; double *userEQ; enum input_method input; enum output_method output; enum xaxis_scale xaxis; enum mono_option mono_opt; enum orientation orientation; int userEQ_keys, userEQ_enabled, col, bgcol, autobars, stereo, raw_format, ascii_range, bit_format, gradient, gradient_count, fixedbars, framerate, bar_width, bar_spacing, bar_height, autosens, overshoot, waves, samplerate, samplebits, channels, autoconnect, sleep_timer, sdl_width, sdl_height, sdl_x, sdl_y, sdl_full_screen, draw_and_quit, zero_test, non_zero_test, reverse, sync_updates, continuous_rendering, disable_blanking, show_idle_bar_heads, waveform; }; struct error_s { char message[MAX_ERROR_LEN]; int length; }; bool load_config(char configPath[PATH_MAX], struct config_params *p, bool colorsOnly, struct error_s *error); cava-0.10.2/configure.ac000066400000000000000000000305601462072613000147770ustar00rootroot00000000000000AC_INIT([cava], [m4_esyscmd_s([cat version])], [karl@stavestrand.no]) AM_INIT_AUTOMAKE([subdir-objects -Wall -Werror foreign]) dnl AC_CONFIG_MACRO_DIRS([m4]) AM_PROG_AR LT_INIT AC_PROG_CC AC_PROG_CC_STDC AM_PROG_LIBTOOL AC_CANONICAL_HOST build_linux=no build_windows=no build_mac=no build_freebsd=no AC_MSG_NOTICE([Checking OS]) # Detect the target system case "${host_os}" in linux*) AC_MSG_NOTICE([Linux detected]) build_linux=yes ;; darwin*) AC_MSG_NOTICE([OSX detected]) build_mac=yes ;; freebsd*) AC_MSG_NOTICE([FreeBSD detected]) build_freebsd=yes ;; *) AC_MSG_ERROR(["OS $host_os is not supported"]) ;; esac # Pass the conditionals to automake AM_CONDITIONAL([LINUX], [test "$build_linux" = "yes"]) AM_CONDITIONAL([OSX], [test "$build_mac" = "yes"]) AM_CONDITIONAL([FREEBSD], [test "$build_freebsd" = "yes"]) dnl ############################ dnl checking if debug is enabled dnl ############################ AC_ARG_ENABLE([debug-output], AS_HELP_STRING([--enable-debug-output], [enable debug messages and frequency table output]) ) AS_IF([test "x$enable_debug_output" != "xyes"], [ dnl enabling debug output mode CPPFLAGS="$CPPFLAGS -DNDEBUG" ]) AC_ARG_ENABLE([asan], AS_HELP_STRING([--enable-asan], [build with AddressSanitizer]) ) AS_IF([test "x$enable_asan" = "xyes"], [ dnl enabling asan CPPFLAGS="$CPPFLAGS -fsanitize=address" LDFLAGS="$LDFLAGS -fsanitize=address" ]) AC_ARG_ENABLE([tsan], AS_HELP_STRING([--enable-tsan], [build with ThreadSanitizer]) ) AS_IF([test "x$enable_tsan" = "xyes"], [ dnl enabling tsan CPPFLAGS="$CPPFLAGS -fsanitize=thread" LDFLAGS="$LDFLAGS -fsanitize=thread" ]) AC_ARG_ENABLE([ubsan], AS_HELP_STRING([--enable-ubsan], [build with UndefinedBehaviorSanitizer]) ) AS_IF([test "x$enable_ubsan" = "xyes"], [ dnl enabling ubsan CPPFLAGS="$CPPFLAGS -fsanitize=undefined" LDFLAGS="$LDFLAGS -fsanitize=undefined" ]) dnl ###################### dnl checking for pthread dnl ###################### AC_CHECK_HEADERS([pthread.h], AC_CHECK_LIB(pthread, pthread_create, LIBS="$LIBS -lpthread", AC_MSG_ERROR([pthread.h found but there is no pthread library to make use of]) ), AC_MSG_ERROR([no pthread.h header header file found]) ) dnl ###################### dnl checking for alloca.h dnl ###################### AC_CHECK_HEADER([alloca.h], [CPPFLAGS="$CPPFLAGS -DHAVE_ALLOCA_H"]) dnl ###################### dnl checking for alsa dev dnl ###################### AC_ARG_ENABLE([input_alsa], AS_HELP_STRING([--disable-input-alsa], [do not include support for input from alsa streams]) ) AS_IF([test "x$enable_input_alsa" != "xno"], [ AC_CHECK_LIB(asound, snd_pcm_open, have_alsa=yes, have_alsa=no) if [[ $have_alsa = "yes" ]] ; then LIBS="$LIBS -lasound" CPPFLAGS="$CPPFLAGS -DALSA" fi if [[ $have_alsa = "no" ]] ; then AC_MSG_NOTICE([WARNING: No alsa dev files found building without alsa support]) fi], [have_alsa=no] ) AM_CONDITIONAL([ALSA], [test "x$have_alsa" = "xyes"]) dnl ###################### dnl checking for pipewire dev dnl ###################### AC_ARG_ENABLE([input_pipewire], AS_HELP_STRING([--disable-input-pipewire], [do not include support for input from pipewire]) ) AS_IF([test "x$enable_input_pipewire" != "xno"], [ PKG_CHECK_MODULES(PIPEWIRE, libpipewire-0.3, have_pipewire=yes, have_pipewire=no) if [[ $have_pipewire = "yes" ]] ; then LIBS="$LIBS $PIPEWIRE_LIBS" CPPFLAGS="$CPPFLAGS -DPIPEWIRE $PIPEWIRE_CFLAGS" fi if [[ $have_pipewire = "no" ]] ; then AC_MSG_NOTICE([WARNING: No pipewire dev files found building without pipewire support]) fi], [have_pipewire=no] ) AM_CONDITIONAL([PIPEWIRE], [test "x$have_pipewire" = "xyes"]) dnl ###################### dnl checking for pulse dev dnl ###################### AC_ARG_ENABLE([input_pulse], AS_HELP_STRING([--disable-input-pulse], [do not include support for input from pulseaudio]) ) AS_IF([test "x$enable_input_pulse" != "xno"], [ AC_CHECK_LIB(pulse-simple, pa_simple_new, have_pulse=yes, have_pulse=no) if [[ $have_pulse = "yes" ]] ; then LIBS="$LIBS -lpulse-simple -lpulse" CPPFLAGS="$CPPFLAGS -DPULSE" fi if [[ $have_pulse = "no" ]] ; then AC_MSG_NOTICE([WARNING: No pulseaudio dev files found building without pulseaudio support]) fi], [have_pulse=no] ) AM_CONDITIONAL([PULSE], [test "x$have_pulse" = "xyes"]) dnl ###################### dnl checking for portaudio dev dnl ###################### AC_ARG_ENABLE([input_portaudio], AS_HELP_STRING([--disable-input-portaudio], [do not include support for input from portaudio]) ) AS_IF([test "x$enable_input_portaudio" != "xno"], [ AC_CHECK_LIB(portaudio, Pa_Initialize, have_portaudio=yes, have_portaudio=no) if [[ $have_portaudio = "yes" ]] ; then LIBS="$LIBS -lportaudio" CPPFLAGS="$CPPFLAGS -DPORTAUDIO" fi if [[ $have_portaudio = "no" ]] ; then AC_MSG_NOTICE([WARNING: No portaudio dev files found building without portaudio support]) fi], [have_portaudio=no] ) AM_CONDITIONAL([PORTAUDIO], [test "x$have_portaudio" = "xyes"]) dnl ###################### dnl checking for sndio dev dnl ###################### AC_ARG_ENABLE([input_sndio], AS_HELP_STRING([--disable-input-sndio], [do not include support for input from sndio]) ) AS_IF([test "x$enable_input_sndio" != "xno"], [ AC_CHECK_LIB(sndio, sio_open, have_sndio=yes, have_sndio=no) if [[ $have_sndio = "yes" ]] ; then LIBS="$LIBS -lsndio" CPPFLAGS="$CPPFLAGS -DSNDIO" fi if [[ $have_sndio = "no" ]] ; then AC_MSG_NOTICE([WARNING: No sndio dev files found building without sndio support]) fi], [have_sndio=no] ) AM_CONDITIONAL([SNDIO], [test "x$have_sndio" = "xyes"]) dnl ###################### dnl checking for oss dev dnl ###################### AC_ARG_ENABLE([input_oss], AS_HELP_STRING([--disable-input-oss], [do not include support for input from oss]) ) AS_IF([test "x$enable_input_oss" != "xno"], [ have_oss=no if [[ $build_freebsd = "yes" ]] ; then AC_CHECK_HEADERS(sys/soundcard.h, have_oss=yes, have_oss=no) if [[ $have_oss = "yes" ]] ; then CPPFLAGS="$CPPFLAGS -DOSS -D__BSD_VISIBLE" fi if [[ $have_oss = "no" ]] ; then AC_MSG_NOTICE([WARNING: No oss dev files found building without oss support]) fi fi], [have_oss=no] ) AM_CONDITIONAL([OSS], [test "x$have_oss" = "xyes"]) dnl ###################### dnl checking for jack dev dnl ###################### AC_ARG_ENABLE([input_jack], AS_HELP_STRING([--disable-input-jack], [do not include support for input from jack]) ) AS_IF([test "x$enable_input_jack" != "xno"], [ PKG_CHECK_MODULES(JACK, jack, have_jack=yes, have_jack=no) if [[ $have_jack = "yes" ]] ; then LIBS="$LIBS $JACK_LIBS" CPPFLAGS="$CPPFLAGS -DJACK $JACK_CFLAGS" fi if [[ $have_jack = "no" ]] ; then AC_MSG_NOTICE([WARNING: No jack dev files found building without jack support]) fi], [have_jack=no] ) AM_CONDITIONAL([JACK], [test "x$have_jack" = "xyes"]) dnl ###################### dnl checking for math lib dnl ###################### AC_CHECK_LIB(m, sqrt, have_m=yes, have_m=no) if [[ $have_m = "yes" ]] ; then LIBS="$LIBS -lm" fi if [[ $have_m = "no" ]] ; then AC_MSG_ERROR([math library is required!]) fi dnl ###################### dnl checking for fftw3 dnl ###################### AC_CHECK_LIB(fftw3,fftw_execute, have_fftw=yes, have_fftw=no) if [[ $have_fftw = "yes" ]] ; then LIBS="$LIBS -lfftw3" fi if [[ $have_fftw = "no" ]] ; then AC_MSG_ERROR([fftw library is required!]) fi dnl ###################### dnl checking for sdl2 dnl ###################### AC_ARG_ENABLE([output_sdl], AS_HELP_STRING([--disable-output-sdl], [do not include support for output with sdl]) ) AS_IF([test "x$enable_output_sdl" != "xno"], [ AC_CHECK_LIB(SDL2,SDL_Init, have_sdl=yes, have_sdl=no) if [[ $have_sdl = "yes" ]] ; then LIBS="$LIBS -lSDL2" CPPFLAGS="$CPPFLAGS -DSDL" dnl ###################### dnl checking for opengl (only if we know we have sdl) dnl ###################### AC_ARG_ENABLE([output_sdl_glsl], AS_HELP_STRING([--disable-output-sdl-glsl], [do not include support for output with sdl_glsl]) ) AS_IF([test "x$enable_output_sdl_glsl" != "xno"], [ m4_ifdef([AX_CHECK_GL], [ AX_CHECK_GL(have_opengl=yes, have_opengl=no) ], [ AC_MSG_NOTICE([You need to install the autoconf archives to check for opengl. Remember to re-run autogen.sh.]) have_opengl=no ]) if [[ $have_opengl = "yes" ]] ; then LIBS="$LIBS $GL_LIBS" CPPFLAGS="$CPPFLAGS -DSDL_GLSL $GL_CFLAGS" fi if [[ $have_opengl = "no" ]] ; then AC_MSG_NOTICE([INFO: building without sdl_glsl (opengl) support]) fi ], [have_opengl=no] ) fi if [[ $have_sdl = "no" ]] ; then AC_MSG_NOTICE([INFO: building without sdl support]) fi ], [have_sdl=no] ) AM_CONDITIONAL([SDL], [test "x$have_sdl" = "xyes"]) AM_CONDITIONAL([SDL_GLSL], [test "x$have_opengl" = "xyes"]) dnl ###################### dnl checking for ncursesw dnl ###################### AC_ARG_ENABLE([output_ncurses], AS_HELP_STRING([--disable-output-ncurses], [do not include support for output with ncurses]) ) AS_IF([test "x$enable_output_ncurses" != "xno"], [ curses_config_bin="ncursesw6-config ncursesw5-config" AC_PATH_PROGS(CURSES_CONFIG, $curses_config_bin) AC_CHECK_LIB(ncursesw, initscr, curses_lib=ncursesw ) AC_CHECK_LIB($curses_lib, initscr, if test "$CURSES_CONFIG" = "" ; then LIBS="$LIBS -l$curses_lib" CPPFLAGS="$CPPFLAGS -DNCURSES" fi if test "$CURSES_CONFIG" != "" ; then CPPFLAGS="$CPPFLAGS `$CURSES_CONFIG --cflags` -DNCURSES" LIBS="$LIBS `$CURSES_CONFIG --libs`" fi AC_CHECK_HEADERS([curses.h], , AC_MSG_ERROR([missing curses.h header])) have_ncurses=yes, AC_MSG_NOTICE([WARNING: building without ncursesw support ncursesw is recomended!]) have_ncurses=no )], [have_ncurses=no] ) AM_CONDITIONAL([NCURSES], [test "x$have_ncurses" = "xyes"]) dnl ###################### dnl checking for cava font dnl ###################### AC_ARG_ENABLE([cava_font], AS_HELP_STRING([--disable-cava-font], [do not include support for the console cava font]) ) AS_IF([test "x$enable_cava_font" != "xno"], [ have_cava_font=yes if [[ $build_freebsd = "yes" ]] ; then AC_PATH_PROG(VTFONTCVT, vtfontcvt) if [[ -z "$VTFONTCVT" ]] ; then AC_MSG_NOTICE([WARNING: vtfontcvt not found]) have_cava_font=no fi AC_PATH_PROG(PSF2BDF, psf2bdf) if [[ -z "$PSF2BDF" ]] ; then AC_MSG_NOTICE([WARNING: psf2bdf not found]) have_cava_font=no fi if [[ $have_cava_font = "no" ]] ; then AC_MSG_NOTICE([WARNING: Font conversion tool missing. Building without cava font supported!]) fi fi], [have_cava_font=no] ) AS_IF([test "x$have_cava_font" = "xyes"], [CPPFLAGS="$CPPFLAGS -DCAVAFONT"], []) AM_CONDITIONAL([CAVAFONT], [test "x$have_cava_font" = "xyes"]) dnl ###################### dnl checking for iniparser dnl ###################### AC_CHECK_LIB(iniparser,iniparser_load, have_iniparser=yes, have_iniparser=no) if [[ $have_iniparser = "yes" ]] ; then LIBS="$LIBS -liniparser" CPPFLAGS="$CPPFLAGS -I/usr/include/iniparser" AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[dictionary* ini; const char *keys[3]; iniparser_getseckeys(ini, "eq", keys);]])], [AC_MSG_RESULT(iniparser > 3.2 test OK)], [AC_MSG_RESULT(iniparser > 3.2 test failed falling back to legacy iniparser mode) CPPFLAGS="$CPPFLAGS -DLEGACYINIPARSER"]) fi if [[ $have_iniparser = "no" ]] ; then AC_MSG_ERROR([iniparser library is required!]) fi dnl ############################ dnl Set font directory dnl ############################ AC_ARG_VAR(FONT_DIR, [Directory where the font will be installed.]) AC_SUBST([FONT_FILE]) AS_IF([test "x$have_cava_font" = "xyes"], [ if [[ "$build_freebsd" = "yes" ]] ; then DEFAULT_FONT_DIR="${datarootdir}/cava" FONT_FILE="cava.fnt" else DEFAULT_FONT_DIR="${datarootdir}/consolefonts" FONT_FILE="cava.psf" fi], [ DEFAULT_FONT_DIR= FONT_FILE=] ) if test -z "$FONT_DIR" ; then FONT_DIR="$DEFAULT_FONT_DIR" fi AC_CONFIG_FILES([Makefile]) AC_OUTPUT cava-0.10.2/debug.h000066400000000000000000000004711462072613000137460ustar00rootroot00000000000000#include #ifdef NDEBUG #define debug(...) \ do { \ } while (0) #else #define debug(...) fprintf(stderr, __VA_ARGS__) #endif cava-0.10.2/example_files/000077500000000000000000000000001462072613000153225ustar00rootroot00000000000000cava-0.10.2/example_files/cava.gif000066400000000000000000002107421462072613000167310ustar00rootroot00000000000000GIF89a˜—ó ?ÿÿêêêòòòôôôûûûýýýþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù!ÿ NETSCAPE2.0,˜—þ0ÉI«½8ëÍ»ÿ`(Ždižhª®lë¾p,Ïtmßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïh-`Ín»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹Œ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²£³·¸¹º»¼½¾¿ÀÁÂÃÄ”µÅÊËÌÍÎÏÐÑÒÓ°ÇÉÔÙÚÛÜÝÞßàÌÖØáæçèéêëìÅãåíòóôõö÷æïñøýþÿ ,¥Ï¿*\È0\Á JœH±¢ÅX)D¼È±£Çþ3Nز¤É“(牔@2¥Ë—0c6[™ ¥Ì›8sêdEÓæÎŸ@ƒ •Ôs¨Ñ£HuMÊ´©Ó¶žJJ5àÒªX³jEwu«×¯`Ÿu K¶¬Y]cϪ]ËÖTÚ¶pãÊ­ôv®Ý»gëâÝË7«Þ¾€'ý+¸°a¥Q+^œ“0ãÇ/:ŽL¹rÂÉ–3k¾‡y³çÏé:ƒMz›èÒ¨SÏL¬ºµëh§_Ëž=+6í½rëÞÍ»·€Û»l·ë»¸ïṄ#k¼¹îå·”CgëÜùtYÒ¯Ÿ­Þ\{5ÖÞs7ÞUöò`ÇGÏ<{¼ê¿Ou~~Öø½í£ª¯Ÿ*~Þý¹þå^€mý·¤ð‡`S>·`( >ˆTƒ¹IJ„Eáov‚a‡@m"'ލ“ˆ&fRbŠ7¡È¢%+¾“‹2Nc)шc7îh’Ž8öè#H@Ö(ä)ã‘HÒƒ¢’/2Ù¤•ùãâ÷j?­úÊû^päç7úáË~RÑ_ý È!í1P`²»Õ‰¾sMoTà#¸ ò‹ÁkŸë˜¸ rP-„ ÿ¤'ÂP¤ŠÃ gBÂå…/ ÷Ø7<Þ­°\ñsÜÒjØB¹àˆ=tß-hÃV]Ðs3ŒÅ›8!$‡W\Ÿþ³ÈEÐAm‰·ƒ¢•ˆÅnÑŒ]$ߌ¬ˆÆ6ö¯ŒoW»È¯rS;Þ׆׻ÛÅ.n£;¨évW½é}¯|¿‹ÞóÂ×¾ó/}ï[Þãö7¹o5ïÅàÏòH·†í«^¼Ü7–¼ðaaOØ¿®ï€5œaþvx¹-¬hü` _X †ð‰-œb·Ã+æpŒ=<ãüâw¿6Þð}Ñ*]?VÇ9þ0އ¬ß"ߨÈ@&ò‘—œd$ ÙÉ5Vr“™üä%ó¸½>v¯”«<å.sùËQ†ò‹Q\b™Åe&óÁ|æú^ùQZsšÑ¼æ0SÙÎ^Æ3›ç,ã6ÓØÏAÖ³ ½…åAóyÇt)Â}E3úÑÁ¤'-GSúÒ*±4¦7­IsúÓ#L(¨GmO“úÔ25ªWšG4âհ޵¬gMëZÛúָε®wÍë7¤á×À¶°‡MìbûØÈN¶²—Íìf;ûÙÐŽ¶´§Míj[ûÚØÎ¶¶·Íín{ûÛà·¸_!ù,*‚RþðÉI«½8ëÍ»ÿ`(Ždižhª®Và¾p,lmßx®ï|ïÿÀ pHÄÌŽ³¢rÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÈÉÊËÌ*HÐ/ÆÓÔWÍ×ÍØÛÉÑÑÕáâNÜÜÚåØÞßHãíîAèéñ×êëIïùú7ôÙóýËìÝ‹±¯ ÁþKˆì Ã‡>v[Ȣŋ5$6¤˜£Çþ$4:ã¤É“Dž“ˆ²¥Ë•Iö{IÓ¤J™ôjêÄxóæÎŸ{jJ”¨Ï¢H_U2_Ò§™–i*ªU“T ^Ýz1+ ®`ÊK¶¬Ù“RϪ –v­[^mßʽwn ¯Ò쪫W^} ñ¥ù—FŠÂ N̸ÔMÄM„²lLÅâ-ů²ç—9dF¸9ôçÓ0;þ«BrLG¦QŠ]ŵjØ›eC¢M…w%ߺû2\RñiÇ-%Oa»ä©åÄ ó,Ûqõ‹Ò±SŸÌäv˜ìl¯[OÄ{ðˆâ¡’bþ<õáÃsî=÷­ò´¯ÏŸô}1ûõŽ' ùýà€“Þ&è Ú—ÓƒáD؃…4W….è†)m7¡$£qx ˆhhÎ*%š(œ‡óý·K‹.ƒâ%Ñ8„Ž5‚q£%9²Ö=~£-Aâåd?yA“”$é•P:IA•$ ÙÝ‘`i%‡^~)¦‚“…9¦DÂ%bƒg¶Y„™n!ù,,‚PþðÉI«½8ëÍ»ÿ`(Ždižhª®Và¾p,lmßx®ï|ïÿÀ pHÄÌŽ³¢rÉl:ŸÐ¨tJõ ¯¯ªvËíz¿à°¸‚ÅŽÏè´zÍn»ßð¸|N¯›ø¼~ÏØÿ€‚ƒ„"}‡}…Š‹ŒŽaˆ‘y”•–—˜5’’™žŸ —›‘¡¥¦§¨n£ˆ©­®¯°N«‡±µ¶·¸)³‰¹½¾¿¿»|ÀÄÅÆ§Â{ÇËÌÍÉzÎÒÓÔqГÕÙÚÛ]×xÜàáâwÞÞ~ãéêëçæåìñòóîô÷øùúûüýþÿ H° Áƒ]•¹’°¡ÃJ ‘<œH‘PÄ#3jœs1ÉÆþ Ót”²¤I/#cœ\Ér½–0c y)³¦M4oêÜIîÏŸ@Cä J´è„¡F“þDª´©M¦N£‚K CT©X«QÍ¢ ^Ö¯Û¶ºKÖ¤XeÓªuu­ÛmßÊõw®Ý|öêvÒ{—l^¯žóùàlßï ?°§ñ±Æ'øþRÌX°ãÇ–QHVWyëeŠ›Bþ¼Ž2`Ò¨{™&œº5®ÕÐÚ$sM;ÝìÚ¸¹ÝÎÍ»·ïßÀƒ N¼¸q¡+g”|¹óAÍEžpº/ëÔ bϵ=»÷ïàËïi4ó䉣³>½{7íßËŸO¿¾ýûs:SÅ/?>ÿü¡¦l»`€Ÿ ˜‚u÷ˆ‚ž1(!N˜Q!ù,,‚TþðÉI«½8ëÍ»ÿ`(Ždižhº lë¾° Îtmßx®ï|ïÿÀ P+ƆȤrÉl:ŸÐ¨Ôg¬¶¦Ø¬vËíz¿à”Õ.›Ïè´z½WU¸|N¯Øø¼~Ïïû1vv„…†‡ˆ‰8‚ŒrŠ‘’“{”˜™š›œA–Œ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øxnFùýþNûŠüH0HÀ#û$H¡Ã‡p‚H±"‰-jÜhcŽÜ Az¤²¤Å‘sLª\ɲ¥Ë—0cÊœI³¦Í›8sê|tÆÎŸ#P:JT›Ð8E“^;zG©SiLŸJ}uªÕ«&z¾Àʵ«×¯%«‚õ&¶^Ù±ÛÎÎSK‚-ÚSn]iÍ÷-©º9ñÚÍ¥bß½¶þ: xáˆ5NÌXÒâÆ?hu¹²å˘sM¾’¹³çÏ C‹Mº´éÓ¨S«^ͺµéÇ®cËžM»¶íÛ¸së†{÷«Í,bööM\Ãðâ@ÏPŽüäQ ÌSDoî÷ùƒé'°S§©}{îîÞkE!ù,5‚EþðÉI«½8ëÍ»ÿ`(Ždižhª®Và¾p,lmßx®ï|ïÿÀ pHÄÌŽ³¢rÉl:ŸÐ¨tJõ ¯¯ªvËíz¿à°¸‚ÅŽÏè´zÍnSËW·|N¯Ûïm8Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”!zG•™š›œi—I¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉʸŸ2ËÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíÞÍ1îòóQð0ôøùDöYúþÿ:ø¹H°  4 *\!7‡ #’€(±¢EŠ3jÜȱ£G2ªGaüH²ÉÈ’(­„Tt2¥Ë*-_Ê|·r¦Ío1oꬖs§Oh=ÕÁcô'£¢FG Mšm)8§L­A¥É/*¹©.±ZÝjK+ׯ±¼‚…%–^Ù±­ÎÊS‹V[“5;½m{j.Ý»šìâÝË·¯ß¿€ L¸°a?+^̸±€Ã)9žì8²å‚z/s¤ÌY±æÏŠ:wÖ—ô&ÑœIÇ5} 5eÖ°c«¬*;Z!ù,;\þðÉI«½8ëÍ»ÿ`(Ždižhª®Và¾p,lmßx®ï|ïÿÀ pH4ÍŽ³¢rÉl:ŸÐ¨tJe!¯¯ªvËíz¿à°x„ÅŽÏè´zÍn»ßð¸|N¯«ÊW»~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®—xH¯³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéJ±Gêîïðñ¡ìIòö÷<ô2øüýVú0üÝP ‚Y *\Ø ¡ †#JœH±¢Å‹3jÜȱ#&€Âã8¤qhdÈ“àL¢\¹M%Ë!._>йÎ!?š2¯á„·3ç<›)zúJ´¨Ñ£H“>ú‰©Ò§¶œBU%•bÕ©§®JÔŠ•Wˆ_»þD(¶¬Ù³hÓª]KH€Û·pãÊÀ¶.Ô°ŽðÚµ t¯ß¿€ L¸°á%z+^̸±ãÇ#K,¹²åËv(cÞ̹³çÏ C‹Mº´éÓ¨S«^ͺµë×°cËžM»¶íÛ¸sëÞÍ»·ïßÀƒ N¼¸ñãÈ“ÿ!ù, ,jUþðÉI«½8ëÍ»ÿ`(Ždiž(¬lë¾A*Ïtmßx®ï|ïÿÀàF„ ȤrÉl:ŸÐ¨¬HeI¯Ø¬vËíz¿›jL.›Ïè´+¦®ßð¸|NW·‹õ¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁ¬wDÂÆÇ¯ÄFÈÌÍPÊ/NÐ.ÎÕÖHÓ-ÒÙ+×ÞßCÜ1Mâãàçè(åÛÜéîï!ëäâðõöòLù÷üõûJÿú <½ Ô·0¡Ã‡ì²Eœ±"³‚G0ZܨKcþCÒùƒ¤È“(=˜Lɲ%…•.cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*µs©ÓXMŸJÖpªÕ‘U¯jMv0j¯[E€å7vMÙ°*³Ö:ûR­¶høWB]3wã^È ê._0õNÜÉï\>„'Þd¸¡Å‚:6 ád”+f.Y9òŒÍž?v­î0i2OŸÝ…µj™®·ÄŽ9ûõ•Úø ØÍ»·ïßÖš¶Ý÷^ÝÀ“ÿ~™ø ãL‘+ŸkóÔ©;O½‚¼ìÓá¿ ^ùvƒ×ÑK|P>¹øá8È·_~^H÷¶ŽçÓ§œ¾‡|ý¼Õ“g|þI`uü­7`" €™|ç ‚vhÃ}OLH!„3Ƀ¡r(Õ‡M„(≃˜ˆâŠ~¨Èâ‹y¸˜‰0æ"¡ƒȘ„‰4ÖxËæ8áèãi&êHFZ’C¦À¤~N>%]Ie•‘A‰£”ZÎÇe—WFÉ„’cŠˆ¦k¦)`›nÆ™¡™r&!ù,2‚KþðÉI«½8ëÍ»ÿ`(Ždižhºlë¾p Îtmßx®ï|ïÿÀ P+ƆȤrÉl:ŸÐ¨Ôg¬¶¦Ø¬vËíz¿à”Õ.›Ïè´z½WÙð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕ&nFÖÚÛØEÜàávÞGâæçiä0èìí^ê/Nð.îõÑóWMø,öýþKûdèÛ÷¯à±€ò\( á@| #þrÈ„¢Ä‹¸,*ш±£,ŽèCŠ”r¤É‹%Oª\ɲ¥Ë—0cÊœI³¦Í›8sê”r§Ob= ¨p¨ÑaA*]Ê´©Ó§X’Š“ ÕUpWe­ºmk¯ˆÀr¥&ÖVÙ±÷Šª×F¡€·pãÊ+m³³PØ®uK·ï\hxVápðCom!>ðË.`µvËè%Ô¸qä˘3kÞ̹jeÆCgúìW´éJ¤ûÎ4|ºõÖ'`§ƒìz™ìY·=ä®Í›‚ØÂ w÷v*|Gq ©é~üGò¿lžË]n›6õë{š{”vìàËO¾¼ùó7¸;Fo*!ù,7`þðÉI«½8ëÍ»ÿ`(Ždižhºlë¾p Îtmßx®ï|ïÿÀ p؉cĤrÉl:ŸÐ¨t ÅË×ÌY_z£ŽsÛîo_d†©%>\l±4ÇŒF¹MåÈ¿.cf¸)$Í›ûvÞúth¼£—ž^Â4šÔ‚YÓsM‚¶زñÙ±; î{ƒ®‘øJã=~B.‰yî-Ê 9ÿ<ù¹õ늫Ÿ›Ž}w_ß»‹O¾¼ùóèÓ«_Ͼ½û÷ðãËŸO¿¾ýûøóëßÏ¿¿ÿÿ+(à€hà&¨à‚ 6èàƒF(á„Vhá…f¨á†vèᇠ†M!ù,<[þðÉI«½8ëÍ»ÿ`(Ždižhºlë¾p Îtmßx®ï|ïÿÀ p؉cĤrÉl:ŸÐ¨t º‘§Ñ‚1gEÙd)Ó£å|*uêÄ)F¨æ¤²ê‘ ל:±ÚÒªuÐW¯VÁÞ˶ËÙ5g‰æyÛ¶®º‰ðÚETV–ÞC÷ê+p!ÂÓ@l6­âÇ8 ’œ0di”;d>eù2´Í@{ÍJ4éÓ§â:F}Æ4ëÐŽ]¿nºz6 ÕTm÷.Þ¾ƒ—¬-œðâ°so’\"sDÏ›K7}Æñ騷\Ïν»÷ïàËO¾¼ùóèÓ«_Ͼ½û÷ðãËŸO¿¾ýûøóëßÏ¿¿ÿÿ(à€hà&¨à‚ 6èàƒF(á„Vh! !ù, ‚_þðÉI«½8ëm…ÿ`( \ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßð¸|N‡±õ¼~Ïïû•w?ƒ„…†‡…AˆŒŽTŠ"‘•–—˜™)“!šžŸ ¡†œ ¢¦§¨©d¤Sª®¯°±C¬²¶·¸¹'´$º¾¿À°¼ÁÄÅÆ˜ÃÇÊËÌ~ÉÍÐÑÒgÏÓÖרOÕÙÜÝÞ:Ûßâãä›´åèéêçëîïßáðóôËòõøùº÷úýþªüþ ¨) ÁƒLȰaŸ…#J„q¢Å‹c*bÜÈÑŠÆŽþ C"ù(²G€“(Sª\ d?’.u°œÉ2f>˜6oÐ܉2g=œ>iðätТ1†îDúî(SJi>]çtꊨ3­¦«ªµkI®^Ãr+¶ìD²fÓ2D«¶í@¶nãêƒ+·®Ñvvób¤«·/9¾~w,¸°5†7C¬¸1¨dŒKFÖ.òäË ãÅÌù—fVCûúLJ´é[¤9^-¬òfÖ°E¥ž»¶l× Xv‡µ¦ÍÝ”sÏV”³÷ÊœdWH‚òtÆU"Ý‚ùj¸Kë¦2zJ\Þ{6Iž]µëlœsþ$øöNÈ _Ï=õ¹c¶oyk?Eúæäþ·Jy´m'`IþõßòiW†}aØ• -ÊòÜ ¶aÛ+ºp!v²Dˆ‚lèJ‡ÕHˆy€Hœ‰ª èƒŠƒ°˜‰‹À¨cf.6·ã.4þxc× iÒ‚FÖðáK"%c’/4Y”PšHåWVÙŽ”Œ¤–,<Ù—"2‘%kbè =d–âå|¹¥y™œ@O›­¸‘ ’ñY™™ƒ_†â'U…Šƒg-„ÚÉ!’þšÊ¢½Ôu(˜|Pš×¥{Hº‘¦BªP¢[ z¦tx O‚ ¢*‡ª®&Bjœk¬Ì°:+®¼>¡«£½Ûé®Âkì± †‡ì²sÔÊl*!ù,‚wþðÉI«½8ëm…ÿ`( \ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßð¸|N‡±õ¼~Ïïû•w?ƒ„…†‡…AˆŒŽTŠ"‘•–—˜™)“!šžŸ ¡†œ ¢¦§¨©d¤Sª®¯°±C¬²¶·¸¹'´$º¾¿À°¼ÁÄÅÆ˜ÃÇÊËÌ~ÉÍÐÑÒgÏÓÖרOÕÙÜÝÞ:Ûßâãä›´åèéêçëîïßáðóôËòõøùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÕ«X³jÝʵ«×¯`ÊëîÙ³hÌ¢];F-Û·[ÜR @·®Ý»xÀ½"wjÞ¿y÷Zé+°áº‚«ŽzøpbIíº66üX[d®“Wv²jæ¿››tÖ0ÚãçÀ¡—”ưšãi¼©U_vÑzãë»ÿjËÒýe¶ÊÛvsû¶7|oŒÀû;þŠùç“ÓÎ*"tŠÒõBºN»xBî³GïÃ;BòÅo7Oý:÷±³Ÿ5ßüO÷ã£Èo¿~ þ™þ¨É8g ¿8 iíX] Zႈ 2ø …ÌLÈZƒ nø‚…zÈaZæ@")8È"„)žÈˆ‰ì”â‹vÄ(£44V°"'-êX#Ž;¦óã$AÚ¨ä‹.Y¤:G*’$“7:Ùã“eU‰äsZJÉå’N>&–|DÈ”Vvyæ—D62&™¨Ç„™w ¹%läså {â"§l`Þ©fl¾ OŸ0Š¸ÏŸ€ šg¡‚êe=ˆæ¨¨>Œ¶€'vzÙä–” ©˜¨ßdŠÄ¦a@:鈤ZS)«—æcꨶ¡êš–¶yh«GÍjD­xÜJh®†¾óêJ¾®â(§‰êj,¯F%ÛÖ²© *œâH+°‚4[,¶Ùhë·‹€Ë!¹”˜{.µ¶ªë„¸"ë® ð†$ï¼,Ô Ò½øª ¿ýöô/´ÏH°,Çj†¾ùm4 ;»°t ‡GñÉ0\1…o<`ÇrÈZe|1É{™œÊ‚© Ë^D!ù,8CR<þPÈI«/ëÍ»ÿ`(Ždižhª®lë¾p,Ïtmßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘j”’—˜™š›œžŸ ¡¢"•¥£¨©ª-¦¦y­¥«²³´°•µ¹ºˆ·”½–»ÂÃ~À¿ÆÄË6ÎÏÐÑÒ‘ÉÊHÖ§ÌÛIÓÞÓÕÙâã/åÜéFßìϺè0ðêó@ííïâ1òôü;öìø²éËׯ`Žß’ì3¸¡7†¹‚ÃFbC‰Ñ,Ò˜‘¢@r¡5Š\ÅšB‚ -&ù¨¤;–wVÂdäÒÙL;2oêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*mVs©S§5©=JµªÕ«X³jÝʵ«×¯`ÊK¶,”¨fÓîB«¶-«uغ‹"å¹tóް+¯Þ¿€ L¸°áÈÏâ›Â¯âǯ` ¹rÊ–3ÃÁìC²æÏo<ƒ­ƒs ѤS×0­ZR!ù,8CR<þ0ÈI« /ëÍ»ÿ`(Ždižhª®lë¾p,Ïtmßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰ŒŠ‘’“”•O˜–›œžŸ ¡¢£¤¥¦¢©ª«¬­§°±²³´µ¶1®¹®·¼½¾¿ÀÁÂÃÄÅ`ºÈªÆËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâP™™É»ãêëìíîïðñòó9å˜ôøòöùýîûŒü TÐÑÀƒß Z@Ȱ¡Ã‡#Jœ¦°ÂÄ‹3jÜȱ£ÇL C®C‡L¤É“(Sª\ɲ¥Ë—0cÊœI³ME 5sò¹©I§Ï;<%üÔIR×УH“+š+LP J£JJµªÕLÓ]Ýʵ«Ã§^ÉD!ù,D‚:þðÉI«½8ÏÀ»ÿ` dižhª®lë¾p,Ïtmßx®ï{臼 pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’S?•“˜™š›œžd––Ÿ£¤¥†¡•¦ª«¬*¨?­±²³f¯>f¹º»¼½´ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎ¥¶@Ñ ÏÖרÙÚÛÜÝÞßàáâãäåæÔçëì~éíñò²ï—ãéóùúXõûÿÇô° Á,*\%!Ç#ŽðEÑ—Ä‹«bÜȱ£Çp Íi I²¤„‘&SzD©²åE‡,]Ê ³ßÌ›÷lNÓ‰Ó`ÅŸºÈլ׳h·˜F“¶Cª´i9¦N£‚ƒ*µê6ªV³jÝʵ«×¯`Ia K¶¬Ì±fÓª]˶­[khßʽèIžsójŠ«·ï)¼~E!ù, Fj9þðÉI«!ëÍ{¸`(Ždižhª®lë¾p,Ïtmßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡#ŠˆŽ2‹“‘–—˜™š›œX””’Ÿ‹¤¥¦B¢£©Š¬Œ§±²m¯Jµ³º»¸¼ÀÁ·¾ÃÇÈÉÊËÌÍzÅÆ«ÐÎÔÕ¦ÐÒÅÖÜÝ—ØÞáâãäåæÄÛçêëˆàìïðgîñôõuó/øñ¸öý-úÿ¦ùHð@ *\Ȱá #JœHQ€Ã‹{bÜÈ•ÀŽk CþИè£È“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜI†$ÏŸ@ú JôÜТHÅMÊ´©Ó§P£JirªUeK¯j=•u«WN]¿~ ›†¬Ø³hÓ>«ª¶­Û·pñ˜K·®Ý»xó›«7N!ù,‚yþðÉI«½8ëmƒÿ`(\ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßð¸|N‡±õ¼~Ïïû•w?ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£)AÊÔ‰RM£.yBªÕ#TA\Ýʵ«×¯`ÊK¶¬Ù³hÓªe”uÊÚ·_Ú’€KWî\º¦ìJЋ&ß¾jÿ¦(ÜÁ #&«x±ØÆ+ ;ÞÉWò䜖/oͬ¹ çÎQ?ƒf*ÕÑeO£ÞRÊájªEµv8;Cí«·æîðzµïßÀóö.²;8¾â.¯§|yÍæ·HŸN½ºuÎ¥^ß~={Tîà§{o>üøóÑʃGT=wöFÝo‡ß :}•öïëßÏ¿¿ÿÿ.”_€v!_w1 ˜„‚.r uÂµÕ N Nhá…Tˆá†vè¡+~HÛpÀE!ù, jrþðÉI«½8ÏÀ»ÿ` dižhª®lë¾p,Ïtmßx®ïc臼 pH,ȤrÉl>~ÐŽsJ­Z¯Ø¬v;F¹à°xL.›Ï,/Ín»ßð¸¥þÍïø¼~ÏçÕ}}‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sê|øÈΟTz‚J´‰ÐE“*]Ê´©Ó§P£JªI€Õ«X³j@µk‹­`·z›"¬Ù«z »äìY8j¥<‰+âݺlY¸5+aoX¸t%Ü58¯^¿b Nì¦paÃÈkí+«“ÇíU¶¬x³ÕË3ßóü¹³gÐqE& 8µêz¤¹Æˆ-óël´Mo–‘û¶Âܽ}ãÎZxNâ§³ ®¼+óæSŸC;JJúKëΨ/*Œ½Ÿmè-¸'øü ñÉɇ6¯¤;¿òár¿O>ûûäìã/ª?ÐþþíW`€9 HàM¨à‚ 6è aë=8Rn JX…Z}^7^‡ †¸T…"šD"–˜Ï‰¤H‹*ÆãbÆxz»Å£î —#0ÍdHB!ù,‚lþðÉI«½8ëmƒÿ`(\ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßð¸|N‡±õ¼~Ïïû•w?ƒ„…†‡…AˆŒŽTŠ"‘•–—˜™)“!šžŸ ¡†œ ¢¦§¨©d¤Sª®¯°±C¬²¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±â83jÜÈQ€„Žþ ;Z.¤ÉŒOš$ɲ›Ê•^†lI3›L)on¬É³šNŽ9b *´§Ñ\B5ý¹Tçѧ²’¢Œ)Õ#U©P³ºªj•kÓ›ZÞòz5éW™bÓ‚"˶ªÚ·™Úb-[®ÝHrÍÒez·o£¼uÉú\0_Á„÷1ìtocÄŠ#_a ÖqeÈ’3;¡ŒÖrgÌšC'áüòliϧE«íµJÓ¯]ŸÔG‹Äj?¤c瞯ömÜ­wÃ=Ï÷o>ÂgÊÞŸñãz’ã\®œ¸¼çÐ'ß>†õxسW‘.’útïÍï…ÿ„ô¨¡Sú g„ЦÁ(?†f7©†‘NT飜vêé§ †úÎ¥¢–jꩨΰiª¬¶êê«°šCj¬´~‘é+«þ6+2»¦k­7ôjŒ°'ü ,MÄ«ì²Ìr‘l³¦>ËÁŒÐ¶$mµ ^‹­§ÚnËi·Þf!ù,#‚_þðÉI«½8ëmƒÿ`(\ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßð¸|N‡±õ¼~Ïïû•w?ƒ„…†‡…AˆŒŽTŠ"‘•–E™š›œ— Y“!¡¥¦2ž©ž§¬­®¯yª²š°µ¶·¸W³³¹½¾¿À6»²ÁÅÆÇÈêÉÍÎϯ˩ÐÔÕÖÒ«×ÛÜÝsÙÞâãäBàœç›åìíî.ê´ñ™ïö÷øôŸóôùÿÙíKç/ ÁƒÖö‹‡°¡Cd #|H±¢!‰ ª³È±#5…þCŠr¤É“Ñ&¢\ÉòRÉ–0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê4ØË¦P£>JÕÔÔªX‹^ÍÊèÖ®`w~ KÖæØ²hcžMËåÚ¶pC¾K·âܺxóêÝË·¯ß¿ìFL8 à)…ß;ìA±cwŒI<ž<.2å˘3kÞÌYƒåΠCŸú,Ú&銧KÏüœz[kÕ0Y3®<6MÙ‡iç¶½ºökÞÀ-ýN¼¸ñãÈ“+_μùãáÎ[Þ…=úÊéϪ[ß^F;÷ï]¼‡Ÿ^µx.£Ê—>¿%ý öZà«G$‹{õ¯äŸŸó~‹ýUQÈŸiä hà&X„€ 6èàƒF(á„Â`…f¨á†c\(vŠáa;‚¢yµÁ`≢•¨~¾¥È"Q#ªQãŒ8æ˜×Š:RÈcqD!ù, jdþðÉI«½8ëÍ»ÿ`(Ždižhª®¬$¼p,ÏBkßx®ï|ïÿÀ pHäÐŽ´¢rÉl:ŸÐ¨tªDZaÔ¬vËíz¿`êõ.›Ïè´zÍ[Ùð¸|N¯ƒÝH»~ÏïûÿxG€„…†‡ˆ[‚I‰Ž‘&‹3’–—˜™‡”2šžŸ ¡eœ1¢¦§¨©A¤Xª®¯°±¬5²¶·¸¹º»¼½¾¿ ÂÃÄÅÆÀÉÊËiÇÎÇÌÑÒÓRÏÖÃÔÙÚÛ>××Üàáâ&ÞÖãçèéåÏêî´µïŸìÎó÷ñøžõÐûÿuõ3° ÁW‹\È0XBl #J„ôâÄ‹3jÜȱ£Çþ CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨QuúŽ*-˜t©Ó§P£JJµªÕ«X³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xIV–·/š½Èü x°ÄÂÙ^œE1ãÇPCžL¹²åËW%cv§™YçŸ7KBÚaE¥E?"½aë©U7b}Z¶íu¯cßîÓ´¥îÝÀ9üN¼¸ñãÈ“+_Î|­æÐôŽN½ºu\÷d¿¾pB8Û¹ü.^9ynáÅÑw°á …+¶x±ã&?D~œtrË”Û`î´YCçÌM®\!öCiÐUD#QqPkÔ{T¯æx•ì#°ïÜNB{#«Ý3rÛ.ƒumUÄc/õÚRr,ËG5¯ôüEtéÇSU¯q]ñvßÓ„ïkü ófГ/2]z2ï× i(¾|TôÙ¿o*?¤ý*gX€ FàIþX êÅ`ƒt=!\Nhá…f¨á ûmèU‡ö!ù,4‚LþðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pHäÑŽ´¢rÉl:ŸÐ¨tJõ ¯°ªvËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~OÁbù€‚ƒ„Q~W…‰Š‹Œ!‡HŽ’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿EGÀÄÅÆÂIǯÉ3ËÄÍ2Ï®Ñ1jÕYÓ†Ø5ÚÞbÜÝßMáãæ]åçKéêíî¡ìïòó—ñô÷øŠöùüýzûþ „p Áƒf "\ȋ†#:y(±¢Å‹3jÜȱ£Çþ CŠI²¤É“(SŠÀ²¥Ë—0¨œÉ1¦Í˜4sb¼É³¥ÎŸ{öJ”¡PžE“¥Eqꃨ8­Æª:+L­[¹ÍàõåXfbÏZ(ëR­[ml}¾+‡k¸,éÃ+ó*ÞNvyð%˜Õ`¿q§erX¯ã5…u4~L9áâ%‡#WÞÌB3Ï@s]BtÓ}.“^õ„t“YË6»LíÙ¸Oܳ;·ï½ÃÿÝÂ5ñã{ÒGÎÜ‹rÕÍ£»Y.½zêÖ³£Á®½ûî?À[ï½ùò諜OϾ½û÷ðg–]¿~‰²ö; ÏÏŸ ôþ?í ,!ù,‚eþðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pHäÑŽ´¢rÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚ¡HÝ0ÛàáDÞÞâæç;äÝèìíîïðñòóôõöÀêH÷ûïùGüÑùK° ¸3 *\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ Cf@(C¤ÉS$cœ\9*å·2._°œù)f š85ÙÌÉóÒΞ@ƒ J´¨Ñ£H“*]šç'Ó§wœž@µªÕ«X@ÝDª‰¬`³rÛÃk‰°h«’]›Ã,‰´iÙÊmáv\´s󦨫·o¾~S,¸ð†+A¬¸qטŽ#7a,¹2Ê–Ý ‹ sæB›Á6-öóWÒWG£¶jºèjÖM^«m=T6U'¶µÒš·íݼÇNÌ3p"½‡Ë6fü¸äL ;Ç)]Iõé,¯#'Ž] äÚO…ï¾§9yìæÏ;O¯8ûö´ßÃ7-¾»úã¾Ûwˆäþþ-(à€hàjˆàF«¡ à‚s=Éx]P¡?I‰…VÆa‡þ}"!ù,‚bþðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pHäÑŽ´¢rÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞHá0ßäå8ââæêë'èáìðñòóôõö÷øùúûüýîHü ¼ðÈÀƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ ëL²$§‘3Lª\ɲe#”2\Ê|3ÆÌ›‹jŽÃɳ§ÏŸ2J´¨Q@“*]Ê´©Ó§P£JJµªÕ«X³jÝʵ«×¯MŠ= ¶l“±h‡š]["mZ nѲ$îXlvÅ:ÉK–®¾Fá&ŠJç Áƒ…ú•”XíƒÆŠO®ñòâH‘Vn\ØðeT™'î¬ó³é“O«N‘zµ´Ð4=»ŽÛQëÙÏjãÞÍA7ïß|OÜñâÀ#ç »9àåNsÞœzXËÔ‹¶k©ôÑÙãv_ú]{x·ã•–~þí’Ûé³­ç»]ü{ÙñåcGa^ üüõ( sì H }&èru0¨`7náƒÚL˜……—µö_0^Ñ¡_!ù, j`þðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pHäÐŽ´¢rÉl:ŸÐ¨tªDZaÔ¬vËíz¿`êõ.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâããcVäèéæHêîïìGðôîòIõùå÷2úþÿ lÁ¯ßÀƒÓ Æ@ÈšB, #.{øB¢Edk\Ü8,#Çþ CŠI²¤É“(Sª\Ér¤Ç–0C½ŒI“ÓÌš8/ÝÌÉ3àΞ@ýL94¨ž¢F“Bª´é¦N£JJµˆ€«X³jÝ* ªW=\ÃrýJv‡Ø³XU E[¶íµgÕ ë¶îйtà«w¯V»€OøýÛwðU †Ó^,$ñá†/9îÊXÙdÄŽ%gnr¹r Î+…^2ÚsЛM«žRzµk&­I ~M»Bì³kë¾-"·nÚ¼Cøþí:8ˆáÄ“ÿ@®¼¹Ô{K:^&Ô«fÿg}®ôïºÃÝ´ýNyðįÍy=õlÝËŸOŸ‘ñúø1'ÎÏ?|jÀ÷õAsnØŸS!˜Ÿ‚Q1XŸƒMA( +ðydž„ Sáxþ—a4®×á~Òƒa‰vœøQ{(¦ça‹ó©£j!ù,#‚\þðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pHäÑŽ´¢rÉl:ŸÐ¨tJõ ¯°ªvËíz¿à°¸‚ÅŽÏè´zÍnSËW·|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíÉpHîòó!ðGôøùöIúþúüfüH/  ‚ÛŒ‘°aº…YJœhâ Š¿Y¬‘±£¶þC^)²¤4’&S6C©²¥Ë—0cÊœI³¦0–6sΩ³§+žÊJ´¨QÊ€ÒTŠì¨Ó£>Ã1=ö´êШংÑúŪU¬`{p KvÓØ^«–];ç,Û·‘ÜîHû®Ý"rïê=”w¯ß¿€ ¶ÑwðŽÂ†ËAL‡.QÅ 9¾¹²å˘3kÆ4ÙèæÏl: Sôã@¦)“n™Z¨ ÖHWË{¶í.µoëÞÝ…1ï ¹Oð-<¸ðÄ'—ÜIóÝËÇ=?NuëêØƒDÏν»÷ïàËO>Oîíå=¡·>ý öÞà»$þüú.ñÛG{²þýü`xø]!ù,(‚VþðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pHäÑŽ´¢rÉl:ŸÐ¨tJõ ¯°ªvËíz¿à°¸‚ÅŽÏè´zÍnSËW·|N¯Ûïm8Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö±zG÷ûûùIüçù›° ¼2 *d‡0ÆÂ‡èfHqœÄ..VÜîb ŽÒ ·y IÛÈ’(§LÉÒÙÊ–0“½Œéd&M:6o*É©³ç.ž=úÌ$ôfÑ¡HñiLÊôÖÑWO›\*µ*¬¨V³>Ä ’«VG^¿Š½6’€³hÓªE­ìØnßþˆ+wÄIºuóªÁ«·ï ¾åÖ ,À¯áÈ+Ö x±ãÇ#KžL¹rJ˜ÙZÞÌ¹óæÆžC‹Mz èÒO金ZªêÖ°Y¼ŽM»v­Ì™më^‚óîßCzþ¹t6ðãÈ“+_Î|¬ðÁ’7?.}úïêÓ#!ù,8.RMþðÉI«½8ëÍ»ÿ`(Ždižhª®Và¾p,lmßx®ï|ïÿÀ pH™gĤrÉl:ŸÐ¨4w¬¾¦Ø¬vËíz¿A«L.›Ïè´'®®ßð¸|N_¶õ¼~ÏïóïF~‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôX€HõùÔ÷2úþÑübüØ, ‚“¼Òk¡‹„ïÒ€HQ˜ÄŠ]L±1£ÇDÈO„üHrÖÈ$'•¥,Yh¥—Ç`²ô#sf…š6õàÌù`'Ï9> åTGÑ¡Hmeã°âÒ¤#žÊ ÈD*TVáQµÓôꎬ^%µ6öMYˆg§¥M³vS["oŸÅ}Ùu®>»aQlÄ›·¯¾~“Ü…°àn†+¶×u±ã–k%~Ìj2åËp#cÞÌ™åΠ©hMºÌçÒ¨ŸNÍ:êèÖW× ;í·k“}m&·î}¼ w½PBYßÃÑùFž¼6óÖ!ù,85RIþðÉI«½8ëÍ»ÿ`(Ždižhª®Và¾p,lmßx®ï|ïÿÀ pH™gĤrÉl:ŸÐ¨4w¬¾¦Ø¬vËíz¿A«L.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòDbUó÷¾õGøüºúF…þ!éGP…@Æ(XP! †h^H±•D3ªºHC# Žž?€ ég$É“žLÊRÈD%JH._ÊœI³¦Í˜6£àÌYbgŸÜ€îŠ’h6£xò„§ÔNS-O—JJµªÕ«¡¢bÝʵ+­^Ãz+¶l²fÓBAÛð¢Ú·ÝÂK·®Ý»xóê­Ëv¯¦‘}UL¸°áÃüR ü`$âLjç,²eÂ’3‡p|ٲƚévöº´ŽÑM{‰!ù,9‚FþðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pHäÑŽ´¢rÉl:ŸÐ¨tJõ ¯°ªvËíz¿à°¸‚ÅŽÏè´zÍnSËW·|N¯Ûïm8Ïïûÿ€)zG‚†‡ˆ‰Šj„I‹‘’“:3”˜™š››–2œ ¡¢£vž1¤¨©ª«S¦Y¬°±²³-®/´¸¹º»d¶¼¿ÀÁ£¶5ÂÆÇȉÄÉÌÍÎtËÏÒÓÔ]ÑÕØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýî HP€¿ƒÛ\X0¯„Ç1œС«ˆQ¤(aãD‹þ¦2ŠÌå‘aÇ’ Ù\É’Ê”/ ‚ôԲ檘Oâ8Ó’ÍŸ¤vV| ”§Ê‡@“n*jhQH•J•ÃÔIU§B¡^|°rª×%W»–¸Jö)ׇb¿ª 6ª‰²Y±î”-íÚ»<ÚnEw®\œtѺÅKX‡Þ)úþ3ðV»ý NlV2Å¿tŒØ²>Ï“ÇVLófÍ(9Ó<ÚèQ]Ò¡)ÇÝÃtjH«½Þ›ÅáÜ`Í^uísÑnĽ}æ­ÄvÉHÀžœïräÁã7^<Íôâ´«{øÝ=»ßíºËŸùÞú,óáù¡GãÜcFö„T«‡{Ý|DÿâŸøé¡_{( (N€†0(ˆ‚=µW Za÷Žƒ`„¬YÈß{$pø†臈KLXF…Ô…ØŸ:&ö#(*¡¢ƒ¼BÜ̈‡wðH„¶(M}EäOëöj|Ïïûÿ€'sbxy9†‡7‚ŒŽ‘H„P‰Š–‡’š›œž”O˜y£vŸ§¨©ª«I¡QŠ<¥g¬µ¶·¸¹®3³f¾TºÂÃÄż2ÀwÆÌÍÎ϶±zÐÔÕÖ×}Ò:ØÜÝÞßàáâãäåæçèéêëìíî(Úˆïóôõšñ8öúûü{ø‹¹þ¡Á‚,F¿ƒÉ ÔRL‡#iøB¢Å‹3jÜȱ£Çá CŠI²¤É“(=P¬‘²¥ª…WJ鲿'˜ iÒ´ÉóÞ?ˆ:)ö '  ‰*mdôàÎ¥PY5-ñÔVU?È¢j½ru«…¬^ÃN*زhƒtM‹m-ÛZnßR‹+·®]!tïêÝ‹´àL²{¿É+©/X‚œÊ0¯¿I[NU̱Ǯ\0þ3™OgÊi,wÁJsä@Ÿã¤“¬h ¯Ó¬~3›u¿Ø@pc¬m»›îË›kñ&2¼·qÈ~%ÿ<Μøò„Å›K}ºõëØ³kßÎ}Åo‹Õ»‹'~|Ú!ù,8nGþðÉI«½8ëÍ»ÿ`(Ždižhª®l[ p,Ï´àÞx®ï|ïÿÀ pH,ÖŽµ¢rÉl:ŸÐ¨têDZcÔ¬vËíz¿`îõ.›Ïè´z [Ùð¸|N¯ŸÝH»~Ïïûÿ#xG€„…†‡ˆ_‚I‰Ž‘*‹4’–—˜™Ž”3šžŸ ¡iœ2¢¦§¨©F¤0ª®¯°±$¬­²¶·¸°´6¹½¾¿—»ÀÃÄÅÂÆÉÊËhÈÌÏÐÑm´ÒÕÖ×>ÎØÛÜÝÞßàáâãäå|Úæéêëìíîïðñòóôõö÷øùúûüýþÿ ø ]‰*\È0Á‡ ’hH±!Ä‹%ލÈ1!Æçþ4‚IÒ„È’(Sª\ɲ¥Ë—0cÊœI³¦Í›8sÂéØQ§O<9þª/hE¢Hí¥˜”ÞɇK-6JµªÕ«X³jÝʵ«WqQ~ -ìB²WŸ2«P[h«ªýó¡ÛºqÁÍí±·O]‡yñõÝ1xÏßÀ‚©)Å‹Ø^ar‡o{Ü/2bÊ0»ˆ¬Yr…ÎÝ@Oíi5–—œ.}m5šÔ¬c‹‚-»¶È´më~’{#ãÝÀWàþ}¢wðã!†¿U¡œíÝåȵ67ëdzØèØÍXš½ûãA\›ï½¼y|äÏ«/!ù,0‚QþðÉI«½8ëÍ»ÿ`(Ždižhª®l[ p,Ï´àÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°Ø›ÍŽÏè´zÍnSËX·|N¯ÛïmxÏïûÿ€)zH‚†‡ˆ‰Šj„J‹‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîï^òóôõöðùúûüî4ý <ñoÆÀƒ=”‘°¡Ã µ<œ˜0" ŠZ´‘±£GKþ?Š4²IÉ‘(A\²2¥Kq-_Êìs¦Ml5o꜖s§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JªÑb°{XïQEØWÖ¯ó¶ìz ,X±U#^5›­@²¶Ø¶uÛn-¹XéêuVp¯»nû2²êW ^­ºަ˜Xc+“!̘ò`µ¨"Ó|ƒóÏQ@K~cÙˆh4§S¥]mõ©Õ‡í±îåš`iÔ·IÄ®7›Wm¿‹ïݬäêáCWf<÷åA /ßì\„ôé3WqûKí˜Qt÷žr<óäÝí¦ }zvëþŸß&¾¼”öñÑßÏ[þþ†ñ_€r!ù,/nTþðÉI«½8ëÍ»ÿ`(Ždižhª®l[ p,Ï´àÞx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíV5ð5îóÃñö1ôùw÷÷úþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢ÅNüì]Üx(c<ާ y„²äŸ‘òLªT…’ÆÊ—0cÊœI³¦M9-gÜÜY&§ ž@ÃøÄÔËPÚÈ ©Ó§P£À£´(¶ª¤j•jµk¬[Ã:õJ¶¬Y^XM¥ý²ÖˆX±goµí27îÀºvó Á«×*ß¾€uüÅõ6làÈG NÌØÄâÆ#KžL¹²e}/kά¹s)Ξ“Þº´éÓ¨SŸ­UuhÖ\]wŽ!ù,Nn5þðÉI«½8ëÍ»ÿ`(Ždižhª®lë~A,Ït¼x®ï|ïÿÀ pH,ºlH›qÉl:ŸÐ¨tJý%¯²ªvËíz¿à°xL.›Ïè´z,h»ßð¸`M¯Ûïø¼~Ïïûÿ€‚ƒ„…xrˆrjXX†Ž‘(‰”n’—˜™šK••*”›¢£¤¥& ‰Ÿ¨Š¦­®¯¦«¬“²p°·¸¹†µ¶)¼oºÁÂÃv¿–¾ÆsÄËÌÍ]ÉÊ´ÆÐÎÖר§ÉªÓÕÙàáâßÒ¿ÔÛãêëÎå'îìñòñßõéóøùàöÝðúÿƒñ;çí^Àƒø#2ºn #J|±pHÃZ NÜÈQDNøé.ÊêH²ä‡ŠBD®ÊèФ˗ä Q‰ ¦Í›%P¡ §Ï:_URæÏ£H ~œYtiÒ"CŸnˆÚƒ*ž¤jduGWX=mëç+Цß¡mIV £+IÍâ Y?£m»¼M"a/’¼@ä^ ›JiZÀzýÖ@ìE°ˆÿQ¼X2)ȳ,ë¡Lc˜ãvk1jÞÃyÆhQ˜ãœÞ\:ÆjM©{½ÞúùRí·gëΖÛîáÝÀö6Ç6¸q}ÃÕ:=ÎüKr¿âmN]ËóœÓSf¯Î½Ùuß»‹—~¼ùóèñ•OϾ½û÷ðãËŸO¿¾¤õöó‹!ù,/‚SþðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖdÙÚÛÜÝ×àáDÞäÞâçè;åëÚéîï*ììðôõ!òëb5û5öþøÊÅ h.¿ƒ1þ)LD° ІÝ$!D¸°bˆÜbÌ&q"? þ?Z·±]Š’#…Ür%‘$QjÜØÑ¥ ˜8+ ü–³'¸5mÂðI´šÐ›E“*]ÊÔЦP=J5ØÔªX¹\õ²5«W+]µÊüJìX0a˪e’VKÛµpžKÕÛºx;ÝÍË·¯ß¿€ œa/,ĉ!¦‚íÜÄÌž.VÑqIÈÏ$?.Òø×d)Ÿ©j¾œ¤³¯ÐPPCU—u×KaOMsšl%·‹æ¦m:ZnG>øyïÊÅ]OŽáxCæÐÛ,¿2=ºÒêUvoKÚº쌷/ï«x6äá¤/¿e}êó ᳟O¿¾&÷ö󳕯¿¿üþ$(à€X €&¨ 6øƒF(á„Vhá…„!ˆá†D!ù,0‚QþðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌcÏÐÑÒÓÍÖׂÔÚÔØÝÞyÛáÐßäåpââæêëìíîïðñòóôõö÷øùèáúþÿ ,”%ËÀƒ¯L’°aÀ… Jœ¨"Š“YT’±ã»þ4<Š Áo›,3FªìPR› ”2TÀÔ²²&¨™0dâ´É³N)~öJ´¨Ñk-¹]ê+é4¦Pw9•¦bj´¨XY÷`ë3 ^«e›Í+X³]Ñ’]Û'ìÙ­o­Vuʶî·iáæ•›b*¼vÍ „·°Ú~ÏV|ã`@†õ.6‘ØÌä2—GŠÌEåb™5?âü9ah1§Eó M×]j0¯Uç`T¶íB´[ÞÞMml\y ñ{¸qBÅ+ÿ“|WðåÇšëz¢ôêØ³kßν»÷ïàËO¾¼ùóèÓ«_O¼1û÷R®ÃŸO¿¾ýûøóëßÏ¿¿"òý' !ù,3‚MþðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°Ø›ÍŽÏè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàÇeXáåæçèéêëìíîïðñòóoãIôøøöH…ûJùëø£Ño Œ€/<Ød¡Ba$œ˜.¢ Š3jÜ8O€ÇÈ CŠÀ±$‹*P¦Ér¤Š–0?šÔ¦’IÍ7ÄŒ)a'Ì™Ùrz$¢Ÿ-{"u ôÑ!OED ²”iÓ«bÝʵNU]ÊK¶ì—¯!ͪ]˶­[8S‡¡ùÖ[\aseÖåvw¯ß¿€ L^^°…'쫸ñ!ÆŽ# ‚,¹²Ã$SP¶Ì¹ æ‚;·ýœ5´èµ¤O«ö“zµë<­_˦{¶íÛ¸sëÞÍ»·ïßÀƒ N¼¸ñãÈ“+ÿT{¹ó!ù,7VHþðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH|ÕŽ´¢rÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§@Hª1¨­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍs««ÎÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèétЪNìHêñÔïG~ô5òùÍ÷IMÿ (@ŸÁ>üf|“PÆÂ‡#JœH±¢E Y5Éã¢Ç2m äø±d«&S–ByŒ¥Ê—0cÊœI³¦Í›8͸Ìɳ§ˆ>ƒ*´¨Ñ£H“ !È” Ò§ušJµj–©S%`•jµk›­M½ŠJr¬YJDϪ]”v­[+mßÊK·®Ý»xóêÝË·¯ß¿€ L¸ð °L +ØéâÇ"!ù,9‚DþðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°Ø›ÍŽÏè´zÍnSËX·|N¯ÛïmxÏïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²‹zH³·¸¹dµ4º¾¿ÀF¼½ÁÅÆÇ-Ã3ÈÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâWÊZãçè‡åæéíî}ë0ïóôõö÷øùúûüýþÿ H° ˆx6 *\x0ž„£ ¦ÈÅ%+jÜø £!ÁGr”òVÉA'GrJ‹% —*1Át5žÈ˜8MÕܱ²œÆzæ ´($¢7¥ôXS’7U>}2uéè#«Zý¥uM×­`y|M36¬YeÏ6K‹­Z§XßÊ5! ®Ý»xó ˜ Ä-_¿ ô ÖË÷`¹‡ 牫¸1´ÄŽ#KžL¹²å˘WAÎÌÙ‘ÖÍC3-º4!ÒC›^5׬cÛ-»¶í؃s۽ͻ·ïßÀƒ ®R·nâÈE!ù, <j<þðÉI«½8OÁ»ÿ  dižhª®lë¾p,Ïtmßx®ïc臼 pH,ȤrÉl>~ÐŽsJ­Z¯Ø¬v;F¹à°xL ˜Ïè´:@n»M^è{N¯ÛIëüúÎ'Ç}‚ƒXz†g„‰U>ŠŽ8‡‡‘•EŒ@–š›œ“†¡5˜ ¢¦§‰Ÿz¨¬+¤­±²dªy³·¯¸¼½¾¿uºRÀÄÅÆÇIÂÈÌÍÎÏ-Ê"ÐÔÕÖÏÒ×ÚÛÜ·ÙÝàáâ‘ßãaµ{æêÎåëZèjîòÆíóVðiöú½õûþÿG) H° Aý*\h0!Çç9ŒH±b·‰áC“±c ŒþïlD²¤&çŒ4“²e”.i­Œ&ÍŽ6oZÉ©“"ÏžN~e(t¨’¢F93ÆJ6&…ñ´•Ô*U÷]Ú"+ª­}¼"ËU…XSd™Žd·´ì³¢ÒºÅ!÷\w]µ»s/´¼úô›D°&|0¾Õ5eX^c8„‘<ó ñ Å‘›MV·yKå¦vŸÀ,Œo¥¬µ|^{G4äÒO2·I5è`Kicq]‚÷ìÛ1uòíGöâc„3T.¹¸´ÎM0W8½OtpЛžR}û ì° v÷>¼.òèçš•¾½ûãÚßËŸOß1ðúøóg¯¿¿ÿÿ)(à€8 æw0&Xß‚¿4èà|¾sß„vßiº!a†ûD!ù,‚tþðÉI«½8ëm…ÿ`( \ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßð¸|N‡±õ¼~Ïïû•w?ƒ„…†‡…AˆŒŽTŠ"‘•–—˜™)“!šžŸ ¡†œ ¢¦§¨©d¤Sª®¯°±C¬²¶·¸¹'´$º¾¿À°¼ÁÄÅÆ˜ÃÇÊËÌ~ÉÍÐÑÒgÏÓÖרOÕÙÜÝÞ:Ûßâãä›´åèéêçëîïßáðóôËòõøùº÷úýþªüþ ¨) ÁƒLȰaŸ…#J„q¢Å‹c*bÜÈÑŠÆŽþ C"ù(²¤IpíNª\9+%Ë—0kŒI³&;V6sê41s§O•= t¨QŒE*˜t©S„MŸJýuªU|U¯j}—u«Wt]¿Šçr¬YaϪ•–v­[{eßÊM×v®Ý»xóêÝË·¯ß¿€ L¸°áÈ+^̸±ãÇQÕì(€å˘3k°t2eF›Coî÷s,Ѩ/“ÆiWêÔ«IµvýZtlN³oÕ¶­ÔsîA»Cßžô»¸³ÒÆ“SD~4øhå¡|ot®ztææXÿ£žÙ:¨¬Ò™qÇŒ+|MðØçW}˽Yø²½·Œ??nýB¸þ“Ä؃€0¨ÈUóqf Göñ¡O >!- Q…J2!:Äa‡N(ƒó¡¸"&ÞA"1#¾Àaˆk|…/¢£ 3â¨И#Yq¸c†@6Ñ"+9M‘)>àä BÚ‘äMù4e4UV°evY¦Òå7_63¦HgvS¦…Ü=’fk.ö&m:2çq*v'!o&³g y¨`}¶ó' ƒ“(`‡Rye‹©_ªåŠ*MÚW¥dh*Ž‘Q>ÆéžRQê b*ê£/êDªãI0ªC³¾ã*œQöˆá[µ*vk¯ ‹Ø¯¬:%ìЋlrÊ+.[\³ÎF+í´ÔV[Ü­ÖŠí…aòj¶Æl ncâŽ+g±æ¦û@¹ê!ù,;‚=þðÉI«½8OÁ»ÿ  dižhª®lë¾p,Ïtmßx®ï{臼 pH,ȤrÉlÆ~ÐŽsJ­Z¯Ø¬vË=E£Ý°xL.›ÏèÞ÷—n»ßð¸|Ž[³éø¼~ÏïSí>~‚ƒ„…†‡€@ˆŒŽŠ‘•–—˜™)“”šžŸ ¡…œ¢¦§¨©ª«¬­®¯°±²³´„¤Rµ¹º»©·¼ÀÁ‘¾"ÃÇÈÉzÅÊÍÎÏeÌÐÓÔÕMÒÖÙIÜÝÞßàÚ½¾ãæEáéáç¦Øìï8êòÝð îõø1óóùýþæûäýHðY@u* v0݇e5\±¢ª‰à²aüf±ã©þÞ4‚äæ±$¨‘$­¡g²%¦•"GºœY ¦J”4s:²Y§ÎŸ„|N ´è¢q]zT) ¤‡ 2ÚFj «ARÝêë ¯¦À–¸×B,×]fG¤­G–ÅÚ)mÍÄmöCݳvµŽ™K†¯Ñ»&m^âWLa ƒ= Ök¸Ü›ÃýËÄû@2È3¹dÆgy#åÊJOðü¹UgŒŸEË ]zÕé‰N6R­ukס#‘í‰öSÛ·¯ê6óºalÇxYÿ:¼ŒoÂÈÏ*_^‚63Ý\o9=!mëÑ]<§¦{ÁïÍ7…/›ž¼{1è³Wm?dü{ÅôMØG²EÿûÅMwÙ’ö€ÓHS p¯ˆ B æW„¡8ø`AÊ'…'qx!Ûa’ဿihš‡êâ%#šçŠšX˜¢ +ZÒ"ƒ3æH™Œ:º!ù,hG"4þPÈI«/ëÍ»ÿ`(Ždižhª®lë¾p,Ïtmßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‰Š‹Œ‡‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»™Ž¾Ž¼Á¨ÄÂǤ¿ÊŠÈÍÎ=ËËÑÊÏÖ×Ô¿ØÜ,Ú¾±ßÀÝä'âáç‹åì$êëí+ïÌñõö÷øùió‰úþÎüý, Áƒ¢ "Ĥpa6~4421¢EV/j<•q£uECª)²¤É“(iu 1¥ËK+_Ê$s¦MD-oêTsçΞ>ƒn)Ft´œB“JDÚB!P¥PEM1µ¡Õ¬º.;¶ÂÙü ¨ ‚¢7L¡Ã‡Gæ‚H±â‰¸d`¼e±#¼þËb€¬%Á (ÓŒÜÕd¥Æ‘%MzHI³ŒË–0Eæ¬ÉóÎM&?_#sfÏŽC“$e±ôKQNGžr0#UÄÑ‹;—4U±µKÕ«»{‚,سcÌQ‹¶m#¶XAºûç&\ºxÙÍù5¯_G{å>¸û·°¤À +v†c:‹Á5–ø8kä9!_Þ j2CΠ÷ôjáèÐiúžV¢¹ÝjÔT¥Æ|ê¤5»×°É¨–S°Cܹõ.c8q;Æ»Hžƒ¹¢¾¶Ñ8WîEæ¹èg¦Sçb}»íÞ³tOÞJùðæM¢'ƒ}}Œñî㯂/¿¾}Yçïës3ÿþÿj´à€xHàsˆ %!ù,8>R?þ0ÈI« /ëÍ»ÿ`(Ždižhª®lë¾p,Ïtm߸xíWîÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘<”’—˜›œžŸ™]••¢¦Ž © §¬­}ª°œ®³´µQ±±¶º»¼A¸°M¿ª½ÄÅt©ÁÈŸÆÍÎkËÌLÑžÏÖ×bÔÊÚ¡ØßàXÝ›ÜÚáçèPãÞKëéïðGîÓãñö÷"óóíõøþÿôõã×  A{ ÒSøbßÁ‡š[8±á@ˆ÷H¤VŽ# ‡ÕCÚÙ-)JKŠ\Y‡ä2“'w¤|ɲf—È`Æ´`³'Â~ Yììá³(º G†ò4ÊôRcJ+4ªäi±¨¨j5bu«×¯%º‚KvƒØ²*°ZBûì,Ûj%¼…„SØ\X¨7iܾŒÜLxH\ …Û<¬¸±ãÇ#KžL¹²å˘3kÞ|“/ç϶ƒ-I4éÓL£^H5ë׃\Ãúw¶Ù¶S0έ¨gÞvŸ™3àïáÈ“+?‡{¹s4ÍŸŠ:7ºôë`¬cw!ù,>‚>þðÉI«½8ëÍ»ÿ`(Ždižhª®–à¾p, lmßx®ï|ïÿÀ pHÄÌŽ³¢rÉl6ШtJ 8¯Ø¬V‹ì¾¶à°X\-WÇè´zñzÙð¸Üd®Gçø¼žçîîÿ€‚ƒ„… }H†Š‹ŒŽ?ˆG”•–—˜Œ’I™žŸ ¡J›2¢¦§¨©ª¤1«¯°±²Ž­0³·¸¹ºhµ_»¿ÀÁÂ:½.NÅ4vvÃÍÎÏ>ÈÇÅÐÕËuÖÚ´ÔÛÞØfßãƒÒäçèéêëìíîïðñòóôõö÷øùú²æûþÿûHžÀ‚*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£ÇÑ CŠI²¤É“(Sª\ɲ¥Ãpe\Êœyæš8sv°IÏ):ƒîú)Å'Q(¿Ž"ý£ÔŠPFM•pRT¦JŸBÍ ªªÖ¯-½‚‹R,Ù³#͆¸Š¶í;µ غý ÷V]rçêí˜wo£»~;,¸pB†ì¦8ãÆ"ŽLyÞä6¤ ^³¹2Î-2?íùi ­4?.}ïô„Ô¬c¿rM•Tߤ\eS¤ý¶îߢxûNÞpÙ¼‹{:®¼9:æÎ£{ƒNwµô}!ù,;‚@þðÉI«½8ëÍ»ÿ`(Ždižhª®–à¾p, lmßx®ï|ïÿÀ pHÄÌŽ³¢rÉl:ŸÐ¨tJõ ¯¯ªvËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„@‡ˆ‰Š‹…Ž‘‘Œ”Œ’—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±² XX³·¸¹º»¼½¾;•Áˆ¿ÄÅÆÇÈÉÊËÌÀÂÁÍÑÒÑÏÐÓרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#N«uE¢Ey‘\Üè.㎎ «xL’f¤Œ(Û˜ŒÑ°Z%5.)í‹i)¥Í›WfÁRçÎ_>]ðì´XPC“^;ª´i4¦)V:z *ÍE¤RÝêÈêÕDYMr;Èë×CaG’]ëK+Û·¸ÜzƒŠ†.Ü»xóêÝË·¯ß¿€µ+˜ÉÙa¥£-ÌxáÆI=ŽLyÏäʘí\Îü*!ù,‚pþðÉI«½8ëmƒÿ`(\ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹®hÜȱ£GþC>úHò£È“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§O)@‚~øI4‹P¡E“V9T©Ó§P£Fd DªÕ«X³j­FõÇÖ¯7ºKV†XeÓ=B­ÛlA¼{"îPºxóêÝË·¯ß¿€ƒ³ëA0^Â$ +^̸±ãÇôJJÞhiòdȵ,K®¬™$fZ=W mò³,Ò9£¦l:ÖjŽ_klIöì¶A–É-ƒ7íK¾}“þ‚øïIÆS%g±ú¸šå§ «hîôR×QPwøj÷&Ù§moñ]jù—ã«KM¯*ûöðãËŸ/.<ýšöïë'•¿ÿÿ(à€ˆNê‚`‚-È çiãàƒ8D!ù, VmþðÉI«½8ÏÀ»ÿ` dižhª®lë¾p,Ïtmßx®ËaîÀ pH,Ȥryô9;̨tJ­Z¯ØìôùÔz¿à°xL.«¸N³zÍn»ßpÚ¯Ûïø¼Þ6ïíÿ€‚ƒk}?„ˆ‰Š‹Œ8† ‘’“”’•™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çì y]ò²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´èŒ‘PŒ*Õ”ÃÒ§7šŠ€JJj7«TGaݶ5+¨®ÙÀzK¶¬ÙbϪ­v­Û¶n±ÁE4w]]ŽwãšÈ«7+ß¾PÿL¸°áÈcX̸±ãÇàNÜ ²eÈ’›Rfw¹3ãÌH7‹Mº´é"ž=Ÿ^šºóê×°cËž½¦õeÚAm[Æ T7fÞÀƒ žiòSã.‘+UN¼¹seÌ‹ú~ü¼ºõëØ­GÏν»÷ïàËßj;y)ÓŸG™¾ñzV!ù,nfþðÉI«½8ëmƒÿ`(\ižhª®lë¾p,Ïtmßx®ïüè¼ pH,ȤrÉlV~ÐsJ­Z¯Ø¬v{F¹à°xL.›Ï0/Ín»ß𸜥þÍïø¼~Ï'Ö}}‚ƒ„…z@†Š‹ŒŽHˆ"“”•–—‘!˜œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ H° Áƒ*\ȰáM JÔQÊÄ‹3jÜȱ£Çþ CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ Ú«¢‡zFIm•©Ñ¥LŸÒk µêªV³nÁªµ«W…\¿þ ˈ¬X~f¥=›om!·á²…#7`ݹxmÜÍË7ÆÞ¾€éH L¸0³¿ž©x±ã'ƒ—4~oüôæ­¿¿þþ•+€NF`äˆà‚ 6Ç}b¤`„ÚMHáZ^¨\†öÁá/v¨G!ù,*‚SþðÉI«½8ëmƒÿ`(\ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßð¸|N‡±õ¼~Ïïû•w?ƒ„…†‡…AˆŒŽTŠ"‘•–—˜™)“!šžŸ ¡†œ ¢¦§¨©d¤Sª®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈËÌÍÎÏÉÒÓÔJÐ×ÐÕÚÛÜ6ØßÌÝâãä&ààåéêéçßëïðÕíØñõö«¬$Mó×÷þÿXòécÂ/ÀƒåsRðY‡…dذYÄ‹/U´˜±£ÇCþÃ}IrOÈe%Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÔ“Ѭjõ‡u«×z]¿~Y(–Wز&¢Õu¶¬Úµ¸ÚŠ} ÷ ]jå~½[— _dÝè}÷·o’ªöŠ8YÅ‹µ6&4yHåq—#‡Ễ37Ïš5Î2ºVéЖN[Q-‹5êG®‘Æ~Íh6í¶oãc‡“îß7r/ñÝ:0p`Â*š•üø§æ)¡;ŸNÝÚÉêØ³kßν»÷ïà•J¿2ùã¡ïkþ|ôCÛ»ŸO¿>Nùöó£_ß¿þÿÀ- LzQà€ŽÅ[Zü%èà>(á Nh¡ ^ø^ƒ÷¨•¡†ó}b%!ù,6‚JþðÉI«½8ëmƒÿ`(\ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,H¡`Él:Ÿ‚¤tJ­>€ØuËíz¿S¨ .›Ï,Ín»ßܱœ ¯Û…êõ}Ïïûÿ€Sy@‚†‡ˆ‰Š‹v„?Œ‘’“”•*ŽA–š›œžo˜"Ÿ£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅ`¡!ÆÊËÌ’È ÍÑÒÓ|ÏZÔØÙÚ]ÖÛßàáxÝâåæç.Ý$èìíîêïòóåñô÷øÓöùüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ CŠI²¤É“(Sª\ɲ¥Ë—0cÊœ iÍqÖnⲩsÏž±~½!t虢—ÈÕté—¦( UJKªÓ-VKdå1gŽ•­W%‚]ÔUÎW¥cÃÎK›¨ì˜³9¯PÆh]söîæÒKƒo8¿àòÎm8Fám‡&–µ¸EcjùF¦–X䪃÷P®ÌTæ;›;‹>ú¹Q¨Ñ¨Ë\.:µk¸Ï^ËÆ¶z¶íTµoë˜{·oN½/ÿMÜqiË+zÜgóåÐY?N½ºõëù’cßË­‚ãrÃ;™*ÚÉï6ÿvkõðS°w_òôyó›HH_¿þþ H€èœx!ù,7‚GþðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z%‚¬vËí ®à°xL.›Ï!¯Ú‹n»ßð¸|ZÛµô¼~Ïïûwwƒ„…†‡{vˆŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ5Ù5×ÜÝœÚà1Þãä“ááåéê‡çàëïð{íÚñõönóÙ÷ûüaùÛý H° ·4 *\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç1Ãg|)0¤ ’(Sª\ɲ¥Ë—“­I³šL55sê¬p“ÍN&ÅýŒÔ³ËÐAa…T”ËÒIm̸[ÈÆk=Žd1e'“/k^•y³çÏ C‹–cy´•¸¦1”öŒÚ¬Ú_«S¯k-»6Ó×¶sëÞÍ»rßÞÀƒ N¼¸qa±+w!ù,8‚IþðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|%üÀ p(èȤrÉ4Öžµ¦tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâyPå1ãÉDêDèVææíÇëó@ñTïå*øPö•ôôý¤ì{¢o €“þÍCÈÄàÁg0Œ¤pÝD%e\üUQÝF$þÏ}äÕ‘ÝÈ!aœÜUrÈÊ—/[ Ió£Ì 5y¥´‘ÅÍz=síDö󇕢E‚⪴Ҧ·˜Bñ´]UNR§j5ru«Wk]¿Šv¬YfeÁ¥= m­7·l›Áå6÷Cݸ™îfÓË/^EUøß¿ˆÛÎ@ø'¸¬‰-ÆÐøæã”Î Çš|£rEZU5#ýг Ï A&mŒu+Ó-PÿSíøk>·ä^)à,؈vGn|sáá ‹“P®ø8ò€Ì]Eß4ý¹õNÕ¯kßν»÷ïàËO¾šðòè1=Ÿ¾½œõ˜Ý+Ê.¿¾ýûøóëßï‚=Q!ù,9‚IþðÉI«½8ëmƒÿ`(\ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,H!pùI:ŸÐ¨tJ­Z¯X“™íz¿à°xL.W¶K³zÍn»ßp,¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚ»ÝÞßàáÛäå|âèâæëìpéïÞíòóôõö÷øùúûüýþÿ Ü1çÇÀƒ7 ’°¡Ã E<œH,bAPÜ <ŒØ=pÉËã;!IªÄe2ÊŒ+Õ„JKt/-ÖÜ ë¦º3Iðº-è"£o|†#º©¤NÛ(ÇÔ\T6Pgʘúm+×nUÃ’ú 6ÙqbÓ>;«¶-3¶nãÊË’ì"¸tóêÝË7ÛÔ\xû®ü[÷«àÈ+^̸±ãǦ®:“ ¹eBH»¸\¨VQœe¶ë9egl¡¥²ú4³Ö~`óííÚ¸sëV|{·ï>½ N¼¸ñãÈy˜ÕtòçWšÃ„NÊòêØ³ku}û¤!ù,8;>HþðÉI«!ëÍ{¸`(Ždižhª®lë¾p,Ïtmßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø˜gëÉz¿à°xL¦pÏš²zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾AÁÂÃÄÅ¿ÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêºÆíÆëðñThhòö»ôg÷û·ù\ü–ò·E ÁKî ;Ȱ¡Ã‡9*„H±¢ED»”ÉØAGt/~Ü fdš&3ÀJù!$–‚`º¤(Sb™8óÈÌɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©'›îœJJµªÕ«X³>…úN+Ñ^·õ36,¶²fÓª]+ -Û·pãÊK·®Ý»xóêâv¯ß }ÿ ,ØM!ù,<‚GþðÉI«½8ëmƒÿ`(\ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßp7¯Û1óß}Ïï#óA~‚i€"ƒ‡ˆ‰>… ŠŽ[Œ“”Š‘S•™L—šžŸpœ$ ¤¥¦§¨(¢©¬­®¯«°³´µ¶c²·º»¼½B¹¾ÁÂÃÄÀÅÈÉÊ·ÇËÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèé%ÍêíîÙìïòóÏñô÷øÁöùüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹¦öaÜÈÑ…ÆŽþ CŠI²¤É“?¢\iQ¥4—V`²¼&s¦†š6§áä³óSÏœõ8ú©‰(PT’*]Ê´© FJíæ´ªS¨B§jgµ«R¬—Ödݪj,YJQÁFRË(gÚ³¼dÉ5Ûð-Üv—Ì ûàmÞ»ÿ&Ù»¶/Ý~ u‘ñÂm}*ææøaå"'Þüä2®ÃœC?-ºt;ϦSÇ$mµê×Â\Þ½Kö]Û´?óÍí‘5ï3¸wð-¼¸ñãÈ“› ®ü(s,ϛی¾z·ôël'S¯±»éî3À{-þW¯ãY•×G|Èù®éã¶.¿¾«õöóëßoú½UþÁD!ù, Ej>þðÉI«½8ÏÀ»ÿ` dižhª®lë¾p,Ïtmßx®ïc臼 pH,ȤrÉl>~ÐŽsJ­Z¯Ø¬v;F¹à°xL.›Ï,/Ín»ßð¸¥þÍïø¼~Ïïûÿ€wu>…†‡ˆ‰Uƒ@ŠŽ‘’tŒ“—˜™š•–›Ÿ ¡¢\£§¨©ª<¥R«¯°±²­³·¸¹º»¼½¾¿ÀÁÂÃÄÅpµ"ÆÊËÌIÈÍÐÑÒ6ÏÓÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïð¢Õñôõqóöùúdøûþÿ xB€Áƒ*ð®Á‡4J\±¢E3¼È±#;‡¹œjy餓$SòA¹R¤Ê—0cd‰J£F™8›Ðb3£“ž_íÌ)ih  % ¥Ød©B¡.‰†sšP)ÕO¢š3*UÚU¬_ JລÓ,²]_…e˜µÕ±Jgµ¦å†v®Ý»x½†•±Öê×¼€±õ}08°ahƒ ^l,ñ^Ɖ)ŽL¹2Þº–3kÞ̹³çÏ C‹Mz1f<“K«v‘ÉéÕ°g´ŽM;ÔìÚ¸3ÝÎÍ»·o߯‹!ù,K‚8þðÉI«½8ëmƒÿ`(\ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßð¸|N‡±õ¼~Ïïû•w?ƒ„…†‡ˆ‰Š‹ŒA‘’“”•."–š›œ‹˜!ž¢£¤¥.¨©ª«¬k S­³­¦¶·¸†´»©¯°$²¼»¹ÄÅÆpÂÃ1¿É´ÇÑ)ÌÀÒÖ)ϳ¾°ÎÙ¬×àÔáäÞßËÌÝç½åîãîñìªNôíòàðùñ÷¨öþø HЂ?WM\Ȱ_À„JœhL!Ä{3j4e‘IÇþ CRú¨„¤È“(Uì[bIË”0c^XIì¥L6oN¢™ËbÎ1<½üÔÙ(è-ŸY>4Êe(ѧub¼HOÓ-N¡jEö0+‹WµxÝJöŒÔªTÙ![¶­˜³jÓýZ‡Ö­Ý»*àžÛ ¯ß¿;Øf ¸°á<„+FömÒÅ·6ú8²#u–›v­ì³›Äv'gV:tÑš§ºé;5d½ÞøbÂËz´íÛijãÞÍ»·ïßÀƒ nÄ4ñãÈ/OÎùòæÐ£ë|.½:nêÖ³[Æ®½ûaîÞÃû/¾¼D×È›ª~kûõðoÂο>ÔùÏìë—¿Yõþÿ"½ H!ù, Jj5þðÉI«½8ëÍ»ÿ`(Ždižhª®l[ p,Ï´àÞx®ï|ïÿÀ pH ÖŽµ¢rÉl:ŸÐ¨tªDZcÔ¬vËíz¿`êõ.›Ïè´zÍ[Ùð¸|N¯ƒÝH»~Ïïû[xGNI†‡ˆ‰|„4ƒŒ2Š‘”•–—˜’›œ8MŸXŠ™¦™¤©ª$¢0Ž¢«‡§³•±¶·­6¡­¸}´´¾ÂÃÄÅ]À³ÆÊËÌÍ<ȧÎÒÓÔÕЦÖÚÛÜÆØ¨Ýáâã’ߘäè¾æ—éíîïië–ðâòµôøBö”ùÜûšý>Û'ÐÚ¿‚oL¡+!š…#ž€x¢¡Ä0/jüñE¯Ì^:‚yAä‹ýP.1I²å–!TºœI³¦™6sêÜɳ§˜>ƒ -Ep¨Ñ£Dí!]t©8‹Mmâ$Õ)7¨ENRÕª¶­^* K–X#v-ëó,·ôÖ²å ×GÝwrç꼫EÞ¾5ùü7¬àÁ} ÿÌŠ¸±cŠKiÎ ãɘã¬;¬'ræÏQÖMZ„èÒ¨S欺µk8¬_Ëv{¶íjµ+ä¾Í›Ùî ¿{ |¸ñzE‹_ÎÆó„…XÇ2!ù,PG:3þðÉI«½8ëÍ»ÿ`(Ždižhª®¬$¼p,ÏBkßx®ï|ïÿÀ pˆ¡iĤrÉl:ŸÐ¨4s¬Â¦Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬—VV­±²š¯U³·¸‘µG¹!¿ÀÁÂýÆa»FÇÄÍÄËÐ[ÉHÑÎ×ÀÕÚQÓ3ÛØØßãKÝ2äèédæ1êîïÒì/ðôõNòóöúû@ø5ü@Â]H°` Î *\Ha³}þJœ¸!b ‹3~Áø‡£Æo =‚ P$É“g>Kcr•Êa(ÿ¼¦¦¥ª™ÁbúÁ™%>\<éDis¨Q9A‹5)z´©1¦w’:ºª©T³jƒu«WY]¿Šdn¬ÙVeS=ËvHZ3a-YmK—Òܺx7þÌËÓݾÇ"!ù, Kj4þðÉI«½8ëÍ»ÿ`(Ždižhª®¬*¼p,ÏBkßx®ï|ïÿÀ pHäÐŽ´¢rÉl:ŸÐ¨tªDZaÔ¬vËíz¿`êõ.›Ïè´zÍ[Ùð¸|N¯ƒø¼~ϸÜGv‚ƒ„…†‡€ˆŒŽZŠI‘•–—˜™&“3šžŸ ¡fœ2¤1¢©ª«¬B§X¯/­´µ¶·!²5±²¸¾¿À´º¦½ÁÆÇÈ‘ÃÉÌÍΟËÏÒÓÔ…ÑÕØÙÚ£ÅÛÞßàP×áäåæ:ãçêëì¹Ýíˆ}ò}ðêé$÷õ‚óüyúæùDü7§_?‚ä‚Pˆ°‰A~ÎkŽ¡‹ÑH”—ñ Fî7„Tµ‘Þ£’|:z™ƒ%—*¹ Ü“Õ2˜pÖ¤2SŠžþvf¹ùN¨1 x~"5*¦˜N¦šúI!ª¢¯’U%·EW«N°ž ö+Ù%bI…jv-‘§n™¶.ÝsïzØj—]ß¼zÿñ-jõïÒÀÖ#Nœ•êáÅ‚úB^©xÄàI“»HÎŒM-gI•?×ólsӢײzaèF¨SËnÑ:ÑkFi9ÍÞ}£öÅÛˆbóN·6áÄ“0ž ¹òçCŸ~W:õëÇúZÇÎ[cÚw\|‡ðßÉ«‡„~lŠíë}E!ù,G‚8þðÉI«½8ëÍ»ÿ`(Ždižhª®l[ p,Ï´ x®ï|àþÀ pH,ȤrÉLÖžµ¦tJ­Z¯Ø¬vËõ@¿±®xL.›Ïè´º¯ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„fm_…‰Š‹Œi‡POŽ•–—˜™l“4’œ3š¡¢£¤wŸ §2¥¬­®¯vªa°´µ¶·U²0¸¼½¾¿)º6ÀÄÅÆÇÈÉÊËÌÍÎÏÐ\ÂÑÔÕÖqÓ×ÚÛÜYÙÝàáâDßãæçè#åéìíîž²ïòóæë‹öôù[ø‰ü…þúR8ˆ Àƒ "\ÈЕÂ2Jœ8!â‹3"ÄØ…£F\à=BöøHÂã>]$Sj4©…¥F‘0s¨dærf¡˜1m*«©³§Ï–( º†§ £D“žCŠ‚)7œ0B9Ñ© «J­M Y5è@¯Y¥nåÑ5^.°a±ºKV¢ZuhÃêc»C]ÀÞŠÐ+·Ù]™)þâèK¸Ò©9‚}\¸ñÏÄv;žŒr"Ë_ÍÎáK™fBŸ·qî,*´ Ó×F“Ö„ºHëjHU¯Æôzvª¸%qÛNV{·Ù¾õN¼ø±áFbë6Μò"Ê57Ÿ^ç9¹åԳò®½»÷ïàÕpO^`!ù,G‚9þðÉI«½8ëÍ»ÿ`(Ždižhª®¬$¼p,ÏBkßx®ï|ïÿÀ pHäÑŽ´b%Àl:ŸÐ€rJ­Z¯Ø¬v;DzaÖ¨8Ê-›Ïè´zÍÆ|¿á±œÙ®Ûïø¼~ÿöÆçc{‚ƒ„…†‡'}H€dˆ‘’“‘ŠG*”›œžŸ ™b¡¥¦§¨©ª«¬­®¯°±²³´µ¶–I·»¼½¾Z¹3¿ÃÄÅÆ6Á2ÇËÌÍÎÉ1ÏÓÔÅÑ`©×/ÕÜÝÞªÚ5ßãäåáæéêëuèìïðñUîòõö÷8ôøûüýúþâ(° Áƒ*\Ȱ¡Ã‡µAœH±¢Å‹3jÜȱ£ÇþxF9"RžH(%Ñœ|âBbÊ{+´¼63ÚK 1›ÔLvÓ^N:Ü‘ìùà§” .‰¶0Š)RšOm*]òsg°ŠCE8ýäThÒ©¶‚Ê3…ØN]]fËVÄZg9¥…úöGݶ ãÚò •Ê]¼õÖâ+ÕïWÀ {#\Öp_Ä©1¾:ïpäËË&ç²ò³ç+ù¨µL¤óçÓBëÑl‰3é.¯QËÞÁZ¦ªd)ÏÞ=xôcs ó«vŸÛ9­n&Îü™iœ¸Ÿ7Ÿ®Cqé‚7¦Îˆu Øo„ïNþÄw»±¯§/ϾÕxCçÛËŸò¾Püùø…ÔÏÏÿÞþþ (à€˜n&ÈO!ù,G‚9þðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏJßt«ï|ïÿÀ pH,<œf[*‘ШtJ­Z¯Ø¬¶é¼m¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ_]8€„…†‡ˆg‚^‰Ž‘r‹9’–—˜™”3šžŸ ¡qœ2¢¦§¨©U¤1ª®¯°±)¬L²¶·¸¹º»¼½;´/¾ÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙCÜÝÞßàÚãä-áçáŽèëÝåîï$ììêòèð÷øõöûçùJð—®Áo]K˜ì Bƒ¹1Vƒá±ˆí F´ÈqF‰ÆvÌ÷Q\Ã*JVQ9òKd,c¢¤ò²¥»šÆpÒiSÏa?íimh/£}]êKé§L£â‚š‡j&ŠRGZÍj+ׯ`Íx K¶¬Ù]cϪ]ÂkZ¶pã^p»P®Ý»³êâÝËÓV;û N Eà,^^¬Fñ•Ä3K®‘ãɘÁ\†³ùÁÛÌ ;‹ݦógÐIƒPº5=ŒHX»žM»¶íÛ¸sëFtzwGÙ¾ƒÃ¬,¼ø;àÆ“óB®¼ù­!ù,8IR4þðÉI«½8ëÍ»ÿ`(ŽdižhªfAë¾p¬tmßx®ï|ïÿÀ p˜’eĤrÉl:ŸÐ¨4w¬º¦Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯ÛÕVë}Ïïûÿs‚ƒ„…†€‰Š‹ŒŒ‡‡yU•–—˜L›ƒ™žŸ ¡Kœœ¢¦§¨©ª«¬­®¯°±²]“G³·¸¹nµFº¾™¤›¿ÃÄÅRÁÆÊËQÈΑÌÓÔCцÕÙÚÛÜ{¼HÝáâãäåæçèéêëìíîïðñòìß1ã×…óúûüpõ0ý H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱc®U/<ŠlòÊÈ“K¶@ɲ¥K *gèÃGè%Ę’TÚ¼sg¨ž>ƒºü'´¨;¢g€]Šƒf'?J¹EeJµªUŸS¯jÝʵ«×¯`ÊK¶ì˜¬fF!ù,J‚2þðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pHäÑŽ´¢rÉl:ŸÐ¨tJõ ¯0[íz¿à°xL.W¶W³zÍn»ßp*)Øïø¼^ïûÿ€‚p{…{ƒˆ‰Š‹ŒdsG‘’“”•~I–š›œž@˜3N¡2Ÿ¦§¨©>¤1£¬/ª±²³´¯°M·5µ¼a†¿w½ÂÃÄÅNÀÀÆÊËÌÍ)È¿ÎÒÓÔІÕÙ`ºÚÝ+×…ÞâQÜãæçèŠåéìíîïðñòóôõö‰ë÷úûü#ùý tqk Áƒúþ!üîЇ#Jœ¨L!Å‹#•³˜qàÆ‚Š—||òáHV%•pLɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£æêAÊ´é¥yê­tª *ª_¦bÝT+V¯\í1¶éIRaá”ݱ6퇶nã„‹­Ü»RA¢°[Q¯<ºxo¶À7°ávƒÏ„:̸±ãÇ#K®g5ØäË#!ù,PM:1þðÉI«½8ëÍ»ÿ`(Ždižhºlë¾p ¢Bmßx.Ì|ïÿÀ pH,ÈKlK:ŸÐ¨tJ­Z¯N¦¶¥Ún±à°xL.›Ç^m7½<»ßð¸|NG²Ûõ¼~Ïïû­wMƒ„…†‡ˆ0‰Ž‘I‹/’–”.—›n™\Už,œ£¤¥¦¡2 ¡§­®¯‰©€¬°µ¶·r²¸»¼½¾º¿ÂÃÄÅÆÇÈÉY´ÊÍÎÏqÁÐÓÔÕSÒÖÙÚÛ>ØÜßàáÞâåæçèŠÌéìäì¤îïáñòõö¼ô÷úûüýþÿ1ä XJ×@‚W ®CøJ¡'†h„hÉa&Šf,RÂØp!ÇAq}I²¤É“(Sª\ɲ¥Ë—0 MŒI³¦Í›8sêÜɳ§ÏŸ@ƒ *Ó#Q"3‡$=ªÄ(Ó K¡:}:n*UXQ¯ª{h,«µ´Šð*¶,?²6š]k -µlãnr;®Ü»èâÝ‹K/ß¿¹:‰!ù,I‚5þðÉI«½8ëÍ»ÿ`(Ždižhª®l[ p,Ï´àÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°Ø›ÍŽÏè´zÍnSËXI`N¯Ûï·~ÏïûÿNpI€„…†‡ˆ‰)‚HŠŽ‘’jŒJ“—˜™š‡xx*•4›£¤¥¦^ž©t ¡2§¯°±²=ªª¬­0³º»¼½µ©·¸¾ÄÅÆÇÈÉÊ*ÀžËÏc¸ZÐÔ8ÍÕÙ[Ò¹Ü6Úן˜ãwáè{ßéævìðñoÜò,ëõø¨î«l÷ù'þþ ”²ßš€E LÈÐHÁ9m6ì q¢Eóô£wñCÅŽþ odŒÈ1ä†&S¢¹QšJ (_Bc‰,fJ›2•Ñ<†3dÏœÇvøs(1¡ïÝ´4%RHOó)-É«©É¨B¬õÈQë%¯±»õdWª»ÈZ dªË²Üó¥v"Ûr[Á{öm¯{wáî‘7Ô^ …+ý|¸±¢ÄŒ® ÕÅØ±åBIöË«òåÏ}2ÃÙzøI¨H„6A¡ƒvH܆•`èáˆð$H≠ƇâŠ,>§â!ù,8@R>þðÉI«"ëÍ»¸`(Ždižhª®lë¾p,ÏtmßxŽ{¼§ÿÀ pH,ȤrYé95̨tJ­Z¯ØìòùÔz¿à°xL.›¸N³zÍn»ßpº¯Ûïø¼^6çíÿ€4}>‚†g„‡‹Œ‰ŠŽ’“—˜v•P™Œ›¡¢£¤nŸ¥©ª«¬J§­°±²³.¯´·¸¹´¶º½¾¿˜¼ÀÃÄ)ÇÈÉÊËÅDÂÎÑÒÌÕÌÓ@ÐØÛÜÝIÚÞáâミäçèé*àêíîèìïò»æñ¬÷óú#ÖýÈp¶ò©¸¯`þ:¬ç‰¡Á‡"öFOEˆû$Z£èðÐE/ø«a$ò°TJ.ë¤RÙÈ1-“qÜD©ã˜ÿ2á<öRÌÎf'ë¡ìI´è—…4*]ji%¦P£zq IªÕ«R¨&ÂʵÑO…Bmv«çk&­„È*ŠÅl°°IÕe{Å­Ü»ÅèZ±ÛN/^£|[Nç÷/ÑÁ†C í’¸'âÆ§Ù"òÇ–1Àíäpæ/˜?K¦C9®»Ð†P®µµôSyªWníªò¹Ø²s¯Æ­»wcÞ¾ƒßðÌr§ðãGlGμ¯íæÐ£KŸN½ºõëîˆcß>N;÷ïàËOþÝr,Þ˫ϕ~½û÷ðãËŸO¿¾ý(çï!ù,4‚IþðÉI«½8ëm…ÿ`( \ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßð¸|N‡±õ¼~Ïïû•w?ƒ„…†‡…AˆŒŽTŠ"‘•–—˜™)“!šžŸ ¡†œ ¢¦§¨©d¤Sª®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌh¬ÍÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùjüýþÿèH°JÀƒ *\Ȱ¡ÃiÏH<œH±IÄŠ3nz¦±£Ç½ CŠIrÇ’(^Lɲ¥Ë—0å œÙ/Mš/oÎŒéM'œ>òê.¨P¢H“*]Úm%Ó§&YÁq µª6ªV³VÊŒ«)¯Z߀ [d,Yg'Íqzdö¬[amßÊK·®Ý»xóêÝkÌ(@¾€eùýXS\¨ƒýÎtøiâš‹#›zÌO²]Ê-×Âl“rçÇšCgâ,º´éÓo£^=G5ë×n\ÞmF6íÛ¸s‹!­»·ïßÀƒ?á-¼8–!ù,)‚TþðÉI«½8ëm…ÿ`( \ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßð¸|N‡±õ¼~Ïïû•w?ƒ„…†‡…AˆŒŽTŠ"‘•–—˜™)“!šžŸ ¡†œ ¢¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóô&¤Súûüýþõ \sD¾ý \ÈpSÁ†#â(hP¢Å‹-(bÜÈÑÞÃŽþ C~ù(²$G&S^D©²eC–.c„)³f<š6s²Ã©³ç9ž+ Ýç³h. *†•¡T¨¤F£"Š¢iB©XcQ=aaÖ¯­¶‚ÛL¬(³tÐ’e¥¶gÛµ©Þæ” ×Ýšwë‚Ê“¯^M~ÿ ®„2ð`F]ÿÍýhøð¡Ä ?h,eûUÞ,ær‹Ìü8‹Þâ™h¢£S[)­ºµëׯ8ÁžM»¶íÛ­NëÃÍ;“n€½ƒ Ìz¸ñ.Å+Ç’|¹óçУKŸNvóê4~÷¾’{íØ}ë–å=¼ù àËŸ7~½û,íß˧¾ý%õïëßÏ¿¿ÿGùý §‹zº( .h_!ù, &jXþðÉI«½8OÁ»ÿ  dižhª®lë¾p,Ïtmßx®ïc臼 pH,ȤrÉl>~ÐŽsJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑ0QQÒÖ×[ÔPØÜÝNÚ?ÞâãEà>äèé8æ@êîï.ì ðôõö÷øùúûsþÿ À¯ Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç÷ CŠI²¤É“¾ª(a¥Ë(cÊL!ïÃÌd/_«éá&²œ.Õ]éSO)M†ª,ÊtÇQN”²lJÕÆSI¥¬ÊuÆÕ®`ÿ| K¶¬Ù³\Ç¢]˶­Û^Z·¾K÷l\€ucÝ…9l¯¿¼°ü|7°_ÀÇ ¿Œ¸ñÆŽ#[,¹rÖ½2Ô^¢lù g3š;‹.÷TMèÑO“Q:"k1¯[;Œ †¶lš¥“Ùö²û6ÂÞ\€;Íí–p-Çs$/þiùçÌíA¯2=:¼êÖ³cÏ};÷âÞ¿£^¼YòÄÍ£FT½lö<ÝËÏP~~åúößD!ù,8&RRþðÉI«!ëÍ{¸`(Ždižhª®lë¾p,Ïtmßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂhÅÆÇÈÉÃÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéÐìêï¿íòðõ»óóöú·øòûÿ H° Áƒ*\Ȱ¡Ã‡#J„¦¬¢2%ýÚMÜÄ¢Gcö3ºãH’ÇÇDŽTÙK%£ô˜ò%½6oÆ48Ó¢’žkæjs§Ñ&@/âÌù! Ó¦G&M&æiÔ¨S‘]ÝÊÕZÖc]þù R¬Y5d‹Ý˜vY˜¶k'Â}›6®Ä¹`ðÚu¨×Kß:V÷úË…ðœÀ‚ÿÖ²8qÁÆX ;Öƒ8Žd+—'ß ü2o]ºdÅdÖÜ¢ó—ÑSPKQMzkX¯[Šm¡²#ÚlËn¤›W`Ü»Çô¾ÇTðàa†ëúý9àâáŽ;÷¢<›ôé\ªcßå:íÜÏyO^Äøòè+œOÏþúzö Ý7‡W~hú"!ù, 'jSþðÉI«½8ÏÀ»ÿ` dižhª®lë¾p,Ïtmßx®ïc臼 pH,ȤrÉl>~ÐŽsJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊQQËÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíî;ñòóôõïøÞöûöùþÚüÊûGК@ÞjEÂÁ€ #ÎbøÃáÃ}3¾¢èÃâÅzìC®âäÁÇ~"Sú: R¥K],齜y+æ<š8sêÜÉÈæ@ž@QùŒ'ƒ$ˆ Hë ½Ãè>N=$MUJš¥SÕ`ÍjckU\™l ;嫲IÆ¢eb¶èW®j×*iÛôíª¸r¿ÑU…7¯ßD}ÿ L¸°áÈ+^̸±ãÇ¢öBžìÄ«]ʘ—X®š¹sÉdA{Í…®SÒ¨‹˜6šzOà‚§[ËžM»¶íÛ¸Ÿ\v,:·ov¯CÞU¸ñ Äc‹ê–óñq½Gýù¶êE¦ŸÀn÷îàI|OþÂøòèO_~={&!ù,%‚WþðÉI«½8ëÍ»ÿ`(Ždižhª®l[ p,Ï´àÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°Ø›ÍŽÏè´zÍnSËX·|Ž Øïø¼>@ïûÿDpI€„j{‡{…Š‹ŒG‚J‘Vˆ”w’—˜‘™K••ž¢£m›4¤¨? ”©­®[¦3¯³-«ˆ´¸¹±Zº¾"¶‡¿ÃÄ-¼½ÅÉÊËÌCÇ0ÍÑÒÓÔŽÇÕØÙÚÔÏ6Ûßàá´Ýâåæç’äèëìílêîñòóoÏô÷øùBðúýþÿ'øH° *Ô‡p¡Ã‡ìBœHq›ÄŠ32»¨±£GBþÁ=àø±¤I6!õ\±w²¥K”)ñ¬¼ö²¦M01eŽdy³§O:$ ÊE]P¢H“ª0ÊS©Ó§KY…Jµê¦4­jÝša*ׯ`9x K¶ìL^fÓªÅ0v­[¨mßÊE—mÓ¹xÞ}±7¯_yu¯öýKxhàˆ5NÌxââÆ>ŽL¹²å˘3kÞ̹s›œ–”¶ã™Öh>ÓN/S]úki¯‹Ånj63Û¿pÓö¤;Yw» .¼x9â_NG9çÌ£¯®ºôëb¬×½{íÀ{?E|óäÓ7A¯¾½û÷ØÃŸ’;ýûøów—¯¿þþnk“Y €_8Ø\¬Å„  fEXƒ)=xF„h!FaHŽa,‰mL‡$n!¢-(X¢{'®rŠ™¸âŒüÉ8ãE؈ãŽ@èÈã@)äD™Œ»HhdiH:³à’™5 åqöMiå!ù,‚`þðÉI«½8ëÍ»ÿ`(Ždižhª®l[ p,Ï´àÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°Ø›ÍŽÏè´zÍnSËX·|N¯ÛïmxÏïûÿ€)zH‚†‡ˆ‰Šj„J‹‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÏÐÑÒÓÍÖ×¾ÔÚÔØÝÞµÛáÐßäå¬ââæêë£èáìðñšîÛòö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ [ÑÓ²dÀ‘ÜLªä‡rÚÊ—ùZJƒI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÕ«X³jÝʵ«×¯òш$3Xžbg-ûììδ2Ö²u«®ºxY°m;È®¼ öVC%¸Ý^~ÿîºøTcPM$–9keÃs^¾º9TgÀ ½|Mº´éÓ¨—ŽNmzµ׬CÃæ0;vÞÚpÛ–¢_ï ¿w; .¸ðEÆá%?þm9óçCŸÎÃ9õŠ“¯kw‘}»÷¾vUXÿnl¼‘î'Ì·–N>êb™(ÔŸ‘ßÞÒû–Déׯpåþïýô߀!ÀGà&¨à‚ 6èàƒ©éá%NèV!ù,‚cþðÉI«½8ëÍ»ÿ`(Ždižhª®l[ p,Ï´àÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÜÝÞßàÚãäKáçáåêë>èîÝìñò-ïïó÷ø$õîùýþûÐýHPBÀs*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱc™ƒþé<ŠÔÜÈ“(Sª$RòÛÊ—­ZzƒY$‰Í4ÍÈ„—SÈÍ›=Éìä4ÈO›EÅ —ÔÇÑ$M£nzŠDª©¥ ©*±Ê•’V]ÃFú:C¬ÙFdeœ]›(-N¶p ¹…·n ¹6ìêåƒw¯ß<}ÿ ¦x°áÈ+^̸qF¬Ž#{,¹rÊ–3k–Šyó“Âl;í.é!§KGJ}ˆ5תÁf6;¶¢Ú¶sÓª»÷ܾƒ Þ4ñã'Œ—ŽÜ‹r`ÏG0oþš÷ƒè §Sog{BíÛy@ö^|x+ä?˜?/5½‡õ웺ï?~ÑùêÛ÷£¿ÿÿ1Y9ÇGCà‘`–-蟃 FYKÆ6aIªv!H–¶áAzöa@!îGá0–(HŠ*!ù,‚dþðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë5î5ìñÛïô1ò÷×õõøüÓúôý>û÷N ÁeÝIÀ°¡Ã‡œø*!¼3F¤Èq•Eþ 5Šdرä©3BŽÔhÒJ-/¬“ÓK{5)Ìd™3ÓM=ƒÚ™Q¨ÑVD7]Š*)D¦P£JJµªU?m\ÝJ)+ׯ`ÊK¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xóêÝË·¯ßJNþUå5X`‡ƒSNÌ8ÉâÆ‰<ŽLùÇäʵ.cÞ|CóÏœ¯‚MÚÄ貇 KMòÁéÒyXKÌööÙÚjÛn„;˜îÝÀ/üN\Âðâz#ïWøx応/Ï!ýt_Õ§»ÈÞâz/îÚW€_á×øð‘ϯS^üO£ìÛ§ˆŽ¾|Dö锿Ÿù}¤ýBä+Ç9!à€âˆÅ"£à 6h̃bFa…”]ˆa(mˆ\Vzh[!ù, jbþðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïð`óôõö÷ñúûüýþÿ H¾ƒø ^ Á†BB#Ò{X¡¡EI”˜qÂÅ‹Ía}´HmdïL2Dɲ¥Ë—0cÊœI³¦Í›8sfQéP§O:B8áâÇ"CN¸Æä•cf¾lv3çÏçß“ät(ÑöHK6- u=Õ}Y·v=Oö—Ò¸p—ÐmïÞUó|ñâÈ“+'x|¹óçУK'ˆ:!ù, j`þðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pHäÐŽ´¢rÉl:ŸÐ¨tªDZaÔ¬vËíz¿`êõ.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüÿ ( ŸAa<ÈЗ‡JœH±¢Å‹3jÜȱ£GQác¬|ÌÉ·’GFâB™ÄË*o½”qr&–˜µlÞì¦óΟ–zÖJ4’ТHMjli1§L‡A•Ú3êÓªV³jÝʵ«×¯`ÊK¶¬Ù³hÓ†›ª¶­Û·pãÊK·®Ý»xóêÝË·¯_Clÿ ØOá«:ûÌXÃâÆ£«’ eT—+wʬy0çÎ?ƒý"DÒ¨˜~XHtj„«¶ÆŠÓõk»¶oÓÍ­[.ïÞ7~›~/¶lBÄÉ%žv9óçLœ'“î—ºëMiC­}ûvìÏGôÞXü¿!ù, !j]þðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pHäÐŽ´¢rÉl:ŸÐ¨tªDZaÔ¬vËíz¿`êõ.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë­cVìðäîHñ’óGõùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹³ÝK’±ã¦þ3<ŠÄRÆÈ“”JÆ@É’J,-c.zùâÍ2‹Ý<¶3'±ž:iúü)ÔСÀŽSŠ´Ó`O›êŠú‹ªÔ«s¬bÝêF+×*E¿zýJd¬L³dÓ~A«¶­Û·pãÊ­( ®Ý»xó ˜;‰m5½€õòœ%°a»„G9|X±ã‘~¯Š<вäË(,cÞ̹ˆfPŸ;ƒ++´hO¦OsJ½š´êW¬?º~Ýn6lÛ´UÅÖ´ÛDïÜ@~ÛÄm‘±á?½%÷g<0Ææ€ A\pz^àg¬ã5¨ý.öï!º#Ož‡øºåÓg8¿W½û4Ëß3d/A{ü¥Äå³¹/¬'ý%ü—TQ(B!ù, %jZþðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pHäÐŽ´¢rÉl:ŸÐ¨tªDZaÔ¬vËíz¿`êõ.›Ïè´zÍ[Ùð¸|N¯ƒÝH»~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéê¦xGë¡íIïwñ2óŸõö÷^ù1ûÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ CŠI²¤É“(öÃ’²e¦•/\Ê´³ÆÌ›‘jâÜéH'ÏŸ‰|JȧP¢HÿMÊTÏÒ¦På<:rª«TAb ³uX׊K¶¬'_w¦íh¶­Ùin㊭µ6+2¹ré´[ o\½+]ìå;ʯ[Àý&,Êp[ÆÃ8~¹2—Ée-#«Ë 3YÍ C‹Mº´i|ƒsyËó6תVÏ];[mT²ÃžÞý#÷YÞÀuø¦z;¸ñ Å“J^Šù çÊ—@5Eõ“ï¦VsÝD÷ßIf~DùèχPÏ4»çtìÑqY¾ýûøóëßÏq¾uFm×!ù,8+>UþðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pÈ¡iĤrÉl:ŸÐ¨´s¬Â¦Ø¬vËíz¿%«L.›Ïè´º(>®ßð¸|N_µÝõ¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙwFÚ?ÜHÞ°à3â=ä2æêëè1ìðñîWñõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£ÇÖ CЉL€É“(Sª@²å¹y5R¬œ¹Ò¥Í0c¢ ÉóäÍŸ-rªèÙ¨ÑBe¥y´i˜C—Îtê)i¨¤I¥N¥jÏê¬P¹6ôš†¬X„fϤ=[pm·lã*{‰î»rᥴ—ͼ¼€ ì¨/áÃ( ÓZqá°Ñ«tL¹²å˘3cQ¬³f(ž±…þœy4éÓ¨'™Níx5ë×°?INéÚIíØ¯f£ÄÍ»òíÞÙ~ŸÜñ§‹ 89²å?•/kÖ“y³g9?‹Vz´é2S·ýUø4(Õ‚¯öÕZ_íf°÷Ê6˰©Û=€/ËMw·ØÞ` §GÜ*ò»–'“±¸5êǰ;´nB»ï®Ã‹O¾¼ùóè_NϾIéöð{¼ßü0~óé#Š!ù,9‚GþðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°Ø›ÍŽÏè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿À:eXÁÅÆ²ÃIÇËÌÍÎÏÐÑÒvÉHÓרŽÕJÙÝÞ„Û4ßãäåæçèéêëìíîïðñBôõö÷øòûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3j•¯c¾Á ¥yY¯ I’!y…›!áäÈi.=¶Œù1¥®•2fÒ¼s'Ï>ÚÌÔ^Ï¢ú€"M:´)ª¥I¡:êK*Õ«¹¬¢Šµë ­KÀšà구 ±h¬’MƒSKж0ÌRTës \oáÊHwçÞ¿–úÒLX’à˜…;:ìR±cEŒO>žL¹²å˘3kÞÌÙÍÝΠE. ës´—P“>¨zµ/ÓÑZ»žG6íÛllãÞÍ»·ïßÀ]Àe8<ÝÄ+E!ù,=‚DþðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°Ø›ÍŽÏè´zÍnSËX·|N¯ÛïmxÏïûÿ€)zH‚†‡ˆ‰Šj„J‹‘’“:4”˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄO–3ÅÉÊË*Ç2mÑÒÓÔÕÌØÙgÎZlÖßÖÚâã[Ü0ÐàéÑäìíNæ6Þêéî,ðõÙ÷òóßøÍæþòáNà }º!ØOá„#Jìq¢Å‹*bÜÈÆŽþ 1 ²¤I9#«\É’HJj^NkI“™LiNn®{ óZÍŸÄzæÔ“(УÀ„6QªÅK¤PEeÂtꉧQ³jº¤êMXµŠ%çU&Ø”cñq5¸¶HØ´pã–x{¦­Ü»©èޱ‹÷ÆÇ¾.Ê\ð=€Ã ‡̰UÃ~ S †ñ<Ç_!çøË‹òÏv@kF$z\é9§G«>™zµëŽ­_Ëž]3íÛmãÞ-Q7ïß}N¼¸ñã!b#_žô1óçØ”CŸ~K:õ‰Ö“e_!¼G÷ë:¶ßþ^“x6úÈ—ÿ}žIzÄê×Ë—óžÛÉóóÿ©ïL¿ÿ[ñý'`;í h`$çx (.èà >(á"!ù,F‚;þðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°Ø›ÍŽÏè´zÍnSËX·|N¯ÛïmxÏïûÿ€)zH‚†‡ˆ‰Šj„JM‘’“”‹—˜™š_4N• •›£¤¥¦>3§«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂî©2ÄÈÉʆÆZËÏÐÑlÍ0»¡×‘ÒÚÛoÔÖØ×ÜâãKÔ6˜àáé¡äîï¨Þèì¢ðæöù÷ò—ôõúðH°`*ÌáÒ%„ #J<ÑÐÒ"ˆ3j†q£Ç®‰*JºÂ¤É“DfCɲe)•]ê(SL‹5sÚ„©³§O>7 J´¨Ñ£H“*]Ê´©Ó§¦hBJÕ„ÔªX³r¸ªµ«W’;ŠK¶¬Ù³hÓª]˶­Û€%}K·®Ý£sïêE™w¯_}ÿ L¸°á¶\+fw±ãq‰÷ ,¹r4ÊÚ"[ÆŠyfã#ò:oî)Z–@Í£§–~†šÇêÔ°ÝµŽ½æ5íÛ´"!ù,Mn5þðÉI«½8ëÍ»ÿ`(Ždižhª®lë¾p Ïtmp®ï|ïÿÀ pH,?·äíÈl:ŸÐ¨tJ­Z¯Ø¬vËízIÊðìK.›Ïè´š'¯ßð¸|N—¶Ãõ¼~Ïïû+wJƒ„…†‡OIˆŒŽHŠ6‘•–—˜{“”›5™ ¡¢Nž4£§¨©ª@¥ci­2«²³´>°8µ¹º»³·¼¿ÀÁq¾ÄÂÇÈÉXÄ̰ÊÏÐÑ&Í­ÆÒØÙÚÔ¥ÛßàáÝžâ¯ÎæéLä›êfì“îò#ðŠó„×÷úõû~ùþé H¤ß]ÿ$8gaƒmT˜H±¢Å‹Ô8䳑ᛎ³¶Ð쀱$FlСÌ32eµb*WÊi)óD75gÆÌ9&OŽ;"Tè!ŸFC!Mzi)Ó¦EŸ¦r*µªÕwQ¯jÝzî%ׯ`±z K¶ì²¬fÓª-B5RÛµp»ÜÄÓ mÜ»)ޮЋ·¯_~vÿ Ü/áÃq #^lV1ãÇsLJ¦¹òãÉ“-kÞ̹³çÏ C§u,º4Ò¦S›CM†µêA˜%Wuýº¶4Ú¶s'í[`!ù,8OR1þðÉI«½8ëÍ»ÿ`(Ždižhª®lë~A,Ït¼x®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~ÏïÓm€6~ƒ„…†‡ˆ‰Š‹eŽ2Œ‘’“”•–—˜™š›œžG‚Ÿ£¤¥¦§¨“¡Ž©­®¯°±²³´µ¶·¸ž«¹½¾¿ÀÁ‡ÄÅÆÇÈÂËÌÍÎÏÐÑ»€ÒÖ×ØÙ‹Ô¢ÚÞß]Ü5bâ4àç‘ÉêÉzå3èð‰ëóÅäî1÷øñü„ôôöîåÓׯ`Ÿó”è»ñ`á@#~sØ`Eˆ3j´@q£ÇT%:‚I²¤É“(Sª\‰I¤%—,3Â$1S•Ř8sÔÌÉÓÛΞ@­ý JTãPh×]z-©:¦P£JJµªÕ«X 9e—âhÖ¯`ÃVõ*oë1±Œ"!ù,P‚3þðÉI«½8ëÍ»ÿ`(Ždižhª®lë¾p Ïtmp®ï|ïÿÀ pH,w·äíÈl:ŸÐ¨tJ­2•Ø™uËíz¿à°Ø›ÍŽÏè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š~eX‹‘’}J“—˜™šA•IK›¢£¤¥ 6¦ª«¬­®¯°±²†¨8³·¸¹ˆµº½¾qµ4¬¼¿ÅÆgÁZÇËÌÍUÉ2ÎÒÓÔBжÕ_×ÙÜÝÞ&ÛßâãäáåwêëìíîèñœÐòvï÷ïõuçúý.ø×ù“Ão Á|Sp¡C Jœ¸("Å‹YÌȱã‹CŠI²¤I A¤<ɲ儕`ºœI2œMz4sê‡SæÎŸ@o&J´(¡ÁŒ*UŠ”ØR >ÉE7õ©ˆªß°¾H°V«`_âdŸױaÍ¡5ò5íž¶nçÀK·æÚºxóêÝË·¯ß¿.æW0ay†ý&>Ì8ðÝ?‹KžL¹rÈ–'F!ù,T‚0þðÉI«½8ëÍ»ÿ`(Ždižhª®lë¾p Ïtmp®ï|ïÿÀ pH,w·äíÈl:ŸÐ¨tJ­2•Ø™uËíz¿à°Ø›ÍŽÏè´zÍnSËX·|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†jpJ‡‹ŒŽŽ‰I‘K–—˜™n”6“œ4š¡¢£¤OŸ ¥©ª«¬M§Z­±²³´†Ÿµ¸¹º»·¼¿ÀÁ¢¾ÂÅÆx¯2ž¯ÇÍÎGÑÒÓÔÕµÉ8ÙÏÝÞßBÜàãäå®Éæcâéìíî,ëïòóôñõøù=÷}üúÿUøÛ30 Áƒ æQˆ°¡Ã‡Ù0ŒH±â£‰3j„q£Ç~ÈÐI’ HKª\™ð䉔,cÊŒs¦Í›CjâÜÉ3‡N ?{ ÔBQžG‡*]ʨ˦P'$]1uQUsWgf}ù´ÕÖq_£NöLYogÅ*MûŒ­Ú·*ÝÂõÚuî ¹vâÍpo>¿|7¼ X°a€…+Él±â!ù,Y‚,þðÉI«½8ëÍ»ÿ`(Ždižhª®lë¾p Ïtmp®ï|ïÿÀ pH,w·äíÈl:ŸÐ¨tJ­2•Ø™uËíz¿à°Ø›ÍŽÏè´zÍnSËX·|N¯Ûïx \™ïûÿ€‚"{Iƒ‡ˆ‰Š‹A…KŽ6Œ“”•–—‘5š4˜Ÿ ¡¢rZ¥8£ª«¬­N¨©W‘®´­°µ¸=š¹¼Ÿ·½+¿Œ»ÀÅÆÇ%‹ÄÈÍ΢ʽÌÏÔÕèÖÙÚÛÜÝÞßàáâãäåæçèéGìíîïðÇÑ€ôê÷]ñúñó؇öøRÙG°]¿Rˆ \ø¤`ÁƒúcH1ŠC‚§RXñÙÅ}žN>êëh‡#Id"ù¥H OËw'cÊ<òë¥;6 >ÈÉn¦ÏŸ>jòÄ9tgQ H“6›?j)²¤É$O2t¨²¥Ë )]Æ|IS&Ëš3kê,™s§ÏŸ@ƒþ3(aÏG‹Î"ªô_ÒO›Æ±ÇTªUM7¯ú¡ O«×¨^K±«6 Ù©YË’:«¶­[slßÊ»´+Ý»xó’«·¯_7|ÿ ¾×Ma+^ì$1ãÇ#KžL¹²å˘3k–wx³g­Ž?‹Îz´i!ù,U‚.þðÉI«½8ëÍ»ÿ`(Ždižhª®l[ p,Ï´àÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°Ø›ÍŽÏè´zÍnSËX·|N¯ÛïmxÏïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯vzH°´µ¶‹¹º»¼½·ÀÁ‘²Jl¾Ç¾ÂÊˈÄ4mÈѺÌÔÕÎ3ÐÒÑ*ÛÜ)ØÖâ?ÞÈã$åÇÝé½*áçð8ìíñ ó¼ë÷¹õüjúÓý:üÛ÷`ூ*\ˆ+! 2œHQ“ćú®`ÓR±£Ç:r?Šé)$É“(Sª\ɲ¥Ë—0cÊ,µ‘ãÌ›8K˜Ìɳ§ÏŸ@ƒ z¡& ¢H“î0jC©Ó§àŒBJ5ÓªX³b¸ªµë¥^ÃŽãÊä"Y±hM³6­Û·pã¢m+·.LºvóºÀK‘¯Þ¿#ýF!ù, T>0þðÉI«½8ëÍ»ÿ`(Ždižhª®¬*¼p,ÏBkßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™k4œ4šŸ ¡¢£¤“§0¥ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÅÆÇÈÉÃÌÍTÊÐÊÎÑÕÆÓØ)ÖÖÙÛÕ*ßÑÝäÃâÐáçÉåì¿êëÞïÇòóí÷ºõ×ñúôúËø¶ûP Áƒ*\x*†:<±¢Å‹3jÜȱ£Ç5 CŠélb'1&9‘\ɲ¥Ë2_Ê3EJO3sêÜɳ§ÏŸWnÎJt‘PE“Òü§TQ!ù,Pb:#þðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pE+҆ȤrÉl:ŸÐ”q ‹Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßpõ¯Ûïx°`Ïïûÿy‚ƒ„…†!€‰€‡ŒQŠ|Ž“‘‘”˜™>–šœŠž¢£* ‰¤…¦‹RsF¨¯iª°‚²~´¸¹ºy¶}½’»ÂÃÄeÀ{¿ÇÅËÌÍVÇÐÉÀÎ$ÓÖÙÌØÚ?Ü݆­®àäXßåèéêëáâtìðñòîïó÷øñõ3ùýþÿ H°`‡s*d„p¡Ã‡#J¼·O†“†3jÔ£l£Ç& CŠI²¤I8Oª\ɤb –0cžI)³¦Í›8sbpYE§O!ù,8TR1þðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïï§€‚ƒ„~‡ˆ‰ŠL……Ž‘‹”•–—’’šŽ˜Ÿ ¡vž¤¢©ª«f§¦®ƒ¬³´µV±²°¸€¶½¾¿&»“º»œÂ*¸ÀÊËu¼ÄÉбÈÓÌÖ×;4Ú4ÔÇÒ®ÆÅ)ÑØåŸÛè0*ééÝâÎ†ß§î¤æö—ìèbðáÑüãÕî Ìðo ‹Ñëd°a…‚Q@ ¦pËĈÍ*b Îè´z-°ßì²|N¯Ûïx|vó÷y‚ƒ„…†<€‰p‡Ž‘’yŒo~•j“*˜kšžŸ `œ™)£i¡%¦}¨¬­®Cªg¯¢±³¶·¸(±m¹V»½ÀÁ¿ÃQÅÆÉʨÈs£tÍËÒÓŽÑeÏεÔÛÜÝÞºÚßâã?YYä_Öèëì'æXí[êñôõïIöSóúýÂøHüáá'° €JR ¤a°Á†—,œ¡b¢ŒV#jÜÈÁ¢Ž CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêܹ-#ÏŸ@ ù új(ÑiF2Óæ†R\IŸ~*ÖÔ†ÔYQ3d½„jS®EÙ öÓ¯ª–]+hk[²/вۤ˜[ºxóN° W¯ß wGòUõ·°a +^̸±ã‰Kfy²å˘3[¨¬¹³Î!ù,VV*þðÉI«½8ëÍ»ÿ`(Ždižhª®lë¾pü tm߸ ï|ïÿÀ pH,a¹dN¢lÖŽ)§J­Z¯Øl%Àíz¿à€vLFI›å´zÍf‡ßá¶|~VÎïø¼~ïw÷€VuI…†‡y~~ˆŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈŠ}ÉÍÂËpÎÐoÒÖ¼Ôq×Ù`Ûßà´Ý_Üãáèéiæç(ì\ÛƒKêôjïb)÷ñò7UúõÈþ¹{·ß€³L(à †#¢rxP¢Å‹(ÒÀȱ£G!U ?jÔñ±¤?‚&SŠÔ¨²¥Ë6#_Ê„s¦Í›Gjâô s'Ξ>#…,24h  Féý+š” ˦—¢„JµªÕ«X³jÝÊ•ÎÓ®`“" KvæØ²hUF!ù,V‚)þðÉI«½8ëÍ»ÿ`(Ždižhª®lë¾pütmßx ï|ïÿÀ pH,­œ2'Y:kÈèèù”Z¯Ø¬vËuQݰxL.›ÏhŸ`Ín»ß‚´|N¯Ûïø-|Ïûÿ€‚ƒx|†l„‰Š‹ŒA_KŽ’“”•–J—›œžŸ™8 ¤¥¦§¨¢£©­®¯°«7±;³µ¸¹ºM³P»I«¿ÂÃ¥½¾ÄÈÉÊËÌÍÎÏÐÑÒÓÔ‡‡Õ׆ÙÝÞDÛ|ßá{ãçè0å}éëoíñò$ïnóõmxÆ4røˆóÏù[£o_¿*\Ȱ¡Ã‡#JœXmŸŠ\Æédã§Žxµh”EÉ—N¢”22ŠÊ•0ci‰ä¥Ì›8sêÜɳ§0šÃlúº (Ñ£H“*]Ê´© ¡BŒÎDè´j1ƒQ¤‚£jµë¨A´¦ëU)ØZdÏ´L[öáÙXlÛÊë".]fv#æ³÷®ß¿úL˜‚à¸"!ù,#‚\þðÉI«½8ëm…ÿ`( \ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßð¸|N‡±õ¼~Ïïû•w?ƒ„…†‡…AˆŒŽTŠ"‘•–—˜™)“!šžŸ ¡†œ ¢¦§¨©d¤Sª®¯°±C¬²¶·¸¹'´$º¾¿À°¼ÁÄÅÆ˜ÃÇÊËÌ~ÉÍÐÑÒgÏÓÖרOÕÙÜÝÞ:Ûßâãä›´åèéêçëîïßáðóôËòõøùº÷úýþªüþ ¨) ÁƒLȰaŸ…#J„q¢Å‹c*bÜÈÑŠÆŽþ C"ù(²¤IpíNª\9+%Ë—0kŒI³&;V6sê41s§O•= t¨QŒE*˜t©S„MŸJýuªU|U¯j}—u«Wt]¿Šçr¬YaÏNLËŒ­Z‡nE%‹{”.4»Ÿæ–}›oÛ½öÚùý9XYad‚ó½Ij`Ö#KžL9¢Ãj1§«Ì¹²„Π#_V¼˜†fOCƒ~uzlëL¯mÅö:[is8±ÞFQ›`o'Y» ¾[¨p&Äs×KÞØêñ%Ì9å‹>éês@Åyf'G]‘õíÁCOVù‹ëúÐ$ß—=–dª)#wA½nó×ì«Ð? þóþ8ˆ€ÚùçEw”Ö_sSX}ŒI§`{â V€àd˜Ž‡9€ˆƒˆlÈF‡ÂD¢ +Ê”¢B‰UX׋q´h£åf£7™Æ„è%£Q=âX¢‘3ꈤIEÉÛ’C É UøÆ}Sb§¤“ð츆‘^Zå1fi”>f4Mš9]™i:²æ]cúPç sº€fuMä‰ÔûŠ››bnI¨~RY衉ÀÉç|\**iK†Æ©%£“fÚÞÞõ)¨¦ Rˆi¨b%z„©¤‚õéñuÖ ª©Þ \«œ}i¬‘ÀJ„•m<@«g1èŠë Âþ߯“Ù:ê°Ì¦Rl³Ðb¸j´Ôêñlµ)D!ù,‚wþðÉI«½8ëm…ÿ`( \ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßð¸|N‡±õ¼~Ïïû•w?ƒ„…†‡…AˆŒŽTŠ"‘•–—˜™)“!šžŸ ¡†œ ¢¦§¨©d¤Sª®¯°±C¬²¶·¸¹'´$º¾¿À°¼ÁÄÅÆ˜ÃÇÊËÌ~ÉÍÐÑÒgÏÓÖרOÕÙÜÝÞ:Ûßâãä›´åèéêçëîïßáðóôËòõøùº÷úýþªüþ ¨) Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÕ«X³jÝʵ«×¯`Ê{Ä Ù³tÌ¢]ûF-Û·ÔÚu w ]«wë"ÉK•¯Þ"~¥þ+d0TÄw vº81ŽÆL!;®!YiåÉk䊽ŒÙŽfœ/†îÜò芧I«0ýfjÕ(X³ªùšYí‚­}ävy[Yod»Wgù{Kñƒ²IÑNè¸Mç°K@§9=º†äœ^V·Žû$í̹ob{?óâ¿—¾>$úôÞ7 @¿¾ýûøL“Ÿžÿ‹üæØ'A€Ö·_{ðS`.`‚žààƒVhá…f8‘¾Åa‡ †ˆÆ‡{!øÉ„öy6[[&’DbY-j‚¢/¼(ÜŠ"‚c&3Ò§¢r,âèDõ¨_;FEä_KªÔd]O¢%SŠSeIW¢•åH[’Õ¥{IæØ]˜7%ó¥˜:‰æšÆ‘Éf‚j¾™›rŠgI݉'"z2Ñ瞉РɟÍš„¡º  ¢¾ :£F@jŒ¤…¶C©^—þ‘) œvêé§k™"¨!ŠJ#©šê#ª|D!ù,9‚?þðÉI«½8ëÍ»ÿ`(Ždižhº lë¾° Îtmßx®ï|ïÿÀ P+ƆȤrÉl:ŸÐ¨Ôg¬¶¦Ø¬vËíz¿à”Õ.›ÏåqÍncÕF·|N§Âõ¼^wÇïÿ€}0‚†‡„/ˆŒmŠ.Ž’ŒW“—˜S•,™y›2ž¢£¤¥¦4 §ª«¬­¥©®±²³´s°µ¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌͼ·ÎÑÒÓ›ÔרÙZÐÚÝÞßv•àãäå*ÜæéêëìíRèîñò×ðóö÷Éõøûü¿úýÎú'° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç½ CŠI²¤É“(S¦À²¥Ë—0¨œ 1¦Í˜nêlI³'Ã;s½éÓÁ/Gg %ú`©Í¢Ý’v‘Ë)ÎIT·d]·5KW¨¾j²&Pì;²`Ób2…­Ú·hÜ>‘ ·®<ºvórE«Ñ*K½aáíæW&à‰ƒ>Œ˜/ãÇüCž,M2åËË,cÞlL3çÏ C‹m·°K[ŽI«bš§Ï«c³‚-ûíF·kƒÌˆ·îßÀƒ ïzø°!ù, 7jDþðÉI«½8ëÍ»ÿ`(Ždiž('¬lë¾B*Ïtmßx®ï|ïÿÀàF„ ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿àkqÌ ›Ïè´zÍ‘Éí¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²hoc³·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊË5µEÌÐÑÒÓÔÕÖרÙÚÛÜŽßàáâãÝæçQäêäèíîHëñàïôõö÷øùúû…òòübðO Áƒ*\Èð“3" #¢{hD¢Åm_\܈-£ Ž™ ©yl²ä™‘eÒ \a²¥KVבXCåÊ—%cªÃÉÓ”Nv~ŽëIL¨¸iFÃIH:¨0¦ßB]:Õ©ÕNPË]Ýʵ«×¯`e K–ÔØ²hÓÊ1ª¶­'¶nãf‚+—ÄÙºaèâ qw¯½~=ô L¸°áÈ+^üe0ãÇqCžœF2å˘3kÞ̹³g?–?‹nz´®!ù,°TÚ$àðÉI«½8ëÍ»ÿ`(ŽdižhªfAë¾p¬tmßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø,TÆ•i¿à°$(›Ïè´`Ìn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•]˜.–›œžŸ™™ ¤¥¦§¨©ª:¢˜«¯°A­]³\±¸¹8¶^¼1ºÁÂ'¿0ÃÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚۦŠÅ/njãjÜSÞæéêëìíîïðñòóôõ>àšöúŠø-Jý3ö T!ù, "j^þðÉI«½8ëÍ»ÿ`(Ždiž('¬lë¾B*Ïtmßx®ï|ïÿÀàF„ ȤrÉl:ŸÐ¨¬HeI¯Ø¬vËíz¿›jL.›Ïè´+¦®ßð¸|NW·‹õ¼~ÏïûMwDƒ„…†‡dFˆŒŽ4Š/‘•–—˜“.™žŸ v›V¡¥¦§¨I£¤©­®¯°#«+±µ¶·±³1¸¼½¾—º¿ÂÃÄÁÅÈÉÊhÇËÎÏÐPÍÑÔÕÖC³×ÚÛÜ€ÙÝàáâÓãæçèéêëìíîïðñòóôõ†øùúûüöÿõØ/ Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ CŠI²¤É“(Sª\©† Ë|,cÊœI³¦Í›8sêÜɳ§Ï‹/_þJ´¨Ñ£H“*] «Ó§¸œBÚôÕ«UWaÝ*˪(­‚ºäMª³÷Ä$ m"¯Ô®eëÌ-»tÙâm'·`^v{Ùõå÷0\zƒ÷^XÅáÅ4ó8²e“5d¾ÌyÍæÎ ÏV¶œXœÒ0q~ÍÚËê¨ñµ†ôzNíÙoãÞÍ»·ïßÀƒ gÛßðã6ŠKP޼¹ æÌK/=öôaºqUG}]Xö[Ñ»?ù΄|­ð⛘W²>½Æöîq£ÿ$1Öùô›Ø¿Š?ÿ’ýþ78€h&‚ 6ȃÑô'„„öDa… ^ˆá†"hÈ¡€~è_ˆ"–hâ‰Z‡¢%!ù,‚eþðÉI«½8ëÍ»ÿ`(Ždižhº lë¾° Îtmßx®ï|ïÿÀ P+ƆȤrÉl:ŸÐ¨Ôg¬¶¦Ø¬vËíz¿à”Õ.›Ïè´z½WÙð¸|N¯Û1nã}Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôñ÷øùúûõþÿø ä° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ CŠü7°$¾‘(q™4™²¥Ë—0cÊœI³¦MfyЍXYò¦O49¤à9ð§Ñ0Aaì$JðhĤ/œJ¥ÕÅÔ«ª^ÁÊu‘V]ÊK¶¬Ù³hÓ*bÚT­[6l÷½ÝöU†®¸úæj«» o>½€‡ø=¸°—Á÷ +Þ‚¸ßâÇRCžüD2åËJ,ÏÒ¬†3æÏ 5zMÇèÒ¨gœNÍÚÄêÖ°cËžM»öD¾CÛ6‹{·ÃÞ¾ƒSÞõµðÚÆ¶œ\ù\æº o.5õꨯÛÐN‰ûïØ?ƒy<ùóèÓ«ï€7¥ùõ%Ú£|ß}÷ëÏ˯¿¿ÿòÑý `kD!ù,niþðÉI«½8ëÍ»ÿ`(Ždižhº lë¾° Îtmßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëAîïðñòìõÇóøóöûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹òi|‡±ã¡Í=ŠI²¤É“(Sª\ɲ%1]ÊL3ßÌ›ejâÃÉ3ŒN}=ƒ J´¨Ñ£H“*]Ê´©Ó§P£úù)OªÕTã]ÝZ#+<®`Sxå¶,‰±î̪ –ÞÚ¨m!Åõ‰ö­Ý»xóêÝË·/Ϲ~í¼v0áI1Ç8̸±ãÇ#KžL¹²e:Š3·¸Ì¹³çÏ C_4<‚4#Ӣ͠NÍšäêÖ8_ÞM»¶íÛ¸ ÉÎr7o“¾»®+œ]ðâçGP9qæ …$!ù,‚iþðÉI«½8ëÍ»ÿ`(Ždižhºlë¾p Îtmßx®ï|ïÿÀ P+ƆȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷ø=Fû-ùþÍüøý˜,à>‚‹4’°¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ CŠÉfa’(#™<’’ÇJ-¥¼|sÇL5sêÜIêf?ž@ƒ J´¨Ñ£H‘ød‘´éš¥2œJ5uªÕ1U¯jõ’ukÇ®^ÊK¶¬Ù³hÓª]˶­ pãÊKW€[¯uóÖ• ·o\¾~ûÞÝXpŠÂz§«q^ÀŽç‚a†²b—KD¦ y3ÜÉ™ËX¾¬c´Ïr;{&Mõß®?ÞÌ:el»°c«X]›ämÕ´gGîí[wn×»ƒ/…é:¿£–•÷rÑ£WW~ÝcvãÛ‡wÿøùƒðŽÇ“7®=´uõËOž¾Ñè(ÞÛŠÿ„þý@õX÷wh\~¸“€%ü§`N ’àÙsŒPø`(^H\†ÖÆa‡­%âˆ$–˜Q„&Þc¡(¦XÏŠ=´è"ì8ãQ2ÞÈ“|ê¸`æùX" F!ù, Ej<þðÉI«!ëÍ{¸`(Ždižhª®lë¾p,Ïtmßx®»^ïíÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ'>“‘–S””—›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅ0™“fËÌÍÎÏÆÒÓ È>ÊÐÙÏÔÜÜÖ=ØÚâÑÝåætããéâçîï8ìÚëòÐôõÎðúû/øÛþò ÈŒŸÁƒ&Œ¡p‡£4$±¢E#/jÜø& Çz mx I²$‹€ß~”IÙÁ¤,–\ÊœI³¦Í›8sêÜ 2#ÏŸ§`nJ´¨Ñ£H‰ùLÊÔØÒ¦P£JJµªÕ«X³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pãJl(Ah%¹xUyóØw¥~y ÓéëGa?;þõûŸDñ=Ÿ€^@ sÿq—àƒL,¨Bh¡2× pvXD†Ëm8Ÿ‡ô¢rœ˜\DÆÐbW†©xÞC/¾PãV1ª¸L…6ÜØ‚)ɸ‡/5¹‚’'醓ß9È’Z0™•Y@—•(p9ˆ—$†)æ˜d–iæ™h¦©æšl¶é&Z¾)§ qÎI˜]´hdvÊçeXâ°§ŽðÙ§n‘¨†ê(>ÊW¤'P*éU& ƒ¥—Ž!ù,0‚OþðÉI«½8ëmƒÿ`(\ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­ZqRéuËíz¿Ð,L.oÅc³zÍnÇÐ?·|Ž…‹èø¼žl¿ïÿ€}!…†‡:ƒ ˆŒzŠS‘’“”˜e–$™ž›Ÿ¢U¡£¦§f¥¨«¬­®¯•–°³´µ¶ª·º»¼½\¹¾ÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ CŠI²¤É“(S榲e>–.cÊœIÌš8ÓÝd´3焞ÕJ´¨Q úT:í¨Ó£Ieù$µÛÓ«C£>šJu+×cL¿Š½vlDzfÓ>Cû²ªZ¶±¼Ž‚{¦Ï\·ié^лoÐ]¹oñ¶à[+Vµƒ#FB˜‚á«‹W4ŽüàñS “%XvJ¹3˜ÍPd® º¨çÓ\J›­x…j¢¨cWyÕÔhÙ2i =u·KÝHm·öMÜVïâÈKO 8¹ó•Ë,gý¹Áé¾°sÐ.½:5îÖSyç3^øðä›»9¾½û÷ðãËŸO¿¾ýûd€Ëпþþ( >hàF¥xà‚Ðy¥ ƒRñ`„ðD!ù,9‚FþðÉI«½8ëÍ»ÿ`(Ždižhºlë¾p Îtmßx®ï|ïÿÀ P+ƆȤrÉl:ŸÐ¨Ôg¬¶¦Ø¬vËíz¿à”Õ.›ÏèÒ¸šn»ßð¸|Ž[éø¼~ÏïGíE~‚ƒ„…†‡€GˆŒŽPŠ0‘•–—˜™!“/šžŸ ¡†œ.¢¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ~#uE Áƒ²@Ȱ¡Ã‡ƒ(”±"¿‰3jÜȱ£G\—?ŠTr$¯’&SŠC©²e7–.¥ ˜I³¦Í›œÀŒÉ³ÚN3œzê ‰³(N¡H{ýLºj)Ó§ÆœBL*U‰ ¯j-fu«×Z]¿Š…v¬Ù³hÓª]«¶,Û·4Üê›….\vvoå½›c/_<~%eýKXSàˆ+^̸±ãÇ#3J™¦ä˘3kNsx³çÏ CuM.!ù, =jCþðÉI«½8ëÍ»ÿ`(Ždiž(¬lë¾A*Ïtmßx®ï|ïÿÀàF„ ȤrÉl:ŸÐ¨¬HeI¯Ø¬vËíz¿›jL.›Ïè´+¦®ßð¸|NW·‹õ¼~ÏïûMwDƒ„v/…‰_‡ˆŠŽWŒ.”Q’-•™šA—V›ŸB+ ¤¥S¢¦©ª«¬e¢1­±²³´@¯µ¸¹º» ·¼¿ÀÁ´¾ÂÅÆÇ•ÄÈËÌÍuÊÎÑÒÓ^ÐÔרÙIÖÚÝÞß4Üàãäåa¨æéêëâìïðÑîñôõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#Æ›'±¢Åpè.jÜ8ƒ"ÇÌ 3øò²dI’&SnD©²¥D–.uÁŒI³¦Í›8s›©³ç>ž>ƒŽ‰ ¢B“v@jÉè ¦J¥@6Õ‰¤££®© Œ+“«O³jMã•WYB\Ï&U;¶GZ±mãN„+·®:¶vÝÒÍ+u/_-xÿvô+¸h§Âˆ½NÌØÔb[„K|¸]ä1_ž¬¹r2t™=„Öë9ÄhΉFn–vzNkÁ¯™Å†3Ûð%Ô¸+ÔÎÍÛõêÞÀƒ N¼¸ñãÈ›¨.¼¹óçùvC_!ù, Gj<þðÉI«½8ëÍ»ÿ`(Ždiž(¬lë¾A*Ïtmßx®ï|ïÿÀàF„ ȤrÉl:ŸÐ¨¬HeI¯Ø¬vËíz¿›jL.›Ïè´+¦®ßð¸|NW·‹õ¼~ÏïûMwDƒ„…†‡dFˆŒŽ4Š/‘•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬R“.­±²³‘¯-´¸¹º{¶V»¿ÀÁ‰½1ÂÆÇÈMÄÅÉÍÎÏ8ËÐÓÔÕ"ÒÖÙÚÛØÜßàÈÞáäpãå’Äèëì¬çíðñžïòõ5øùúûüæê¥èÙˆ¢ŸÁ~ÿz™H°áˆƒó%´µ Ã‹%"FœøJC>ä1ŠÌ b-‹#Sª´ƒr¥Ë—]Bœ©C&Í›8}ØÌɳ§ÏŸ@ƒ J”NɃÛ]ÊôCǦâZBýñÔ©~vbM§…Ö­I»‚¥:ÉëÕ±y¾¢£ví™¶8Žt"¡O¸n ÕåGw¯>8~ÿ›wP`‰Mã¬áÂ~ûKÜødÇg!CºLù0cσ3kvÄyZé¹RÍZËi©gÄne6m{Ør‹eû¶¼ÞЀûf»{¸ñmÂ+Ç•|¹óVÍŸKGe[·Â騳kßn#:÷ƒò:ùó"!ù,E‚>þðÉI«½8ëÍ»ÿ`(Ždižhº lë¾° Îtmßx®ï|ïÿÀ P+ƆȤrÉl:ŸÐ¨Ôg¬¶¦Ø¬vËíz¿à”Õ.›Ïè´z½WÙð¸|N¯Û1nã}Ïïûÿ€8yE…†‡ˆ‰sƒGŠŽ‘’@Œ0“—˜™š›•/œ ¡¢£vž.‘¦W¤«¬­®R©,¯³´µ¶6±2·»¼½¾¹¿ÂÃÄ£ÁÅÈÉʉÇËÎÏÐrÍÑÔÕÖ[Ó×ÚÛÜD±Ýàáâ¸ßãæçèÙéìíãëîñòÕðóö÷Åõøûü¶Ç H0@¿ƒý+È`‡#JœH±¢Å‹3jÜȱ£Ç þ CüˆC¤Èj&C’¼‘²áJ-¢Œéð¥M:4kFË9ð¦Ï' y” t¤«¢C*UT(Q¤¯\ªHꮦ<Ÿ •j"«·ô…ÛŠ¬×³Ä1»Š-Z/jÄ¥R®M9Okܾå2·G_±Ý­”·ëÞ/u$αË1¼jôÎÒøFer©à<&Ùðd¾u—\®1Ji4’?à ­:Ãi$`S·ž=1¶gÚ¸)ÚÞš»wí®²ç½†4Ü·‰ÝNbÍ‰ŠµñçHŠ+t½º\ꮤÓþƒû2ḭ́[y;‰wQç“ߘ~Kû=È³ŽŸïãýøÌéë×a_ø±åí)'`ýYö߀R f¦$è`- >(á5Nh!4`­wᆓdx ‡F!ù,A‚BþðÉI«½8ëÍ»ÿ`(Ždižhº lë¾° Îtmßx®ï|ïÿÀ P+ƆȤrÉl:ŸÐ¨Ôg¬¶¦Ø¬vËíz¿à”Õ.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–cU—›œž6™FŸ£¤¥¦¡E§«¬­‘©G®²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòíõö÷øùóüý5úõùHDÀƒö *\¸!B†#Jœ¸ Š3*´øB£ÇÀ CŠIrG%S2:y¥ K*TÉð¥Œ2ª°Y('À/1Y¤ù̧@`FóIHЍB¦÷‚AMˆsê>§­^ý¥u©U¬Y¿"Û¬ÙheϪe–v­Û·p;ðŒK7Ø\OwëêÝË·¯ßždÅþ̨l[ˆ ¬&oâÄ‹§¶qü8ed¨^%³¡\yÞe¦™1WÕ¼†sçÓóRkK¯[˾az¶m7skßÞ&wPÞÀ'ÿNîâN#!ù, J>5þðÉI«½8ëÍ»ÿ`(Ždižhª®¬*¼p,ÏBkßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃLÆÇÈÉÊÄÍÎ9ËÑËÏÔÕÖרÙÚÛ‰4Þ4ÜáâãäåæçèéêëìíîïðñòóôõÃ񿂻ùùöÖüøöŒæ¯`¨ œf°!§…ÊJÌ1ÙÄ‹•*"Ãȱ£Ç1 CŠI²¤É“(Sª\yR£>….™=øFË›?bÊÔ)¡fM%>iâÉ3IÐoCCF!ù,A‚?þðÉI«½8ëÍ»ÿ`(Ždižhºlë¾p Îtmßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéê¨íîïðñëôÝò÷òøûîõþ©1ÆÐÇoß¿ƒ½*lA°à=„s-\(É!¼ˆƒLT(ÆâÃÏûeÉc£ÀŽ!/‚LI²e ”*a¾sI3•L‘7Û1Ê9¯¦Ï†2ÂÜ™óçOžBY.Bj´&S¦Š 6mù´èR«S©Z•ŠˆkV&&ªªz“hÙ`aæI C˜WCo¿&aûB]c±&Š+÷È]†ÁøÜ—È_…¿N¬ñ0ã.‹K¾¹PåÉÜÈMryGgÌÙ4å¬×ÈgÐ×D+E¡:¤’Ó¨K–±ò,ë­¸mií1¶§Ù*`_àmñuî;— ÜBó&Ï“;[.½ú!ù,B‚>þðÉI«½8ëÍ»ÿ`(Ždižhºlë¾p Ît(Üx®ïBíÿÀ pH,ȤrkÆ–Ð oÊ‹Z¯Ø¬vËíz+Îp뻤šqä´zÍn»ßðøç|–Ûïø¼~χÓÍ}‚ƒ„…†‡T‡‹ŒŽ@‰S‘•–—˜™ƒ“UšžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíÜœ;îòó˜ð:ôøùŒö9úþÿ}ø¡H° 7$ ì!k¡Á‡û*”Ø"Ä‹›(:¬(£ÇöQl ‹äÇ“#Fj\Ù‘#?”0˰|ùÀd {{lÆü FL(—T¶ /§Å!z†ùyÔP%Biådt(ÒcOm4g ¯y²^ý%vÎV(]‹º;¶XYo‹Äí5·-ººBðêÒk7ŠR'}=ümRïlàÑ?A̸±ãÇ#KžL¹²å˘3kÌw³çl?›µzQ1 ¦-C‹î z騥®öÒzBíÙp ã¾r»¦np¯]ü½-ñѲ‹+GÕ»ùq7½—WŽî‰ºtÉi©‚²~}w߃>ï®-|,óäý¡OÏÞQð1¾I·Ÿïv<ýû "!ù,@‚?þðÉI«½8ëÍ»ÿ`(Ždižhª®l[ p,Ï´àÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»­¸|N¯Þø¼~Ïï‹ì€v~ƒ„…†‡]ŠrˆŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑcIÔ1Òר£ÕÕÙÝÞšÛÔßãä‘áIåéê„çH íJëòónð4ôø‡ö3¸û2ùù³vk Œ€÷´QÐ`‡#JœH±b·…3j¤‚±Ì¾® C®ø(²$‹Ž&Sª”‚r¥Ë—0c>Y´H¦M4ÝÜɳ§ÏŸ@ƒ J4cÎ@E“z; è'SAJE¶”ö´NT©³U¥s5äÔ®`‘} {bì³1Ñ’¢DÛoWÆ]«§£Ý¬tóšËzw Þ¿§úús´u`]s±&‰¨0£ÃýðNãKÙo#Çq ¿“,&±æÏ*<[ ºôΦS«^­š4ëד\ÞíH6íÛ…"!ù,H‚4þðÉI«½8ëÍ»ÿ`(Ždižhºlë¾p Îtmßx®ï|ïÿÀ P+ƆȤrÉl:ŸÐ¨Ôg¬¶¦Ø¬vËíz¿à”Õ.›Ïè´z½WÙð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·º»¼½¾¸ÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝnFÞâãßàGæçmé2äîïðñòóôõö÷øùúûüýþÿòc÷B Áƒ!º@È0ɯ‡¿Jœ(¢Å]3"¼xQ£Ç€`-TÈ⣾G’4YåC8.#²œIdI31}9ÉÙ«"OŒ4ƒÚl‡é'P£º‚*=1TR`K£JJµªÕ«3žbÝÊÕŽÖ®`Úh*¶¬#²fÓª]˶­[_ßÊ]!ù,@‚>þðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžnI¡1Ÿ¤¥¦v¢¢§«¬­f©¡®²³´V°Iµ¹º»B·H¼ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛܾJÝáâãäåæçèŒß4éíîïðñòóôõö÷øùúûüýþÿZ7CA¯Ö \øáà¨&a0œ¸-¢ ŠéYÌÈ1ÞÆŽl CŠI²¤É“(±}LÉ2ÚÊ–0cÊœùï%ÍrêÜɳ§€›@ƒ²´)´¨¬>“ú4š‡(Ó§P£s*µªÕ«X³jݺ‰*ׯ`Ê¥â5DÙ±hO|<›V‘Ò·:5FlK·®]ylïê]“wo°!ù,B‚<þðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°Ø›ÍŽÏè´zÍnSËX·|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µApI¶º»¼>¸H½ÁÂÃ&¿JÄÈÉÊÆ4ËdÍ2ÏÓaÑÒÔVÖZØÜÙÚ6ÝSßàáåOãæQèéìFëíð!ïñhóô÷öø`úûþýþ DPUÁDµ0¡C> JœH±¢ÅN2jÜȱ£€6÷Cj¼Hr˜È“#Ù ôX²%¯•'AÂÜÈdfH6Yºü”³£“žË¥™bhÊH%͈siÒ§—~,êªÕR›½.¢¿¬T·råæuXgÇN+‹/­ ·/¾©µÄö\wçê=“—Kß'ÖÍXiU1…=€Mül0Æ !/Z|˜ã`/ “¬ˆ²Øvš[d– s"ÓÿBCQý²²%Ôu`3bTö^ ¶ÑÞ™ûö…ÞIû¾ø¡ÝÄ“cv­¼¹-ãÆKg}ºõnž‡^~½;«ì@·koÍû%äÔ™án¾}£êîã·þ,¿~;øöñE!ù,G‚4þðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°Ø›ÍŽÏè´zÍnSËX·|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿vpIÀÄÅÄÂHÆÊ˸ÈJÌÐÑÒÓÔÕÖcÙÚÛÜÝ×àá—ÞäÞWÎ3åëÚâîØìëçèZMñÝL÷åóô6úäÞ ìÓ¯&€æ„¡!·±><´ÐßA‰í.lˆñÄW•³9 éEÅ(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒâ 9í¤ÐIFF!ª± RIÕD}Êf*ÕEV¯¢Éªµ«×¯`ÃR`Š‚¬Ø³®Ì¢]»Cí&·lã¶€›‰)]¹rïŽ É#Þ¿»ìòLøšÞˆ‰N,s±2ÇŒBfli²âÁù0SeXçŸ7CŠ!ù,Ln.þðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,ÖŽµ¢rÉl:ŸÐ¨têDZcÔ¬vËíz¿`îõ.›Ïè´z [Ùð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰(ŒŽŠ“”•–€‘™‘—œžŸa𢠥¦§¨@££©­®¯°«¢±µ¶·¨³š¸¼½¾ˆº™¿ÃÄÅxÁ›ÆÊJÈËÏГnHkÍÑØÙ‚ÓGÚÞßà:ÜIáåæ­ã4*é3çîïðì2ñõö÷øùúkóXûý`ü˜-  X *|–a@[Ö-Œ×ðUEXIM|wÝÃZŸmÉ«£«’HJ@©ÒÉV,[ÆlIÓÌL’7™…Dô²¦œê³KOD‘”IÒ¢œž‚ú…ª†V{d…ªhë¯ZÀfËÖ¦'ÈNQ+…mÙ‚ù…2÷íT´„ކ¨ ¯Ý¿&ôÞÍhŽ/à¿‚¯ô«¸±>Ë;ž\2å˘9XÎ\h3ç´K=}Y4éÓŠM£Þ!ù,PB:7þðÉI«½8ëÍ»ÿ`(ŽdinBª®l+œp,Ïtmßx®ï|ïÿ%—Ð,ȤrÉl:Ÿ’¡T­Z¯Ø¬vËEN§Ý°xL.›Ï¸¯Ín»ßð¸W-”Ûïø¼ÞN¯ïÿ€‚ƒ@}D„ˆ‰Š‹Œ†-‘’“”g,•™š›œG—+¡¢£¤"ŸT¥©ª«¡§)¬°±²‰®/³·¸¹oµº½¾¿Z¼“ÄÅÆÇÈÀËÌNÂ’ÉÑÉÍÔÕEÏ‘ÒÚÅÖÝÞß"ÛÛàäåæâÚçëìÍéÒíñòóôõö÷øùúûüýþÿ H° Áƒ*\Ȱa•wÑJ‘Û‰ŠÈ&jì‚ñœŽÎC^èhì#Ib2N¢ÉR‰Jeº^¶Ä€m¦™MpÚtä NM4?×éÜI)裦zÎJTÒOADmJnª «°rÐ:ŠéN®{Àf«Ï«M²xÐZP{Ï,G•>•²•3wB]zn¹ä%#ìî.¥0üÊÛ ‚pÃWGò+˜êÄ óh|‹²c$’7dÖaY–°Í—o€Æ0úFçXŸá†v©Ú©âv©O®žM»¶íÛ¸sÏ9¥»÷ÈÖ¾ƒÞè´pÛ¥ï?N;y•åÌ£·z-}a;cava-0.10.2/example_files/config000066400000000000000000000232471462072613000165220ustar00rootroot00000000000000## Configuration file for CAVA. # Remove the ; to change parameters. [general] # Smoothing mode. Can be 'normal', 'scientific' or 'waves'. DEPRECATED as of 0.6.0 ; mode = normal # Accepts only non-negative values. ; framerate = 60 # 'autosens' will attempt to decrease sensitivity if the bars peak. 1 = on, 0 = off # new as of 0.6.0 autosens of low values (dynamic range) # 'overshoot' allows bars to overshoot (in % of terminal height) without initiating autosens. DEPRECATED as of 0.6.0 ; autosens = 1 ; overshoot = 20 # Manual sensitivity in %. If autosens is enabled, this will only be the initial value. # 200 means double height. Accepts only non-negative values. ; sensitivity = 100 # The number of bars (0-512). 0 sets it to auto (fill up console). # Bars' width and space between bars in number of characters. ; bars = 0 ; bar_width = 2 ; bar_spacing = 1 # bar_height is only used for output in "noritake" format ; bar_height = 32 # For SDL width and space between bars is in pixels, defaults are: ; bar_width = 20 ; bar_spacing = 5 # sdl_glsl have these default values, they are only used to calulate max number of bars. ; bar_width = 1 ; bar_spacing = 0 # Lower and higher cutoff frequencies for lowest and highest bars # the bandwidth of the visualizer. # Note: there is a minimum total bandwidth of 43Mhz x number of bars. # Cava will automatically increase the higher cutoff if a too low band is specified. ; lower_cutoff_freq = 50 ; higher_cutoff_freq = 10000 # Seconds with no input before cava goes to sleep mode. Cava will not perform FFT or drawing and # only check for input once per second. Cava will wake up once input is detected. 0 = disable. ; sleep_timer = 0 [input] # Audio capturing method. Possible methods are: 'fifo', 'portaudio', 'pipewire', 'alsa', 'pulse', 'sndio', 'oss', 'jack' or 'shmem' # Defaults to 'oss', 'pipewire', 'sndio', 'jack', 'pulse', 'alsa', 'portaudio' or 'fifo', in that order, dependent on what support cava was built with. # On Mac it defaults to 'portaudio' or 'fifo' # On windows this is automatic and no input settings are needed. # # All input methods uses the same config variable 'source' # to define where it should get the audio. # # For pulseaudio and pipewire 'source' will be the source. Default: 'auto', which uses the monitor source of the default sink # (all pulseaudio sinks(outputs) have 'monitor' sources(inputs) associated with them). # # For pipewire 'source' will be the object name or object.serial of the device to capture from. # Both input and output devices are supported. # # For alsa 'source' will be the capture device. # For fifo 'source' will be the path to fifo-file. # For shmem 'source' will be /squeezelite-AA:BB:CC:DD:EE:FF where 'AA:BB:CC:DD:EE:FF' will be squeezelite's MAC address # # For sndio 'source' will be a raw recording audio descriptor or a monitoring sub-device, e.g. 'rsnd/2' or 'snd/1'. Default: 'default'. # README.md contains further information on how to setup CAVA for sndio. # # For oss 'source' will be the path to a audio device, e.g. '/dev/dsp2'. Default: '/dev/dsp', i.e. the default audio device. # README.md contains further information on how to setup CAVA for OSS on FreeBSD. # # For jack 'source' will be the name of the JACK server to connect to, e.g. 'foobar'. Default: 'default'. # README.md contains further information on how to setup CAVA for JACK. # ; method = pulse ; source = auto ; method = pipewire ; source = auto ; method = alsa ; source = hw:Loopback,1 ; method = fifo ; source = /tmp/mpd.fifo ; method = shmem ; source = /squeezelite-AA:BB:CC:DD:EE:FF ; method = portaudio ; source = auto ; method = sndio ; source = default ; method = oss ; source = /dev/dsp ; method = jack ; source = default # The options 'sample_rate', 'sample_bits', 'channels' and 'autoconnect' can be configured for some input methods: # sample_rate: fifo, pipewire, sndio, oss # sample_bits: fifo, pipewire, sndio, oss # channels: sndio, oss, jack # autoconnect: jack # Other methods ignore these settings. # # For 'sndio' and 'oss' they are only preferred values, i.e. if the values are not supported # by the chosen audio device, the device will use other supported values instead. # Example: 48000, 32 and 2, but the device only supports 44100, 16 and 1, then it # will use 44100, 16 and 1. # ; sample_rate = 44100 ; sample_bits = 16 ; channels = 2 ; autoconnect = 2 [output] # Output method. Can be 'ncurses', 'noncurses', 'raw', 'noritake', 'sdl' # or 'sdl_glsl'. # 'noncurses' (default) uses a buffer and cursor movements to only print # changes from frame to frame in the terminal. Uses less resources and is less # prone to tearing (vsync issues) than 'ncurses'. # # 'raw' is an 8 or 16 bit (configurable via the 'bit_format' option) data # stream of the bar heights that can be used to send to other applications. # 'raw' defaults to 200 bars, which can be adjusted in the 'bars' option above. # # 'noritake' outputs a bitmap in the format expected by a Noritake VFD display # in graphic mode. It only support the 3000 series graphical VFDs for now. # # 'sdl' uses the Simple DirectMedia Layer to render in a graphical context. # 'sdl_glsl' uses SDL to create an OpenGL context. Write your own shaders or # use one of the predefined ones. ; method = noncurses # Orientation of the visualization. Can be 'bottom', 'top', 'left' or 'right'. # Default is 'bottom'. Other orientations are only supported on sdl and ncruses # output. Note: many fonts have weird glyphs for 'top' and 'right' characters, # which can make ncurses not look right. ; orientation = bottom # Visual channels. Can be 'stereo' or 'mono'. # 'stereo' mirrors both channels with low frequencies in center. # 'mono' outputs left to right lowest to highest frequencies. # 'mono_option' set mono to either take input from 'left', 'right' or 'average'. # set 'reverse' to 1 to display frequencies the other way around. ; channels = stereo ; mono_option = average ; reverse = 0 # Raw output target. A fifo will be created if target does not exist. ; raw_target = /dev/stdout # Raw data format. Can be 'binary' or 'ascii'. ; data_format = binary # Binary bit format, can be '8bit' (0-255) or '16bit' (0-65530). ; bit_format = 16bit # Ascii max value. In 'ascii' mode range will run from 0 to value specified here ; ascii_max_range = 1000 # Ascii delimiters. In ascii format each bar and frame is separated by a delimiters. # Use decimal value in ascii table (i.e. 59 = ';' and 10 = '\n' (line feed)). ; bar_delimiter = 59 ; frame_delimiter = 10 # sdl window size and position. -1,-1 is centered. ; sdl_width = 1000 ; sdl_height = 500 ; sdl_x = -1 ; sdl_y= -1 ; sdl_full_screen = 0 # set label on bars on the x-axis. Can be 'frequency' or 'none'. Default: 'none' # 'frequency' displays the lower cut off frequency of the bar above. # Only supported on ncurses and noncurses output. ; xaxis = none # enable alacritty synchronized updates. 1 = on, 0 = off # removes flickering in alacritty terminal emulator. # defaults to off since the behaviour in other terminal emulators is unknown ; alacritty_sync = 0 # Shaders for sdl_glsl, located in $HOME/.config/cava/shaders ; vertex_shader = pass_through.vert ; fragment_shader = bar_spectrum.frag ; for glsl output mode, keep rendering even if no audio ; continuous_rendering = 0 # disable console blank (screen saver) in tty # (Not supported on FreeBSD) ; disable_blanking = 0 # show a flat bar at the bottom of the screen when idle, 1 = on, 0 = off ; show_idle_bar_heads = 1 # show waveform instead of frequency spectrum, 1 = on, 0 = off ; waveform = 0 [color] # Colors can be one of seven predefined: black, blue, cyan, green, magenta, red, white, yellow. # Or defined by hex code '#xxxxxx' (hex code must be within ''). User defined colors requires # a terminal that can change color definitions such as Gnome-terminal or rxvt. # default is to keep current terminal color ; background = default ; foreground = default # SDL and sdl_glsl only support hex code colors, these are the default: ; background = '#111111' ; foreground = '#33ffff' # Gradient mode, only hex defined colors are supported, # background must also be defined in hex or remain commented out. 1 = on, 0 = off. # You can define as many as 8 different colors. They range from bottom to top of screen ; gradient = 0 ; gradient_count = 8 ; gradient_color_1 = '#59cc33' ; gradient_color_2 = '#80cc33' ; gradient_color_3 = '#a6cc33' ; gradient_color_4 = '#cccc33' ; gradient_color_5 = '#cca633' ; gradient_color_6 = '#cc8033' ; gradient_color_7 = '#cc5933' ; gradient_color_8 = '#cc3333' [smoothing] # Percentage value for integral smoothing. Takes values from 0 - 100. # Higher values means smoother, but less precise. 0 to disable. # DEPRECATED as of 0.8.0, use noise_reduction instead ; integral = 77 # Disables or enables the so-called "Monstercat smoothing" with or without "waves". Set to 0 to disable. ; monstercat = 0 ; waves = 0 # Set gravity percentage for "drop off". Higher values means bars will drop faster. # Accepts only non-negative values. 50 means half gravity, 200 means double. Set to 0 to disable "drop off". # DEPRECATED as of 0.8.0, use noise_reduction instead ; gravity = 100 # In bar height, bars that would have been lower that this will not be drawn. # DEPRECATED as of 0.8.0 ; ignore = 0 # Noise reduction, int 0 - 100. default 77 # the raw visualization is very noisy, this factor adjusts the integral and gravity filters to keep the signal smooth # 100 will be very slow and smooth, 0 will be fast but noisy. ; noise_reduction = 77 [eq] # This one is tricky. You can have as much keys as you want. # Remember to uncomment more than one key! More keys = more precision. # Look at readme.md on github for further explanations and examples. ; 1 = 1 # bass ; 2 = 1 ; 3 = 1 # midtone ; 4 = 1 ; 5 = 1 # treble cava-0.10.2/example_files/etc/000077500000000000000000000000001462072613000160755ustar00rootroot00000000000000cava-0.10.2/example_files/etc/asound.conf000066400000000000000000000010411462072613000202310ustar00rootroot00000000000000pcm.!default { type plug # <-- no { here slave.pcm { type multi slaves { a { channels 2 pcm "hw:0,0" } # the real device b { channels 2 pcm "hw:Loopback,0" } # the loopback driver } bindings { 0 { slave a channel 0 } 1 { slave a channel 1 } 2 { slave b channel 0 } 3 { slave b channel 1 } } } ttable [ [ 1 0 1 0 ] # left -> a.left, b.left [ 0 1 0 1 ] # right -> a.right, b.right ] } cava-0.10.2/example_files/etc/asound_dmix.conf000066400000000000000000000027421462072613000212630ustar00rootroot00000000000000pcm.dmixed { type dmix ipc_key 1024 ipc_key_add_uid 0 slave { pcm "hw:1,0" #your hardware speaker device period_time 0 period_size 1024 buffer_size 4096 channels 2 } bindings { 0 0 1 1 } } pcm.dsnooped { type dsnoop ipc_key 1025 slave { pcm "hw:1,6" #your hardware input device (mic) period_time 0 period_size 1024 buffer_size 4096 channels 2 } bindings { 0 0 1 1 } } pcm.dmixerloop { type dmix ipc_key 2048 ipc_perm 0666 # allow other users slave.pcm "hw:Loopback,0,0" slave { period_time 0 period_size 1024 buffer_size 4096 channels 2 # must match bindings } bindings { 0 0 1 1 } } pcm.out { type plug route_policy "duplicate" slave.pcm { type multi slaves { a { channels 2 pcm "dmixed" } b { channels 2 pcm "dmixerloop" } } bindings { 0 { slave a channel 0 } 1 { slave a channel 1 } 2 { slave b channel 0 } 3 { slave b channel 1 } } } ttable [ [ 1 0 1 0 ] [ 0 1 0 1 ] ] } pcm.looprec { type hw card "Loopback" device 1 subdevice 0 } pcm.!default { type asym playback.pcm "out" #capture.pcm "looprec" capture.pcm "dsnooped" } ctl.!default { type hw card 1 }cava-0.10.2/example_files/etc/modprobe.d/000077500000000000000000000000001462072613000201265ustar00rootroot00000000000000cava-0.10.2/example_files/etc/modprobe.d/alsa-aloop.conf000066400000000000000000000001001462072613000230140ustar00rootroot00000000000000options snd-aloop index=1 enable=1 pcm_substreams=4 id=Loopback cava-0.10.2/example_files/test_configs/000077500000000000000000000000001462072613000200115ustar00rootroot00000000000000cava-0.10.2/example_files/test_configs/alsa_zero_test000066400000000000000000000004621462072613000227540ustar00rootroot00000000000000## test config file for CAVA, testing if zero alsa input gives zero bar height output # make sure to enable snd-aloop first with: sudo modprobe snd-aloop [general] draw_and_quit = 60 zero_test = 1 non_zero_test = 0 [input] method = alsa source = hw:Loopback,1 [output] method = raw data_format = asciicava-0.10.2/example_files/test_configs/fifo_zero_test000066400000000000000000000003511462072613000227540ustar00rootroot00000000000000## test config file for CAVA, testing if zero fifo input gives zero bar height output [general] draw_and_quit = 60 zero_test = 1 non_zero_test = 0 [input] method = fifo source = /dev/zero [output] method = raw data_format = asciicava-0.10.2/example_files/test_configs/non_zero_test000066400000000000000000000003621462072613000226250ustar00rootroot00000000000000## test config file for CAVA, testing if random fifo input gives non-zero bar height output [general] draw_and_quit = 60 zero_test = 0 non_zero_test = 1 [input] method = fifo source = /dev/urandom [output] method = raw data_format = asciicava-0.10.2/example_files/test_configs/pipewire_zero_test000066400000000000000000000003601462072613000236550ustar00rootroot00000000000000## test config file for CAVA, testing if zero pulseaudio input gives zero bar height output [general] draw_and_quit = 60 zero_test = 0 non_zero_test = 0 [input] method = pipewire source = auto [output] method = raw data_format = ascii cava-0.10.2/example_files/test_configs/portaudio_zero_test000066400000000000000000000002751462072613000240440ustar00rootroot00000000000000## test config file for CAVA, testing portaudio input. [general] draw_and_quit = 60 zero_test = 0 non_zero_test = 0 [input] method = portaudio [output] method = raw data_format = asciicava-0.10.2/example_files/test_configs/pulse_zero_test000066400000000000000000000003551462072613000231650ustar00rootroot00000000000000## test config file for CAVA, testing if zero pulseaudio input gives zero bar height output [general] draw_and_quit = 60 zero_test = 1 non_zero_test = 0 [input] method = pulse source = auto [output] method = raw data_format = ascii cava-0.10.2/example_files/test_configs/shmem_zero_test000066400000000000000000000004711462072613000231450ustar00rootroot00000000000000## test config file for CAVA, testing if zero shmem input gives zero bar height output # run squeezelite first with -v -m 51:fb:32:f8:e6:9f -z [general] draw_and_quit = 60 zero_test = 1 non_zero_test = 0 [input] method = shmem source = /squeezelite-51:fb:32:f8:e6:9f [output] method = raw data_format = asciicava-0.10.2/example_files/test_configs/sndio_zero_test000066400000000000000000000002741462072613000231510ustar00rootroot00000000000000## test config file for CAVA, testing if any sndio input. [general] draw_and_quit = 60 zero_test = 0 non_zero_test = 0 [input] method = sndio [output] method = raw data_format = asciicava-0.10.2/input/000077500000000000000000000000001462072613000136445ustar00rootroot00000000000000cava-0.10.2/input/alsa.c000066400000000000000000000064761462072613000147450ustar00rootroot00000000000000// input: ALSA #include "input/alsa.h" #include "debug.h" #include "input/common.h" #include #include #include // assuming stereo #define CHANNELS_COUNT 2 #define SAMPLE_RATE 44100 static void initialize_audio_parameters(snd_pcm_t **handle, struct audio_data *audio, snd_pcm_uframes_t *frames) { // alsa: open device to capture audio int err = snd_pcm_open(handle, audio->source, SND_PCM_STREAM_CAPTURE, 0); if (err < 0) { fprintf(stderr, "error opening stream: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } else debug("open stream successful\n"); snd_pcm_hw_params_t *params; snd_pcm_hw_params_alloca(¶ms); // assembling params snd_pcm_hw_params_any(*handle, params); // setting defaults or something // interleaved mode right left right left snd_pcm_hw_params_set_access(*handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); // trying to set 16bit snd_pcm_hw_params_set_format(*handle, params, SND_PCM_FORMAT_S16_LE); snd_pcm_hw_params_set_channels(*handle, params, CHANNELS_COUNT); unsigned int sample_rate = SAMPLE_RATE; // trying our rate snd_pcm_hw_params_set_rate_near(*handle, params, &sample_rate, NULL); // number of frames pr read snd_pcm_hw_params_set_period_size_near(*handle, params, frames, NULL); err = snd_pcm_hw_params(*handle, params); // attempting to set params if (err < 0) { fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } if ((err = snd_pcm_prepare(*handle)) < 0) { fprintf(stderr, "cannot prepare audio interface for use (%s)\n", snd_strerror(err)); exit(EXIT_FAILURE); } // getting actual format snd_pcm_hw_params_get_format(params, (snd_pcm_format_t *)&sample_rate); // converting result to number of bits if (sample_rate <= 5) audio->format = 16; else if (sample_rate <= 9) audio->format = 24; else audio->format = 32; snd_pcm_hw_params_get_rate(params, &audio->rate, NULL); snd_pcm_hw_params_get_period_size(params, frames, NULL); // snd_pcm_hw_params_get_period_time(params, &sample_rate, &dir); } void *input_alsa(void *data) { int err; struct audio_data *audio = (struct audio_data *)data; snd_pcm_t *handle; snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t period_size; snd_pcm_uframes_t frames = audio->input_buffer_size / 2; initialize_audio_parameters(&handle, audio, &frames); snd_pcm_get_params(handle, &buffer_size, &period_size); unsigned char buf[buffer_size]; frames = period_size / ((audio->format / 8) * CHANNELS_COUNT); signed char *buffer = malloc(period_size); while (!audio->terminate) { err = snd_pcm_readi(handle, buf, frames); if (err == -EPIPE) { /* EPIPE means overrun */ debug("overrun occurred\n"); snd_pcm_prepare(handle); } else if (err < 0) { debug("error from read: %s\n", snd_strerror(err)); } else if (err != (int)frames) { debug("short read, read %d %d frames\n", err, (int)frames); } write_to_cava_input_buffers(frames * CHANNELS_COUNT, buf, data); } free(buffer); snd_pcm_close(handle); return NULL; } cava-0.10.2/input/alsa.h000066400000000000000000000001241462072613000147320ustar00rootroot00000000000000// header file for alsa, part of cava. #pragma once void *input_alsa(void *data); cava-0.10.2/input/common.c000066400000000000000000000042451462072613000153050ustar00rootroot00000000000000#include "input/common.h" #include #include #include int write_to_cava_input_buffers(int16_t samples, unsigned char *buf, void *data) { if (samples == 0) return 0; struct audio_data *audio = (struct audio_data *)data; pthread_mutex_lock(&audio->lock); int bytes_per_sample = audio->format / 8; if (audio->samples_counter + samples > audio->cava_buffer_size) { // buffer overflow, discard what ever is in the buffer and start over for (uint16_t n = 0; n < audio->cava_buffer_size; n++) { audio->cava_in[n] = 0; } audio->samples_counter = 0; } int n = 0; for (uint16_t i = 0; i < samples; i++) { switch (bytes_per_sample) { case 1:; int8_t *buf8 = (int8_t *)&buf[n]; audio->cava_in[i + audio->samples_counter] = *buf8 * UCHAR_MAX; break; case 3: case 4:; if (audio->IEEE_FLOAT) { float *ieee_float = (float *)&buf[n]; audio->cava_in[i + audio->samples_counter] = *ieee_float * USHRT_MAX; } else { int32_t *buf32 = (int32_t *)&buf[n]; audio->cava_in[i + audio->samples_counter] = (double)*buf32 / USHRT_MAX; } break; default:; int16_t *buf16 = (int16_t *)&buf[n]; audio->cava_in[i + audio->samples_counter] = *buf16; break; } n += bytes_per_sample; } audio->samples_counter += samples; pthread_mutex_unlock(&audio->lock); return 0; } void reset_output_buffers(struct audio_data *data) { struct audio_data *audio = (struct audio_data *)data; pthread_mutex_lock(&audio->lock); for (uint16_t n = 0; n < audio->cava_buffer_size; n++) { audio->cava_in[n] = 0; } pthread_mutex_unlock(&audio->lock); } void signal_threadparams(struct audio_data *audio) { pthread_mutex_lock(&audio->lock); audio->threadparams = 0; pthread_mutex_unlock(&audio->lock); } void signal_terminate(struct audio_data *audio) { pthread_mutex_lock(&audio->lock); audio->terminate = 1; pthread_mutex_unlock(&audio->lock); } cava-0.10.2/input/common.h000066400000000000000000000025041462072613000153060ustar00rootroot00000000000000#pragma once #include #include #include #include #include #include #include #ifndef _MSC_VER #include #endif // number of samples to read from audio source per channel #define BUFFER_SIZE 512 struct audio_data { double *cava_in; int input_buffer_size; int cava_buffer_size; int format; unsigned int rate; unsigned int channels; int threadparams; // shared variable used to prevent main thread from cava_init before input // threads have finalized parameters (0=allow cava_init, 1=disallow) char *source; // alsa device, fifo path or pulse source int im; // input mode alsa, fifo, pulse, portaudio, shmem or sndio int terminate; // shared variable used to terminate audio thread char error_message[1024]; int samples_counter; int IEEE_FLOAT; // format for 32bit (0=int, 1=float) int autoconnect; // auto connect to audio source (0=off, 1=once at startup, 2=regularly) pthread_mutex_t lock; }; void reset_output_buffers(struct audio_data *data); void signal_threadparams(struct audio_data *data); void signal_terminate(struct audio_data *data); int write_to_cava_input_buffers(int16_t size, unsigned char *buf, void *data); extern pthread_mutex_t lock; cava-0.10.2/input/fifo.c000066400000000000000000000032541462072613000147370ustar00rootroot00000000000000#include "input/fifo.h" #include "input/common.h" #include int open_fifo(const char *path) { int fd = open(path, O_RDONLY); int flags = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, flags | O_NONBLOCK); return fd; } // input: FIFO void *input_fifo(void *data) { struct audio_data *audio = (struct audio_data *)data; unsigned char buf[audio->input_buffer_size * audio->format / 8]; int fd = open_fifo(audio->source); int test_mode = 0; if (strcmp(audio->source, "/dev/zero") == 0) { test_mode = 1; } while (!audio->terminate) { int time_since_last_input = 0; unsigned int offset = 0; do { int num_read = read(fd, buf + offset, sizeof(buf) - offset); if (num_read < 1) { // if no bytes read sleep 10ms and zero shared buffer nanosleep(&(struct timespec){.tv_sec = 0, .tv_nsec = 10000000}, NULL); time_since_last_input++; if (time_since_last_input > 10) { reset_output_buffers(audio); close(fd); fd = open_fifo(audio->source); time_since_last_input = 0; offset = 0; } } else { offset += num_read; time_since_last_input = 0; } } while (offset < sizeof(buf)); write_to_cava_input_buffers(audio->input_buffer_size, buf, audio); if (test_mode) { nanosleep(&(struct timespec){.tv_sec = 0, .tv_nsec = 1000000}, NULL); // sleep 1 ms to prevent deadlock reading from /dev/zero } } close(fd); return 0; } cava-0.10.2/input/fifo.h000066400000000000000000000001241462072613000147350ustar00rootroot00000000000000// header files for fifo, part of cava #pragma once void *input_fifo(void *data); cava-0.10.2/input/jack.c000066400000000000000000000303211462072613000147170ustar00rootroot00000000000000#include #include #include #include "input/common.h" #include "input/jack.h" // CAVA is hard-coded to a maximum of 2 channels, i.e. stereo. #define MAX_CHANNELS 2 typedef jack_default_audio_sample_t sample_t; struct jack_data { struct audio_data *audio; // CAVA ctx jack_client_t *client; // JACK client jack_port_t *port[MAX_CHANNELS]; // input ports jack_nframes_t nframes; // number of samples per port sample_t *buf; // samples buffer int graphorder; // JACK graph ordering signal (0=unchanged, 1=changed) int shutdown; // JACK shutdown signal (0=keep, 1=shutdown) }; static bool set_rate(struct jack_data *jack) { // Query sample rate from JACK server. If CAVA doesn't support the final value then it will // complain later. jack_nframes_t rate = jack_get_sample_rate(jack->client); if (rate <= 0) { fprintf(stderr, __FILE__ ": jack_get_sample_rate() failed.\n"); return false; } jack->audio->rate = rate; return true; } static bool set_format(struct jack_data *jack) { // JACK returns 32bit float data. jack->audio->format = 32; jack->audio->IEEE_FLOAT = 1; return true; } static bool set_channels(struct jack_data *jack) { // Try to create terminal audio-typed input ports for the requested number of channels. These // ports can receive the audio data from other JACK clients. static const char *port_name[MAX_CHANNELS][MAX_CHANNELS] = {/* mono */ {"M", NULL}, /* stereo */ {"L", "R"}}; static const char port_type[] = JACK_DEFAULT_AUDIO_TYPE; static const unsigned long flags = JackPortIsInput | JackPortIsTerminal; int channels; int chtype; int ch; // Limit the requested channels in case CAVA becomes surround-aware and MAX_CHANNELS hasn't // adapted yet. channels = jack->audio->channels > MAX_CHANNELS ? MAX_CHANNELS : jack->audio->channels; // Determines the row in the 'port_name' table, i.e. mono, stereo, etc... chtype = channels - 1; // Try to create a port for every requested channel. After the for-loop the variable 'ch' holds // the number of actual created ports. for (ch = 0; ch < channels; ++ch) { if ((jack->port[ch] = jack_port_register(jack->client, port_name[chtype][ch], port_type, flags, 0)) == NULL) break; } // If not even one port was created, then there was a deeper problem. if (ch == 0) { fprintf(stderr, __FILE__ ": jack_port_register('%s') failed.\n", port_name[chtype][0]); return false; } // If less ports were created than channels requested, then the JACK server is probably not // configured for the requested channels, e.g. we requested stereo but the server only provides // mono. In this case we rename the created ports according to the resulting table row. if (ch < channels) { int chtype_new; channels = ch; chtype_new = channels - 1; for (ch = 0; ch < channels; ++ch) { int err; if ((err = jack_port_rename(jack->client, jack->port[ch], port_name[chtype_new][ch])) != 0) { fprintf(stderr, __FILE__ ": jack_port_rename('%s', '%s') failed: 0x%x\n", port_name[chtype][ch], port_name[chtype_new][ch], err); return false; } } } jack->audio->channels = channels; return true; } static int on_buffer_size(jack_nframes_t nframes, void *arg) { // Buffersize changes should never happen in CAVA! struct jack_data *jack = arg; if ((jack->shutdown == 1) || (jack->audio->terminate == 1)) return 0; if (jack->nframes != nframes) { fprintf(stderr, __FILE__ ": Unexpected change of JACK port buffersize! Aborting!\n"); jack->shutdown = 1; return 1; } return 0; } static int on_graph_order(void *arg) { ((struct jack_data *)arg)->graphorder = 1; return 0; } static int on_process(jack_nframes_t nframes, void *arg) { // Interleave samples from separate ports and feed them to CAVA. struct jack_data *jack = arg; sample_t *buf[MAX_CHANNELS]; unsigned char *buf_cava; if ((jack->shutdown == 1) || (jack->audio->terminate == 1)) return 0; for (unsigned int i = 0; i < jack->audio->channels; ++i) { if ((buf[i] = jack_port_get_buffer(jack->port[i], nframes)) == NULL) { fprintf(stderr, __FILE__ ": jack_port_get_buffer('%s') failed.\n", jack_port_name(jack->port[i])); jack->shutdown = 1; return 1; } } switch (jack->audio->channels) { case 1: // If mono then no interleaving needed, feed into CAVA directly. buf_cava = (unsigned char *)buf[0]; break; case 2: // If stereo then unroll interleaving manually. for (jack_nframes_t i = 0; i < nframes; ++i) { jack->buf[2 * i + 0] = buf[0][i]; jack->buf[2 * i + 1] = buf[1][i]; } buf_cava = (unsigned char *)jack->buf; break; default: // Else to the loops. for (jack_nframes_t i = 0; i < nframes; ++i) { for (unsigned int j = 0; j < jack->audio->channels; ++j) jack->buf[jack->audio->channels * i + j] = buf[j][i]; } buf_cava = (unsigned char *)jack->buf; break; } write_to_cava_input_buffers(nframes * jack->audio->channels, buf_cava, jack->audio); return 0; } static int on_sample_rate(jack_nframes_t nframes, void *arg) { // Sample rate changes are not supported in CAVA! struct jack_data *jack = arg; if ((jack->shutdown == 1) || (jack->audio->terminate == 1)) return 0; if (jack->audio->rate != nframes) { fprintf(stderr, __FILE__ ": Unexpected change of JACK sample rate! Aborting!\n"); jack->shutdown = 1; return 1; } return 0; } static void on_shutdown(void *arg) { ((struct jack_data *)arg)->shutdown = 1; } static bool auto_connect(struct jack_data *jack) { // Get all physical terminal input-ports and mirror their connections to CAVA. static const char type_name_pattern[] = JACK_DEFAULT_AUDIO_TYPE; static const unsigned long flags = JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal; unsigned int channels; const char **ports = NULL; bool success = false; if ((jack->shutdown == 1) || (jack->audio->terminate == 1)) return true; if ((ports = jack_get_ports(jack->client, NULL, type_name_pattern, flags)) == NULL) { fprintf(stderr, __FILE__ ": jack_get_ports() failed: No physical terminal input-ports found!\n"); goto cleanup; } // If CAVA is configured for mono, then we connect everything to the one mono port. If we have // more channels, then we limit the number of connection ports to the number of channels. for (channels = 0; ports[channels] != NULL; ++channels) ; if ((jack->audio->channels > 1) && (channels > jack->audio->channels)) channels = jack->audio->channels; // Visit the physical terminal input-ports, get their connections and apply them to CAVA's // input-ports. for (unsigned int i = 0; i < channels; ++i) { const char **connections; jack_port_t *port; const char *port_name; if ((connections = jack_port_get_all_connections( jack->client, jack_port_by_name(jack->client, ports[i]))) == NULL) continue; if (jack->audio->channels == 1) port = jack->port[0]; else port = jack->port[i]; port_name = jack_port_name(port); for (int j = 0; connections[j] != NULL; ++j) { if (jack_port_connected_to(port, connections[j]) == 0) jack_connect(jack->client, connections[j], port_name); } jack_free(connections); } success = true; cleanup: if (!success) jack->shutdown = 1; jack_free(ports); return success; } void *input_jack(void *data) { static const char client_name[] = "cava"; static const jack_options_t options = JackNullOption | JackServerName; static const struct timespec rqtp = {.tv_sec = 0, .tv_nsec = 1000000}; // 1ms nsleep struct audio_data *audio = data; char *server_name; jack_status_t status; int err; struct jack_data jack = {0}; bool is_jack_activated = false; bool success = false; jack.audio = audio; // JACK server selection by source or implicit default. if (strlen(audio->source) == 0) server_name = NULL; else server_name = audio->source; if ((jack.client = jack_client_open(client_name, options, &status, server_name)) == NULL) { fprintf(stderr, __FILE__ ": Could not open JACK source '%s': 0x%x\n", server_name, status); goto cleanup; } if (!set_rate(&jack) || !set_format(&jack) || !set_channels(&jack)) goto cleanup; // Parameters finalized. Signal main thread. signal_threadparams(audio); // JACK returns samples per channel. Adjust its buffersize to fit within CAVA. // Must be a power of 2. jack.nframes = 1 << 31; while (jack.nframes > audio->input_buffer_size / audio->channels) jack.nframes >>= 1; if ((err = jack_set_buffer_size(jack.client, jack.nframes)) != 0) { fprintf(stderr, __FILE__ ": jack_set_buffer_size() failed: 0x%x\n", err); goto cleanup; } // Work buffer for interleaving if not mono. if ((audio->channels > 1) && ((jack.buf = malloc(jack.nframes * audio->channels * sizeof(sample_t))) == NULL)) { fprintf(stderr, __FILE__ ": malloc() failed: %s\n", strerror(errno)); goto cleanup; } // Set JACK callbacks before JACK activation. if ((err = jack_set_buffer_size_callback(jack.client, on_buffer_size, &jack)) != 0) { fprintf(stderr, __FILE__ ": jack_set_buffer_size_callback() failed: 0x%x\n", err); goto cleanup; } if (audio->autoconnect > 0) { if (audio->autoconnect == 1) jack.graphorder = 1; else { if ((err = jack_set_graph_order_callback(jack.client, on_graph_order, &jack)) != 0) { fprintf(stderr, __FILE__ ": jack_set_graph_order_callback() failed: 0x%x\n", err); goto cleanup; } } } if ((err = jack_set_process_callback(jack.client, on_process, &jack)) != 0) { fprintf(stderr, __FILE__ ": jack_set_process_callback() failed: 0x%x\n", err); goto cleanup; } if ((err = jack_set_sample_rate_callback(jack.client, on_sample_rate, &jack)) != 0) { fprintf(stderr, __FILE__ ": jack_set_sample_rate_callback() failed: 0x%x\n", err); goto cleanup; } jack_on_shutdown(jack.client, on_shutdown, &jack); if ((err = jack_activate(jack.client)) != 0) { fprintf(stderr, __FILE__ ": jack_activate() failed: 0x%x\n", err); goto cleanup; } is_jack_activated = true; while (audio->terminate != 1) { if (jack.shutdown == 1) signal_terminate(audio); else if (jack.graphorder == 1) { if (!auto_connect(&jack)) goto cleanup; jack.graphorder = 0; } nanosleep(&rqtp, NULL); } success = true; cleanup: if (is_jack_activated && ((err = jack_deactivate(jack.client)) != 0)) { fprintf(stderr, __FILE__ ": jack_deactivate() failed: 0x%x\n", err); success = false; } free(jack.buf); for (int i = 0; i < MAX_CHANNELS; ++i) { if ((jack.port[i] != NULL) && ((err = jack_port_unregister(jack.client, jack.port[i])) != 0)) { fprintf(stderr, __FILE__ ": jack_port_unregister('%s') failed: 0x%x\n", jack_port_name(jack.port[i]), err); success = false; } } if ((jack.client != NULL) && ((err = jack_client_close(jack.client)) != 0)) { fprintf(stderr, __FILE__ ": jack_client_close() failed: 0x%x\n", err); success = false; } signal_threadparams(audio); signal_terminate(audio); if (!success) exit(EXIT_FAILURE); return NULL; } cava-0.10.2/input/jack.h000066400000000000000000000001241462072613000147220ustar00rootroot00000000000000// header file for jack, part of cava. #pragma once void *input_jack(void *data); cava-0.10.2/input/oss.c000066400000000000000000000124361462072613000146220ustar00rootroot00000000000000#include #include #include #include #include "input/common.h" #include "input/oss.h" static bool set_format(int fd, struct audio_data *audio) { // CAVA favors signed and little endian (sle) formats. It might actually not work correctly if // we feed it an unsigned or big endian format. Therefore we prefer to select one of the // supported sle formats, if any exist. // The favored sle formats. 16bit has priority, followed by "bigger is better". static const int fmts_sle[] = {AFMT_S16_LE, AFMT_S32_LE, AFMT_S24_LE, AFMT_S8}; // Bitmasks of formats categorized by bitlength. static const int fmts_8bits = AFMT_U8 | AFMT_S8; static const int fmts_16bits = AFMT_S16_LE | AFMT_S16_BE | AFMT_U16_LE | AFMT_U16_BE; static const int fmts_24bits = AFMT_S24_LE | AFMT_S24_BE | AFMT_U24_LE | AFMT_U24_BE; static const int fmts_32bits = AFMT_S32_LE | AFMT_S32_BE | AFMT_U32_LE | AFMT_U32_BE; int fmts; int fmt; // Get all supported formats from the audio device. if (ioctl(fd, SNDCTL_DSP_GETFMTS, &fmts) == -1) { fprintf(stderr, __FILE__ ": ioctl(SNDCTL_DSP_GETFMTS) failed: %s\n", strerror(errno)); return false; } // Determine the sle format for the requested bitlength. switch (audio->format) { case 8: fmt = AFMT_S8; break; case 16: fmt = AFMT_S16_LE; break; case 24: fmt = AFMT_S24_LE; break; case 32: fmt = AFMT_S32_LE; break; default: fprintf(stderr, __FILE__ ": Invalid format: %d\n", audio->format); return false; } // If the requested format is not available then test for the other sle formats. if (!(fmts & fmt)) { for (size_t i = 0; i < sizeof(fmts_sle) / sizeof(fmts_sle[0]); ++i) { if (fmts & fmts_sle[i]) { fmt = fmts_sle[i]; break; } } } // Set the format of the device. If not supported then OSS will adjust to a supported format. if (ioctl(fd, SNDCTL_DSP_SETFMT, &fmt) == -1) { fprintf(stderr, __FILE__ ": ioctl(SNDCTL_DSP_SETFMT) failed: %s\n", strerror(errno)); return false; } // Determine the actual bitlength of the returned format. if (fmts_8bits & fmt) audio->format = 8; else if (fmts_16bits & fmt) audio->format = 16; else if (fmts_24bits & fmt) audio->format = 24; else if (fmts_32bits & fmt) audio->format = 32; else { fprintf(stderr, __FILE__ ": No support for 8, 16, 24 or 32 bits in OSS source '%s'.\n", audio->source); return false; } return true; } static bool set_channels(int fd, struct audio_data *audio) { // Try to set the requested channels, OSS will adjust to a supported value. If CAVA doesn't // support the final value then it will complain later. int channels = audio->channels; if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1) { fprintf(stderr, __FILE__ ": ioctl(SNDCTL_DSP_CHANNELS) failed: %s\n", strerror(errno)); return false; } audio->channels = channels; return true; } static bool set_rate(int fd, struct audio_data *audio) { // Try to set the requested rate, OSS will adjust to a supported value. If CAVA doesn't support // the final value then it will complain later. int rate = audio->rate; if (ioctl(fd, SNDCTL_DSP_SPEED, &rate) == -1) { fprintf(stderr, __FILE__ ": ioctl(SNDCTL_DSP_SPEED) failed: %s\n", strerror(errno)); return false; } audio->rate = rate; return true; } void *input_oss(void *data) { static const int flags = O_RDONLY; struct audio_data *audio = data; int bytes; size_t buf_size; int fd = -1; void *buf = NULL; bool success = false; if ((fd = open(audio->source, flags, 0)) == -1) { fprintf(stderr, __FILE__ ": Could not open OSS source '%s': %s\n", audio->source, strerror(errno)); goto cleanup; } // For OSS it's adviced to determine format, channels and rate in this order. if (!set_format(fd, audio) || !set_channels(fd, audio) || !set_rate(fd, audio)) goto cleanup; // Parameters finalized. Signal main thread. signal_threadparams(audio); // OSS uses 32 bits for 24bit. if (audio->format == 24) bytes = 4; // = 32 / 8 else bytes = audio->format / 8; buf_size = audio->input_buffer_size * bytes; if ((buf = malloc(buf_size)) == NULL) { fprintf(stderr, __FILE__ ": malloc() failed: %s\n", strerror(errno)); goto cleanup; } while (audio->terminate != 1) { ssize_t rd; if ((rd = read(fd, buf, buf_size)) < 0) { fprintf(stderr, __FILE__ ": read() failed: %s\n", strerror(errno)); goto cleanup; } else if (rd == 0) signal_terminate(audio); else write_to_cava_input_buffers(rd / bytes, buf, audio); } success = true; cleanup: free(buf); if ((fd >= 0) && (close(fd) == -1)) { fprintf(stderr, __FILE__ ": close() failed: %s\n", strerror(errno)); success = false; } signal_threadparams(audio); signal_terminate(audio); if (!success) exit(EXIT_FAILURE); return NULL; } cava-0.10.2/input/oss.h000066400000000000000000000001221462072613000146140ustar00rootroot00000000000000// header file for oss, part of cava. #pragma once void *input_oss(void *data); cava-0.10.2/input/pipewire.c000066400000000000000000000107261462072613000156420ustar00rootroot00000000000000#include "input/pipewire.h" #include "input/common.h" #include #include #include #include struct pw_data { struct pw_main_loop *loop; struct pw_stream *stream; struct spa_audio_info format; unsigned move : 1; struct audio_data *cava_audio; }; static void on_process(void *userdata) { struct pw_data *data = userdata; struct pw_buffer *b; struct spa_buffer *buf; uint32_t n_samples; int16_t *samples; if (data->cava_audio->terminate == 1) pw_main_loop_quit(data->loop); if ((b = pw_stream_dequeue_buffer(data->stream)) == NULL) { pw_log_warn("out of buffers: %m"); return; } buf = b->buffer; if ((samples = buf->datas[0].data) == NULL) return; n_samples = buf->datas[0].chunk->size / (data->cava_audio->format / 8); write_to_cava_input_buffers(n_samples, buf->datas[0].data, data->cava_audio); pw_stream_queue_buffer(data->stream, b); } static void on_stream_param_changed(void *_data, uint32_t id, const struct spa_pod *param) { struct pw_data *data = _data; if (param == NULL || id != SPA_PARAM_Format) return; if (spa_format_parse(param, &data->format.media_type, &data->format.media_subtype) < 0) return; if (data->format.media_type != SPA_MEDIA_TYPE_audio || data->format.media_subtype != SPA_MEDIA_SUBTYPE_raw) return; spa_format_audio_raw_parse(param, &data->format.info.raw); } static const struct pw_stream_events stream_events = { PW_VERSION_STREAM_EVENTS, .param_changed = on_stream_param_changed, .process = on_process, }; static void do_quit(void *userdata, int signal_number) { struct pw_data *data = userdata; data->cava_audio->terminate = 1; pw_log_warn("pw quit signal %d received, terminating...", signal_number); pw_main_loop_quit(data->loop); } void *input_pipewire(void *audiodata) { struct pw_data data = { 0, }; data.cava_audio = (struct audio_data *)audiodata; const struct spa_pod *params[1]; uint8_t buffer[data.cava_audio->input_buffer_size]; struct pw_properties *props; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); uint32_t nom; nom = nearbyint((10000 * data.cava_audio->rate) / 1000000.0); pw_init(0, 0); data.loop = pw_main_loop_new(NULL); if (data.loop == NULL) { data.cava_audio->terminate = 1; sprintf(data.cava_audio->error_message, __FILE__ ": Could not create main loop. Is your system running pipewire? Maybe try " "pulse input method instead."); return 0; } pw_loop_add_signal(pw_main_loop_get_loop(data.loop), SIGINT, do_quit, &data); pw_loop_add_signal(pw_main_loop_get_loop(data.loop), SIGTERM, do_quit, &data); props = pw_properties_new(PW_KEY_MEDIA_TYPE, "Audio", PW_KEY_MEDIA_CATEGORY, "Capture", PW_KEY_MEDIA_ROLE, "Music", NULL); const char *source = data.cava_audio->source; if (strcmp(source, "auto") == 0) { pw_properties_set(props, PW_KEY_STREAM_CAPTURE_SINK, "true"); } else { pw_properties_set(props, PW_KEY_TARGET_OBJECT, source); } pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%u/%u", nom, data.cava_audio->rate); pw_properties_set(props, PW_KEY_NODE_ALWAYS_PROCESS, "true"); data.stream = pw_stream_new_simple(pw_main_loop_get_loop(data.loop), "cava", props, &stream_events, &data); enum spa_audio_format audio_format = SPA_AUDIO_FORMAT_S16; switch (data.cava_audio->format) { case 8: audio_format = SPA_AUDIO_FORMAT_S8; break; case 16: audio_format = SPA_AUDIO_FORMAT_S16; break; case 24: audio_format = SPA_AUDIO_FORMAT_S24; break; case 32: audio_format = SPA_AUDIO_FORMAT_S32; break; }; params[0] = spa_format_audio_raw_build( &b, SPA_PARAM_EnumFormat, &SPA_AUDIO_INFO_RAW_INIT(.format = audio_format, .rate = data.cava_audio->rate)); pw_stream_connect(data.stream, PW_DIRECTION_INPUT, PW_ID_ANY, PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_MAP_BUFFERS | PW_STREAM_FLAG_RT_PROCESS, params, 1); pw_main_loop_run(data.loop); pw_stream_destroy(data.stream); pw_main_loop_destroy(data.loop); pw_deinit(); return 0; } cava-0.10.2/input/pipewire.h000066400000000000000000000001331462072613000156360ustar00rootroot00000000000000// header file for pipewire, part of cava. #pragma once void *input_pipewire(void *data);cava-0.10.2/input/portaudio.c000066400000000000000000000133771462072613000160310ustar00rootroot00000000000000#include "input/portaudio.h" #include "input/common.h" #include #define SAMPLE_SILENCE -32767 #define PA_SAMPLE_TYPE paInt16 typedef short SAMPLE; typedef struct { int frameIndex; /* Index into sample array. */ int maxFrameIndex; SAMPLE *recordedSamples; } paTestData; static struct audio_data *audio; int16_t silence_buffer[8092] = {SAMPLE_SILENCE}; static int recordCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData) { paTestData *data = (paTestData *)userData; unsigned char *rptr = (unsigned char *)inputBuffer; unsigned char *silence_ptr = (unsigned char *)silence_buffer; long framesToCalc; int finished; unsigned long framesLeft = data->maxFrameIndex - data->frameIndex; (void)outputBuffer; // Prevent unused variable warnings. (void)timeInfo; (void)statusFlags; (void)userData; if (framesLeft < framesPerBuffer) { framesToCalc = framesLeft; finished = paComplete; } else { framesToCalc = framesPerBuffer; finished = paContinue; } if (inputBuffer == NULL) write_to_cava_input_buffers(framesToCalc * 2, silence_ptr, audio); else write_to_cava_input_buffers(framesToCalc * 2, rptr, audio); data->frameIndex += framesToCalc; if (finished == paComplete) { data->frameIndex = 0; finished = paContinue; } if (audio->terminate == 1) finished = paComplete; return finished; } void portaudio_simple_free(paTestData data) { Pa_Terminate(); free(data.recordedSamples); } void *input_portaudio(void *audiodata) { audio = (struct audio_data *)audiodata; PaStreamParameters inputParameters; PaStream *stream; PaError err = paNoError; paTestData data; // start portaudio err = Pa_Initialize(); if (err != paNoError) { fprintf(stderr, "Error: unable to initilize portaudio - %s\n", Pa_GetErrorText(err)); exit(EXIT_FAILURE); } // get portaudio device int deviceNum = -1, numOfDevices = Pa_GetDeviceCount(); if (!strcmp(audio->source, "list")) { if (numOfDevices < 0) { fprintf(stderr, "Error: portaudio was unable to find a audio device! Code: 0x%x\n", numOfDevices); exit(EXIT_FAILURE); } for (int i = 0; i < numOfDevices; i++) { const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo(i); printf("Device #%d: %s\n" "\tInput Channels: %d\n" "\tOutput Channels: %d\n" "\tDefault SampleRate: %lf\n", i + 1, deviceInfo->name, deviceInfo->maxInputChannels, deviceInfo->maxOutputChannels, deviceInfo->defaultSampleRate); } exit(EXIT_SUCCESS); } else if (!strcmp(audio->source, "auto")) { deviceNum = Pa_GetDefaultInputDevice(); if (deviceNum == paNoDevice) { fprintf(stderr, "Error: no portaudio input device found\n"); exit(EXIT_FAILURE); } } else if (sscanf(audio->source, "%d", &deviceNum)) { if (deviceNum > numOfDevices) { fprintf(stderr, "Error: Invalid input device!\n"); exit(EXIT_FAILURE); } deviceNum--; } else { for (int i = 0; i < numOfDevices; i++) { const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo(i); if (!strcmp(audio->source, deviceInfo->name)) { deviceNum = i; break; } } if (deviceNum == -1) { fprintf(stderr, "Error: No such device '%s'!\n", audio->source); exit(EXIT_FAILURE); } } inputParameters.device = deviceNum; // set parameters data.maxFrameIndex = audio->input_buffer_size * 1024 / 2; data.recordedSamples = (SAMPLE *)malloc(2 * data.maxFrameIndex * sizeof(SAMPLE)); if (data.recordedSamples == NULL) { fprintf(stderr, "Error: failure in memory allocation!\n"); exit(EXIT_FAILURE); } else memset(data.recordedSamples, 0x00, 2 * data.maxFrameIndex); inputParameters.channelCount = 2; inputParameters.sampleFormat = PA_SAMPLE_TYPE; inputParameters.suggestedLatency = Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency; inputParameters.hostApiSpecificStreamInfo = NULL; // set it to work err = Pa_OpenStream(&stream, &inputParameters, NULL, audio->rate, audio->input_buffer_size / 2, paClipOff, recordCallback, &data); if (err != paNoError) { fprintf(stderr, "Error: failure in opening stream (%s)\n", Pa_GetErrorText(err)); exit(EXIT_FAILURE); } // main loop while (1) { // start recording data.frameIndex = 0; err = Pa_StartStream(stream); if (err != paNoError) { fprintf(stderr, "Error: failure in starting stream (%s)\n", Pa_GetErrorText(err)); exit(EXIT_FAILURE); } // record while ((err = Pa_IsStreamActive(stream)) == 1) { Pa_Sleep(1000); if (audio->terminate == 1) break; } // check for errors if (err < 0) { fprintf(stderr, "Error: failure in recording audio (%s)\n", Pa_GetErrorText(err)); exit(EXIT_FAILURE); } // check if it bailed if (audio->terminate == 1) break; } // close stream if ((err = Pa_CloseStream(stream)) != paNoError) { fprintf(stderr, "Error: failure in closing stream (%s)\n", Pa_GetErrorText(err)); exit(EXIT_FAILURE); } portaudio_simple_free(data); return 0; } cava-0.10.2/input/portaudio.h000066400000000000000000000000661462072613000160250ustar00rootroot00000000000000#pragma once void *input_portaudio(void *audiodata); cava-0.10.2/input/pulse.c000066400000000000000000000107071462072613000151450ustar00rootroot00000000000000#include "input/pulse.h" #include "input/common.h" #include #include #include pa_mainloop *m_pulseaudio_mainloop; void cb(__attribute__((unused)) pa_context *pulseaudio_context, const pa_server_info *i, void *userdata) { // getting default sink name struct audio_data *audio = (struct audio_data *)userdata; pthread_mutex_lock(&audio->lock); free(audio->source); audio->source = malloc(sizeof(char) * 1024); strcpy(audio->source, i->default_sink_name); // appending .monitor suufix audio->source = strcat(audio->source, ".monitor"); pthread_mutex_unlock(&audio->lock); // quiting mainloop pa_context_disconnect(pulseaudio_context); pa_context_unref(pulseaudio_context); pa_mainloop_quit(m_pulseaudio_mainloop, 0); pa_mainloop_free(m_pulseaudio_mainloop); } void pulseaudio_context_state_callback(pa_context *pulseaudio_context, void *userdata) { // make sure loop is ready switch (pa_context_get_state(pulseaudio_context)) { case PA_CONTEXT_UNCONNECTED: // printf("UNCONNECTED\n"); break; case PA_CONTEXT_CONNECTING: // printf("CONNECTING\n"); break; case PA_CONTEXT_AUTHORIZING: // printf("AUTHORIZING\n"); break; case PA_CONTEXT_SETTING_NAME: // printf("SETTING_NAME\n"); break; case PA_CONTEXT_READY: // extract default sink name // printf("READY\n"); pa_operation_unref(pa_context_get_server_info(pulseaudio_context, cb, userdata)); break; case PA_CONTEXT_FAILED: fprintf(stderr, "failed to connect to pulseaudio server\n"); exit(EXIT_FAILURE); break; case PA_CONTEXT_TERMINATED: // printf("TERMINATED\n"); pa_mainloop_quit(m_pulseaudio_mainloop, 0); break; } } void getPulseDefaultSink(void *data) { struct audio_data *audio = (struct audio_data *)data; pa_mainloop_api *mainloop_api; pa_context *pulseaudio_context; int ret; // Create a mainloop API and connection to the default server m_pulseaudio_mainloop = pa_mainloop_new(); mainloop_api = pa_mainloop_get_api(m_pulseaudio_mainloop); pulseaudio_context = pa_context_new(mainloop_api, "cava device list"); // This function connects to the pulse server pa_context_connect(pulseaudio_context, NULL, PA_CONTEXT_NOFLAGS, NULL); // printf("connecting to server\n"); // This function defines a callback so the server will tell us its state. pa_context_set_state_callback(pulseaudio_context, pulseaudio_context_state_callback, (void *)audio); // starting a mainloop to get default sink // starting with one nonblokng iteration in case pulseaudio is not able to run if (!(ret = pa_mainloop_iterate(m_pulseaudio_mainloop, 0, &ret))) { fprintf(stderr, "Could not open pulseaudio mainloop to " "find default device name: %d\n" "check if pulseaudio is running\n", ret); exit(EXIT_FAILURE); } pa_mainloop_run(m_pulseaudio_mainloop, &ret); } void *input_pulse(void *data) { struct audio_data *audio = (struct audio_data *)data; uint16_t buffer_size = audio->input_buffer_size * audio->format / 8; unsigned char buf[buffer_size]; /* The sample type to use */ static const pa_sample_spec ss = {.format = PA_SAMPLE_S16LE, .rate = 44100, .channels = 2}; pa_buffer_attr pb = {.maxlength = (uint32_t)-1, // BUFSIZE * 2, .fragsize = buffer_size}; pa_simple *s = NULL; int error; if (!(s = pa_simple_new(NULL, "cava", PA_STREAM_RECORD, audio->source, "audio for cava", &ss, NULL, &pb, &error))) { sprintf(audio->error_message, __FILE__ ": Could not open pulseaudio source: %s, %s. \ To find a list of your pulseaudio sources run 'pacmd list-sources'\n", audio->source, pa_strerror(error)); audio->terminate = 1; pthread_exit(NULL); return 0; } while (!audio->terminate) { if (pa_simple_read(s, buf, sizeof(buf), &error) < 0) { sprintf(audio->error_message, __FILE__ ": pa_simple_read() failed: %s\n", pa_strerror(error)); audio->terminate = 1; } write_to_cava_input_buffers(audio->input_buffer_size, buf, data); } pa_simple_free(s); pthread_exit(NULL); return 0; } cava-0.10.2/input/pulse.h000066400000000000000000000001741462072613000151470ustar00rootroot00000000000000// header file for pulse, part of cava. #pragma once void *input_pulse(void *data); void getPulseDefaultSink(void *data); cava-0.10.2/input/shmem.c000066400000000000000000000063001462072613000151200ustar00rootroot00000000000000#include "input/shmem.h" #include "input/common.h" #include #include #include #include typedef unsigned int u32_t; typedef short s16_t; int rc; // See issue #375 // Hard-coded in squeezelite's output_vis.c, but // this should be the same as mmap_area->buf_size // if you were to dynamically allocate. #define VIS_BUF_SIZE 16384 typedef struct { pthread_rwlock_t rwlock; u32_t buf_size; u32_t buf_index; bool running; u32_t rate; time_t updated; s16_t buffer[VIS_BUF_SIZE]; } vis_t; // input: SHMEM void *input_shmem(void *data) { struct audio_data *audio = (struct audio_data *)data; vis_t *mmap_area; int fd; /* file descriptor to mmaped area */ int mmap_count = sizeof(vis_t); int buf_frames; int fftw_frames = audio->input_buffer_size / 2; struct timespec req = {.tv_sec = 0, .tv_nsec = 0}; int16_t buf[fftw_frames * 2]; s16_t silence_buffer[fftw_frames * 2]; for (int i = 0; i < fftw_frames * 2; i++) silence_buffer[i] = 0; // printf("input_shmem: source: %s", audio->source); fd = shm_open(audio->source, O_RDWR, 0666); if (fd < 0) { fprintf(stderr, "Could not open source '%s': %s\n", audio->source, strerror(errno)); exit(EXIT_FAILURE); } else { mmap_area = mmap(NULL, sizeof(vis_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if ((intptr_t)mmap_area == -1) { fprintf(stderr, "mmap failed - check if squeezelite is running with visualization enabled\n"); exit(EXIT_FAILURE); } } while (!audio->terminate) { // audio rate may change between songs (e.g. 44.1kHz to 96kHz) audio->rate = mmap_area->rate; buf_frames = mmap_area->buf_size / 2; // reread after the whole buffer has changed req.tv_nsec = (1000000 / mmap_area->rate) * buf_frames; if (mmap_area->running) { // Frames are written by squeezelite to the buffer array starting from // buffer[buf_index + 1], looping around the whole array. // Thus, the starting position only affects the phase spectrum of the // fft, and not the power spectrum, so we can just read in the // whole buffer. for (int i = 0; i < buf_frames / (fftw_frames * 2); i += fftw_frames * 2) { for (int n = 0; n < fftw_frames * 2; n++) { buf[n] = mmap_area->buffer[n + i]; } write_to_cava_input_buffers(fftw_frames * 2, (unsigned char *)buf, audio); } nanosleep(&req, NULL); } else { write_to_cava_input_buffers(fftw_frames * 2, (unsigned char *)silence_buffer, audio); nanosleep(&req, NULL); } } // cleanup if (fd > 0) { if (close(fd) != 0) { fprintf(stderr, "Could not close file descriptor %d: %s", fd, strerror(errno)); } } else { fprintf(stderr, "Wrong file descriptor %d", fd); } if (munmap(mmap_area, mmap_count) != 0) { fprintf(stderr, "Could not munmap() area %p+%d. %s", mmap_area, mmap_count, strerror(errno)); } return 0; } cava-0.10.2/input/shmem.h000066400000000000000000000001261462072613000151250ustar00rootroot00000000000000// header file for shmem, part of cava. #pragma once void *input_shmem(void *data); cava-0.10.2/input/sndio.c000066400000000000000000000056611462072613000151340ustar00rootroot00000000000000#include #include #include #include "input/common.h" #include "input/sndio.h" void *input_sndio(void *data) { static const unsigned int mode = SIO_REC; struct audio_data *audio = data; struct sio_par par; int bytes; size_t buf_size; struct sio_hdl *hdl = NULL; void *buf = NULL; bool is_sio_started = false; bool success = false; if ((hdl = sio_open(audio->source, mode, 0)) == NULL) { fprintf(stderr, __FILE__ ": Could not open sndio source '%s'.\n", audio->source); goto cleanup; } // The recommended approach to negotiate device parameters is to try to set them with preferred // values and check what sndio returns for actual supported values. If CAVA doesn't support the // final values for rate and channels then it will complain later. We test the resulting format // explicitly here. sio_initpar(&par); par.bits = audio->format; par.sig = 1; par.le = 1; par.rchan = audio->channels; par.rate = audio->rate; par.appbufsz = audio->input_buffer_size * SIO_BPS(audio->format) / audio->channels; if (sio_setpar(hdl, &par) == 0) { fprintf(stderr, __FILE__ ": sio_setpar() failed.\n"); goto cleanup; } if (sio_getpar(hdl, &par) == 0) { fprintf(stderr, __FILE__ ": sio_getpar() failed.\n"); goto cleanup; } switch (par.bits) { case 8: case 16: case 24: case 32: audio->format = par.bits; break; default: fprintf(stderr, __FILE__ ": No support for 8, 16, 24 or 32 bits in sndio source '%s'.\n", audio->source); goto cleanup; } audio->channels = par.rchan; audio->rate = par.rate; // Parameters finalized. Signal main thread. signal_threadparams(audio); // Get the correct number of bytes per sample. Sndio uses 32 bits for 24bit, thankfully SIO_BPS // handles this. bytes = SIO_BPS(audio->format); buf_size = audio->input_buffer_size * bytes; if ((buf = malloc(buf_size)) == NULL) { fprintf(stderr, __FILE__ ": malloc() failed: %s\n", strerror(errno)); goto cleanup; } if (sio_start(hdl) == 0) { fprintf(stderr, __FILE__ ": sio_start() failed.\n"); goto cleanup; } is_sio_started = true; while (audio->terminate != 1) { size_t rd; if ((rd = sio_read(hdl, buf, buf_size)) == 0) { fprintf(stderr, __FILE__ ": sio_read() failed.\n"); goto cleanup; } write_to_cava_input_buffers(rd / bytes, buf, audio); } success = true; cleanup: if (is_sio_started && (sio_stop(hdl) == 0)) { fprintf(stderr, __FILE__ ": sio_stop() failed.\n"); success = false; } free(buf); if (hdl != NULL) sio_close(hdl); signal_threadparams(audio); signal_terminate(audio); if (!success) exit(EXIT_FAILURE); return NULL; } cava-0.10.2/input/sndio.h000066400000000000000000000001261462072613000151300ustar00rootroot00000000000000// header file for sndio, part of cava. #pragma once void *input_sndio(void *data); cava-0.10.2/input/winscap.c000066400000000000000000000150271462072613000154610ustar00rootroot00000000000000#define UNICODE #define _UNICODE #include #include #include #include #include #include #include #include #include #include "input/common.h" #define REFTIMES_PER_SEC 10000000 #define REFTIMES_PER_MILLISEC 10000 // the device change funcitonality is disabled until I figure out how // or if to rewrite it to c /* class DeviceChangeNotification : public IMMNotificationClient { volatile ULONG ref; volatile bool &changed; HANDLE hEvent; public: DeviceChangeNotification(volatile bool &changed, HANDLE hEvent) : changed(changed), hEvent(hEvent) {} // This is meant to be allocated on stack, so we don't actually free. STDMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&ref); } STDMETHODIMP_(ULONG) Release() { return InterlockedDecrement(&ref); } STDMETHODIMP QueryInterface(REFIID iid, void **ppv) { if (iid == IID_IUnknown) { AddRef(); *ppv = (IUnknown *)this; } else if (iid == __uuidof(IMMNotificationClient)) { AddRef(); *ppv = (IMMNotificationClient *)this; } else { *ppv = nullptr; return E_NOINTERFACE; } return S_OK; } STDMETHODIMP OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR) { if (flow == eRender && role == eConsole) { changed = true; SetEvent(hEvent); } return S_OK; } STDMETHODIMP OnDeviceAdded(LPCWSTR) { return S_OK; } STDMETHODIMP OnDeviceRemoved(LPCWSTR) { return S_OK; } STDMETHODIMP OnDeviceStateChanged(LPCWSTR, DWORD) { return S_OK; } STDMETHODIMP OnPropertyValueChanged(LPCWSTR, const PROPERTYKEY) { return S_OK; } }; */ struct { HRESULT hr; LPCWSTR error; } error_table[] = { {AUDCLNT_E_UNSUPPORTED_FORMAT, L"Requested sound format unsupported"}, }; void input_winscap(void *data) { static const GUID CLSID_MMDeviceEnumerator = {0xBCDE0395, 0xE52F, 0x467C, 0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E}; static const GUID IID_IMMDeviceEnumerator = {0xA95664D2, 0x9614, 0x4F35, 0xA7, 0x46, 0xDE, 0x8D, 0xB6, 0x36, 0x17, 0xE6}; static const GUID IID_IAudioClient = {0x1CB9AD4C, 0xDBFA, 0x4c32, 0xB1, 0x78, 0xC2, 0xF5, 0x68, 0xA7, 0x03, 0xB2}; static const GUID IID_IAudioCaptureClient = { 0xc8adbd64, 0xe71e, 0x48a0, {0xa4, 0xde, 0x18, 0x5c, 0x39, 0x5c, 0xd3, 0x17}}; struct audio_data *audio = (struct audio_data *)data; pthread_mutex_lock(&audio->lock); CoInitialize(0); WAVEFORMATEX *wfx = NULL; WAVEFORMATEXTENSIBLE *wfx_ext = NULL; IMMDeviceEnumerator *pEnumerator = NULL; HRESULT hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &IID_IMMDeviceEnumerator, (void **)&pEnumerator); HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); /* volatile bool deviceChanged = false; DeviceChangeNotification deviceChangeNotification(deviceChanged, hEvent); pEnumerator->RegisterEndpointNotificationCallback(&deviceChangeNotification); */ while (!audio->terminate) { ResetEvent(hEvent); IMMDevice *pDevice = NULL; pEnumerator->lpVtbl->GetDefaultAudioEndpoint(pEnumerator, eRender, eConsole, &pDevice); IAudioClient *pClient = NULL; pDevice->lpVtbl->Activate(pDevice, &IID_IAudioClient, CLSCTX_ALL, 0, (void **)&pClient); hr = pClient->lpVtbl->GetMixFormat(pClient, &wfx); HRESULT hrInit = pClient->lpVtbl->Initialize(pClient, AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_LOOPBACK, 16 * REFTIMES_PER_MILLISEC, 0, wfx, 0); if (FAILED(hrInit)) { //_com_error err(hrInit); IPropertyStore *pProps = NULL; pDevice->lpVtbl->OpenPropertyStore(pDevice, STGM_READ, &pProps); PROPVARIANT varName; PropVariantInit(&varName); pProps->lpVtbl->GetValue(pProps, &PKEY_Device_FriendlyName, &varName); fwprintf(stderr, L"Failed to open: %s\n", varName.pwszVal); PropVariantClear(&varName); WaitForSingleObject(hEvent, INFINITE); continue; } UINT32 bufferFrameCount; pClient->lpVtbl->GetBufferSize(pClient, &bufferFrameCount); IAudioCaptureClient *pCapture = NULL; pClient->lpVtbl->GetService(pClient, &IID_IAudioCaptureClient, (void **)&pCapture); WAVEFORMATEX format = *wfx; DWORD dwDelay = (DWORD)(((double)REFTIMES_PER_SEC * bufferFrameCount / format.nSamplesPerSec) / REFTIMES_PER_MILLISEC / 2); LPBYTE pSilence = (LPBYTE)malloc(bufferFrameCount * format.nBlockAlign); ZeroMemory(pSilence, bufferFrameCount * format.nBlockAlign); pClient->lpVtbl->Start(pClient); audio->channels = format.nChannels; audio->rate = format.nSamplesPerSec; audio->format = format.wBitsPerSample; if (format.wBitsPerSample == 32) audio->IEEE_FLOAT = 1; pthread_mutex_unlock(&audio->lock); // deviceChanged while (!audio->terminate) { Sleep(dwDelay); UINT32 packetLength; HRESULT hrNext = pCapture->lpVtbl->GetNextPacketSize(pCapture, &packetLength); if (hrNext == AUDCLNT_E_DEVICE_INVALIDATED) { // while (!deviceChanged) // ; break; } else { // ensure(hrNext); ; } while (packetLength) { LPBYTE pData; UINT32 numFramesAvailable; DWORD flags; pCapture->lpVtbl->GetBuffer(pCapture, &pData, &numFramesAvailable, &flags, 0, 0); if (flags & AUDCLNT_BUFFERFLAGS_SILENT) pData = pSilence; write_to_cava_input_buffers(numFramesAvailable * format.nChannels, (unsigned char *)pData, audio); pCapture->lpVtbl->ReleaseBuffer(pCapture, numFramesAvailable); pCapture->lpVtbl->GetNextPacketSize(pCapture, &packetLength); } } // deviceChanged = false; pClient->lpVtbl->Stop(pClient); free(pSilence); } } cava-0.10.2/input/winscap.h000066400000000000000000000002541462072613000154620ustar00rootroot00000000000000// header files for winscap, part of cava #ifdef __cplusplus extern "C" { #endif #pragma once void *input_winscap(void *data); #pragma once #ifdef __cplusplus } #endif cava-0.10.2/output/000077500000000000000000000000001462072613000140455ustar00rootroot00000000000000cava-0.10.2/output/noritake.c000066400000000000000000000020461462072613000160270ustar00rootroot00000000000000#include "../config.h" #include #include #include #include int print_ntk_out(int bars_count, int fd, int bit_format, int bar_width, int bar_spacing, int bar_height, int const f[]) { int8_t buf_8; int8_t val1; uint64_t bits; int8_t j; int8_t k; // Custom Noritake VFD bitmap for 3000-series for (int i = 0; i < bars_count; i++) { int f_limited = f[i]; if (f_limited > (pow(2, bit_format) - 1)) f_limited = pow(2, bit_format) - 1; val1 = f_limited >> (bar_height / 8 - 1); // Will not work above 32 for now bits = pow(2, val1) - 1; for (k = 0; k < bar_width; k++) { for (j = 0; j < bar_height / 8; j++) { buf_8 = bits >> (8 * (bar_height / 8 - 1 - j)) & 0xff; write(fd, &buf_8, sizeof(int8_t)); } } buf_8 = 0; for (j = 0; j < bar_height / 8 * bar_spacing; j++) { write(fd, &buf_8, sizeof(int8_t)); } } return 0; } cava-0.10.2/output/noritake.h000066400000000000000000000002141462072613000160270ustar00rootroot00000000000000int print_ntk_out(int bars_count, int fd, int bit_format, int bar_width, int bar_spacing, int bar_height, int const f[]); cava-0.10.2/output/raw.c000066400000000000000000000027271462072613000150120ustar00rootroot00000000000000#include #include #include #include int print_raw_out(int bars_count, int fd, int is_binary, int bit_format, int ascii_range, char bar_delim, char frame_delim, int const f[]) { int16_t buf_16; int8_t buf_8; if (is_binary) { for (int i = 0; i < bars_count; i++) { int f_limited = f[i]; if (f_limited > (pow(2, bit_format) - 1)) f_limited = pow(2, bit_format) - 1; switch (bit_format) { case 16: buf_16 = f_limited; write(fd, &buf_16, sizeof(int16_t)); break; case 8: buf_8 = f_limited; write(fd, &buf_8, sizeof(int8_t)); break; } } } else { // ascii for (int i = 0; i < bars_count; i++) { int f_ranged = f[i]; if (f_ranged > ascii_range) f_ranged = ascii_range; // finding size of number-string in byte int bar_height_size = 2; // a number + \0 if (f_ranged != 0) bar_height_size += floor(log10(f_ranged)); char bar_height[bar_height_size]; snprintf(bar_height, bar_height_size, "%d", f_ranged); write(fd, bar_height, bar_height_size - 1); write(fd, &bar_delim, sizeof(bar_delim)); } write(fd, &frame_delim, sizeof(frame_delim)); } return 0; } cava-0.10.2/output/raw.h000066400000000000000000000002361462072613000150100ustar00rootroot00000000000000int print_raw_out(int bars_count, int fd, int is_binary, int bit_format, int ascii_range, char bar_delim, char frame_delim, int const f[]); cava-0.10.2/output/sdl_cava.c000066400000000000000000000154661462072613000160010ustar00rootroot00000000000000#ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS 1 #include #else #include #endif #include "output/sdl_cava.h" #include #include #include "util.h" #define MAX_GRADIENT_COLOR_DEFS 8 SDL_Window *gWindow = NULL; SDL_Renderer *gRenderer = NULL; SDL_Event e; struct colors { uint16_t RGB[3]; }; struct colors *gradient_colors_sdl; struct colors fg_color = {0}; struct colors bg_color = {0}; static void parse_color(char *color_string, struct colors *color) { if (color_string[0] == '#') { sscanf(++color_string, "%02hx%02hx%02hx", &color->RGB[0], &color->RGB[1], &color->RGB[2]); } } void init_sdl_window(int width, int height, int x, int y, int full_screen) { if (x == -1) x = SDL_WINDOWPOS_UNDEFINED; if (y == -1) y = SDL_WINDOWPOS_UNDEFINED; if (SDL_Init(SDL_INIT_VIDEO) < 0) { printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError()); } else { Uint32 sdl_flags = SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; if (full_screen == 1) sdl_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; gWindow = SDL_CreateWindow("cava", x, y, width, height, sdl_flags); if (gWindow == NULL) { printf("Window could not be created! SDL_Error: %s\n", SDL_GetError()); } else { gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED); if (gRenderer == NULL) { printf("Renderer could not be created! SDL Error: %s\n", SDL_GetError()); } } } } void init_sdl_surface(int *w, int *h, char *const fg_color_string, char *const bg_color_string, int gradient, int gradient_count, char **gradient_color_strings) { SDL_GetWindowSize(gWindow, w, h); parse_color(bg_color_string, &bg_color); SDL_SetRenderDrawColor(gRenderer, fg_color.RGB[0], fg_color.RGB[1], fg_color.RGB[2], 0xFF); SDL_RenderClear(gRenderer); parse_color(fg_color_string, &fg_color); SDL_SetRenderDrawColor(gRenderer, fg_color.RGB[0], fg_color.RGB[1], fg_color.RGB[2], 0xFF); if (gradient) { struct colors gradient_color_defs[MAX_GRADIENT_COLOR_DEFS]; for (int i = 0; i < gradient_count; i++) { parse_color(gradient_color_strings[i], &gradient_color_defs[i]); } int lines = *h; gradient_colors_sdl = (struct colors *)malloc((lines * 2) * sizeof(struct colors)); int individual_size = lines / (gradient_count - 1); float rest = lines / (float)(gradient_count - 1) - individual_size; float rest_total = 0; int gradient_lines = 0; for (int i = 0; i < gradient_count - 1; i++) { individual_size = lines / (gradient_count - 1); if (rest_total > 1.0) { individual_size++; rest_total = rest_total - 1.0; } for (int n = 0; n < individual_size; n++) { for (int c = 0; c < 3; c++) { float next_color = gradient_color_defs[i + 1].RGB[c] - gradient_color_defs[i].RGB[c]; next_color *= n / (float)individual_size; gradient_colors_sdl[gradient_lines].RGB[c] = gradient_color_defs[i].RGB[c] + next_color; } gradient_lines++; } rest_total = rest_total + rest; } gradient_colors_sdl[lines - 1] = gradient_color_defs[gradient_count - 1]; } } int draw_sdl(int bars_count, int bar_width, int bar_spacing, int remainder, int height, const int bars[], int previous_frame[], int frame_time, enum orientation orientation, int gradient) { bool update = false; int rc = 0; SDL_Rect fillRect; for (int bar = 0; bar < bars_count; bar++) { if (bars[bar] != previous_frame[bar]) { update = true; break; } } if (update) { SDL_SetRenderDrawColor(gRenderer, bg_color.RGB[0], bg_color.RGB[1], bg_color.RGB[2], 0xFF); SDL_RenderClear(gRenderer); if (gradient) { for (int line = 0; line < height; line++) { SDL_SetRenderDrawColor(gRenderer, gradient_colors_sdl[line].RGB[0], gradient_colors_sdl[line].RGB[1], gradient_colors_sdl[line].RGB[2], 0xFF); for (int bar = 0; bar < bars_count; bar++) { if (bars[bar] > line) { int x1 = bar * (bar_width + bar_spacing); if (bar == 0) x1 = 0; int x2 = x1 + bar_width; SDL_RenderDrawLine(gRenderer, x1, height - line, x2, height - line); } } } } else { for (int bar = 0; bar < bars_count; bar++) { switch (orientation) { case ORIENT_LEFT: fillRect.x = 0; fillRect.y = bar * (bar_width + bar_spacing) + remainder; fillRect.w = bars[bar]; fillRect.h = bar_width; break; case ORIENT_RIGHT: fillRect.x = height - bars[bar]; fillRect.y = bar * (bar_width + bar_spacing) + remainder; fillRect.w = bars[bar]; fillRect.h = bar_width; break; case ORIENT_TOP: fillRect.x = bar * (bar_width + bar_spacing) + remainder; fillRect.y = 0; fillRect.w = bar_width; fillRect.h = bars[bar]; break; default: fillRect.x = bar * (bar_width + bar_spacing) + remainder; fillRect.y = height - bars[bar]; fillRect.w = bar_width; fillRect.h = bars[bar]; break; } SDL_SetRenderDrawColor(gRenderer, fg_color.RGB[0], fg_color.RGB[1], fg_color.RGB[2], 0xFF); SDL_RenderFillRect(gRenderer, &fillRect); } } SDL_RenderPresent(gRenderer); } SDL_Delay(frame_time); while (SDL_PollEvent(&e)) { if (e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { rc = -1; if (gradient) { free(gradient_colors_sdl); } } if (e.type == SDL_KEYDOWN) { if (e.key.keysym.sym == SDLK_q || e.key.keysym.sym == SDLK_ESCAPE) rc = -2; } if (e.type == SDL_QUIT) rc = -2; } return rc; } // general: cleanup void cleanup_sdl(void) { SDL_DestroyWindow(gWindow); SDL_Quit(); } cava-0.10.2/output/sdl_cava.h000066400000000000000000000010531462072613000157710ustar00rootroot00000000000000#include "../config.h" void init_sdl_window(int width, int height, int x, int y, int full_screen); void init_sdl_surface(int *width, int *height, char *const fg_color_string, char *const bg_color_string, int gradient, int gradient_count, char **gradient_color_strings); int draw_sdl(int bars_count, int bar_width, int bar_spacing, int remainder, int height, const int bars[], int previous_frame[], int frame_timer, enum orientation orientation, int gradient); void cleanup_sdl(void); cava-0.10.2/output/sdl_glsl.c000066400000000000000000000241731462072613000160230ustar00rootroot00000000000000#define GL_GLEXT_PROTOTYPES 0 #ifdef _MSC_VER #include #include #else #include #include #endif #include "output/sdl_glsl.h" #include #include #include "util.h" SDL_Window *glWindow = NULL; GLuint shading_program; GLint uniform_bars; GLint uniform_bars_count; SDL_GLContext *glContext = NULL; struct colors { uint16_t R; uint16_t G; uint16_t B; }; static void parse_color(char *color_string, struct colors *color) { if (color_string[0] == '#') { sscanf(++color_string, "%02hx%02hx%02hx", &color->R, &color->G, &color->B); } } GLuint get_shader(GLenum, const char *); GLuint custom_shaders(const char *, const char *); const char *read_file(const char *); GLuint compile_shader(GLenum type, const char **); GLuint program_check(GLuint); void init_sdl_glsl_window(int width, int height, int x, int y, int full_screen, char *const vertex_shader, char *const fragmnet_shader) { if (x == -1) x = SDL_WINDOWPOS_UNDEFINED; if (y == -1) y = SDL_WINDOWPOS_UNDEFINED; if (SDL_Init(SDL_INIT_VIDEO) < 0) { fprintf(stderr, "SDL could not initialize! SDL_Error: %s\n", SDL_GetError()); exit(1); } #ifdef __APPLE__ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); #endif Uint32 sdl_flags = SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; if (full_screen == 1) sdl_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; glWindow = SDL_CreateWindow("cava", x, y, width, height, sdl_flags); if (glWindow == NULL) { fprintf(stderr, "Window could not be created! SDL_Error: %s\n", SDL_GetError()); exit(1); } SDL_GLContext glContext = SDL_GL_CreateContext(glWindow); if (glContext == NULL) { fprintf(stderr, "GLContext could not be created! SDL Error: %s\n", SDL_GetError()); exit(1); } #ifdef _MSC_VER // Initialize GLEW glewExperimental = GL_TRUE; GLenum glewError = glewInit(); if (glewError != GLEW_OK) { printf(stderr, "Error initializing GLEW! %s\n", glewGetErrorString(glewError)); exit(1); } #endif // Use Vsync if (SDL_GL_SetSwapInterval(1) < 0) { printf("Warning: Unable to set VSync! SDL Error: %s\n", SDL_GetError()); } shading_program = custom_shaders(vertex_shader, fragmnet_shader); glReleaseShaderCompiler(); if (shading_program == 0) { fprintf(stderr, "could not compile shaders: %s\n", SDL_GetError()); exit(1); } glUseProgram(shading_program); GLint gVertexPos2DLocation = -1; gVertexPos2DLocation = glGetAttribLocation(shading_program, "vertexPosition_modelspace"); if (gVertexPos2DLocation == -1) { fprintf(stderr, "could not find vertex position shader variable!\n"); exit(1); } glClearColor(0.f, 0.f, 0.f, 1.f); GLfloat vertexData[] = {-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f}; GLuint indexData[] = {0, 1, 2, 3}; GLuint gVBO = 0; glGenBuffers(1, &gVBO); glBindBuffer(GL_ARRAY_BUFFER, gVBO); glBufferData(GL_ARRAY_BUFFER, 2 * 4 * sizeof(GLfloat), vertexData, GL_STATIC_DRAW); GLuint gIBO = 0; glGenBuffers(1, &gIBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gIBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4 * sizeof(GLuint), indexData, GL_STATIC_DRAW); GLuint gVAO = 0; glGenVertexArrays(1, &gVAO); glBindVertexArray(gVAO); glEnableVertexAttribArray(gVertexPos2DLocation); glBindBuffer(GL_ARRAY_BUFFER, gVBO); glVertexAttribPointer(gVertexPos2DLocation, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), NULL); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gIBO); uniform_bars = glGetUniformLocation(shading_program, "bars"); uniform_bars_count = glGetUniformLocation(shading_program, "bars_count"); int error = glGetError(); if (error != 0) { fprintf(stderr, "glError on init: %d\n", error); exit(1); } } void init_sdl_glsl_surface(int *w, int *h, char *const fg_color_string, char *const bg_color_string, int bar_width, int bar_spacing, int gradient, int gradient_count, char **gradient_color_strings) { struct colors color = {0}; GLint uniform_bg_col; uniform_bg_col = glGetUniformLocation(shading_program, "bg_color"); parse_color(bg_color_string, &color); glUniform3f(uniform_bg_col, (float)color.R / 255.0, (float)color.G / 255.0, (float)color.B / 255.0); GLint uniform_fg_col; uniform_fg_col = glGetUniformLocation(shading_program, "fg_color"); parse_color(fg_color_string, &color); glUniform3f(uniform_fg_col, (float)color.R / 255.0, (float)color.G / 255.0, (float)color.B / 255.0); GLint uniform_res; uniform_res = glGetUniformLocation(shading_program, "u_resolution"); SDL_GetWindowSize(glWindow, w, h); glUniform3f(uniform_res, (float)*w, (float)*h, 0.0f); GLint uniform_bar_width; uniform_bar_width = glGetUniformLocation(shading_program, "bar_width"); glUniform1i(uniform_bar_width, bar_width); GLint uniform_bar_spacing; uniform_bar_spacing = glGetUniformLocation(shading_program, "bar_spacing"); glUniform1i(uniform_bar_spacing, bar_spacing); GLint uniform_gradient_count; uniform_gradient_count = glGetUniformLocation(shading_program, "gradient_count"); if (gradient == 0) gradient_count = 0; glUniform1i(uniform_gradient_count, gradient_count); GLint uniform_gradient_colors; uniform_gradient_colors = glGetUniformLocation(shading_program, "gradient_colors"); float gradient_colors[8][3]; for (int i = 0; i < gradient_count; i++) { parse_color(gradient_color_strings[i], &color); gradient_colors[i][0] = (float)color.R / 255.0; gradient_colors[i][1] = (float)color.G / 255.0; gradient_colors[i][2] = (float)color.B / 255.0; } glUniform3fv(uniform_gradient_colors, 8, (const GLfloat *)gradient_colors); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_INT, NULL); SDL_GL_SwapWindow(glWindow); } int draw_sdl_glsl(int bars_count, const float bars[], int frame_time, int re_paint, int continuous_rendering) { int rc = 0; SDL_Event event; if (re_paint || continuous_rendering) { glUniform1fv(uniform_bars, bars_count, bars); glUniform1i(uniform_bars_count, bars_count); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_INT, NULL); SDL_GL_SwapWindow(glWindow); } SDL_Delay(frame_time); SDL_PollEvent(&event); if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { glViewport(0, 0, event.window.data1, event.window.data2); rc = -1; } if (event.type == SDL_KEYDOWN) { if (event.key.keysym.sym == SDLK_q || event.key.keysym.sym == SDLK_ESCAPE) rc = -2; } if (event.type == SDL_QUIT) rc = -2; return rc; } // general: cleanup void cleanup_sdl_glsl(void) { SDL_GL_DeleteContext(glContext); SDL_DestroyWindow(glWindow); SDL_Quit(); } const char *read_file(const char *filename) { long length = 0; char *result = NULL; FILE *file = fopen(filename, "r"); if (file) { int status = fseek(file, 0, SEEK_END); if (status != 0) { fclose(file); return NULL; } length = ftell(file); status = fseek(file, 0, SEEK_SET); if (status != 0) { fclose(file); return NULL; } result = malloc((length + 1) * sizeof(char)); if (result) { size_t actual_length = fread(result, sizeof(char), length, file); result[actual_length++] = '\0'; } fclose(file); return result; } fprintf(stderr, "Couldn't open shader file %s", filename); exit(1); return NULL; } GLuint custom_shaders(const char *vsPath, const char *fsPath) { GLuint vertexShader; GLuint fragmentShader; vertexShader = get_shader(GL_VERTEX_SHADER, vsPath); fragmentShader = get_shader(GL_FRAGMENT_SHADER, fsPath); shading_program = glCreateProgram(); glAttachShader(shading_program, vertexShader); glAttachShader(shading_program, fragmentShader); glLinkProgram(shading_program); // Error Checking GLuint status; status = program_check(shading_program); if (status == GL_FALSE) return 0; return shading_program; } GLuint get_shader(GLenum eShaderType, const char *filename) { const char *shaderSource = read_file(filename); GLuint shader = compile_shader(eShaderType, &shaderSource); free((char *)shaderSource); return shader; } GLuint compile_shader(GLenum type, const char **sources) { GLuint shader; GLint success, len; GLsizei srclens[1]; srclens[0] = (GLsizei)strlen(sources[0]); shader = glCreateShader(type); glShaderSource(shader, 1, sources, srclens); glCompileShader(shader); glGetShaderiv(shader, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len); if (len > 1) { char *log; log = malloc(len); glGetShaderInfoLog(shader, len, NULL, log); fprintf(stderr, "%s\n\n", log); free(log); } fprintf(stderr, "Error compiling shader.\n"); exit(1); } return shader; } GLuint program_check(GLuint program) { // Error Checking GLint status; glValidateProgram(program); glGetProgramiv(program, GL_LINK_STATUS, &status); if (!status) { GLint len; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &len); if (len > 1) { char *log; log = malloc(len); glGetProgramInfoLog(program, len, &len, log); fprintf(stderr, "%s\n\n", log); free(log); } SDL_Log("Error linking shader default program.\n"); return GL_FALSE; } return GL_TRUE; }cava-0.10.2/output/sdl_glsl.h000066400000000000000000000011401462072613000160150ustar00rootroot00000000000000#include "../config.h" void init_sdl_glsl_window(int width, int height, int x, int y, int full_screen, char *const vertex_shader, char *const fragment_shader); void init_sdl_glsl_surface(int *width, int *height, char *const fg_color_string, char *const bg_color_string, int bar_width, int bar_spacing, int gradient, int gradient_count, char **gradient_color_strings); int draw_sdl_glsl(int bars_count, const float bars[], int frame_timer, int re_paint, int continuous_rendering); void cleanup_sdl_glsl(void); cava-0.10.2/output/shaders/000077500000000000000000000000001462072613000154765ustar00rootroot00000000000000cava-0.10.2/output/shaders/bar_spectrum.frag000066400000000000000000000044661462072613000210370ustar00rootroot00000000000000#version 330 in vec2 fragCoord; out vec4 fragColor; // bar values. defaults to left channels first (low to high), then right (high to low). uniform float bars[512]; uniform int bars_count; // number of bars (left + right) (configurable) uniform int bar_width; // bar width (configurable), not used here uniform int bar_spacing; // space bewteen bars (configurable) uniform vec3 u_resolution; // window resolution //colors, configurable in cava config file (r,g,b) (0.0 - 1.0) uniform vec3 bg_color; // background color uniform vec3 fg_color; // foreground color uniform int gradient_count; uniform vec3 gradient_colors[8]; // gradient colors vec3 normalize_C(float y,vec3 col_1, vec3 col_2, float y_min, float y_max) { //create color based on fraction of this color and next color float yr = (y - y_min) / (y_max - y_min); return col_1 * (1.0 - yr) + col_2 * yr; } void main() { // find which bar to use based on where we are on the x axis float x = u_resolution.x * fragCoord.x; int bar = int(bars_count * fragCoord.x); //calculate a bar size float bar_size = u_resolution.x / bars_count; //the y coordinate and bar values are the same float y = bars[bar]; // make sure there is a thin line at bottom if (y * u_resolution.y < 1.0) { y = 1.0 / u_resolution.y; } //draw the bar up to current height if (y > fragCoord.y) { //make some space between bars basen on settings if (x > (bar + 1) * (bar_size) - bar_spacing) { fragColor = vec4(bg_color,1.0); } else { if (gradient_count == 0) { fragColor = vec4(fg_color,1.0); } else { //find which color in the configured gradient we are at int color = int((gradient_count - 1) * fragCoord.y); //find where on y this and next color is supposed to be float y_min = color / (gradient_count - 1.0); float y_max = (color + 1.0) / (gradient_count - 1.0); //make color fragColor = vec4(normalize_C(fragCoord.y, gradient_colors[color], gradient_colors[color + 1], y_min, y_max), 1.0); } } } else { fragColor = vec4(bg_color,1.0); } }cava-0.10.2/output/shaders/northern_lights.frag000066400000000000000000000017611462072613000215550ustar00rootroot00000000000000#version 330 in vec2 fragCoord; out vec4 fragColor; // bar values. defaults to left channels first (low to high), then right (high to low). uniform float bars[512]; uniform int bars_count; // number of bars (left + right) (configurable) uniform vec3 u_resolution; // window resolution, not used here //colors, configurable in cava config file uniform vec3 bg_color; // background color(r,g,b) (0.0 - 1.0), not used here uniform vec3 fg_color; // foreground color, not used here void main() { // find which bar to use based on where we are on the x axis int bar = int(bars_count * fragCoord.x); float bar_y = 1.0 - abs((fragCoord.y - 0.5)) * 2.0; float y = (bars[bar]) * bar_y; float bar_x = (fragCoord.x - float(bar) / float(bars_count)) * bars_count; float bar_r = 1.0 - abs((bar_x - 0.5)) * 2; bar_r = bar_r * bar_r * 2; // set color fragColor.r = fg_color.x * y * bar_r; fragColor.g = fg_color.y * y * bar_r; fragColor.b = fg_color.z * y * bar_r; } cava-0.10.2/output/shaders/pass_through.vert000066400000000000000000000005361462072613000211120ustar00rootroot00000000000000#version 330 // Input vertex data, different for all executions of this shader. layout(location = 0) in vec3 vertexPosition_modelspace; // Output data ; will be interpolated for each fragment. out vec2 fragCoord; void main() { gl_Position = vec4(vertexPosition_modelspace,1); fragCoord = (vertexPosition_modelspace.xy+vec2(1,1))/2.0; } cava-0.10.2/output/terminal_bcircle.c000066400000000000000000000036621462072613000175160ustar00rootroot00000000000000#include "output/terminal_bcircle.h" #include #include #include #include #include #include #ifndef M_PI #define M_PI 3.141592 #endif #define DEGTORAD(deg) (deg * (180.0f / M_PI)) #define DOT 0x2588 int init_terminal_bcircle(int col, int bgcol) { initscr(); curs_set(0); timeout(0); noecho(); start_color(); use_default_colors(); init_pair(1, col, bgcol); if (bgcol != -1) bkgd(COLOR_PAIR(1)); attron(COLOR_PAIR(1)); // attron(A_BOLD); return 0; } void get_terminal_dim_bcircle(int *w, int *h) { getmaxyx(stdscr, *h, *w); clear(); // clearing in case of resieze } int draw_terminal_bcircle(int tty, int h, int w, int f[]) { const wchar_t *bars[] = {L"\u2581", L"\u2582", L"\u2583", L"\u2584", L"\u2585", L"\u2586", L"\u2587", L"\u2588"}; // output: check if terminal has been resized if (!tty) { if (LINES != h || COLS != w) { return -1; } } float deg, width, height; int y, x; /* Convert to int */ width = f[1] / 10; height = f[1] / 15; int oy, ox; oy = LINES / 2 - height / 2; ox = COLS / 2 - width / 2; for (x = 0; x < COLS; x++) { for (y = 0; y < LINES; y++) { mvaddstr(y, x, " "); } } /* Draw circle */ for (deg = 0; deg < 360.0f; deg += 1.0f) { x = ox + width + (int)(width * cos(DEGTORAD(deg))); y = oy + height + (int)(height * sin(DEGTORAD(deg))); mvaddwstr(y, x, bars[7]); } refresh(); return 0; } // general: cleanup void cleanup_terminal_bcircle(void) { echo(); #ifdef __FreeBSD__ system("vidcontrol -f >/dev/null 2>&1"); #else system("setfont >/dev/null 2>&1"); system("setfont /usr/share/consolefonts/Lat2-Fixed16.psf.gz >/dev/null 2>&1"); system("setterm -blank 10"); #endif endwin(); system("clear"); } cava-0.10.2/output/terminal_bcircle.h000066400000000000000000000003261462072613000175150ustar00rootroot00000000000000#pragma once int init_terminal_bcircle(int col, int bgcol); void get_terminal_dim_bcircle(int *w, int *h); int draw_terminal_bcircle(int virt, int height, int width, int f[]); void cleanup_terminal_bcircle(void); cava-0.10.2/output/terminal_ncurses.c000066400000000000000000000271101462072613000175670ustar00rootroot00000000000000#include "output/terminal_ncurses.h" #include #include #include #include #include "util.h" int gradient_size = 64; struct colors { NCURSES_COLOR_T color; NCURSES_COLOR_T R; NCURSES_COLOR_T G; NCURSES_COLOR_T B; }; #define COLOR_REDEFINITION -2 #define MAX_COLOR_REDEFINITION 256 const int num_bar_heights = 8; const wchar_t *bar_heights_bottom[] = {L"\u2581", L"\u2582", L"\u2583", L"\u2584", L"\u2585", L"\u2586", L"\u2587", L"\u2588"}; const wchar_t *bar_heights_top[] = {L"\u2594", L"\U0001FB82", L"\U0001FB83", L"\u2580", L"\U0001FB84", L"\U0001FB85", L"\U0001FB86", L"\u2588"}; const wchar_t *bar_heights_left[] = {L"\u258F", L"\u258E", L"\u258D", L"\u258C", L"\u258B", L"\u258A", L"\u2589", L"\u2588"}; const wchar_t *bar_heights_right[] = {L"\u2595", L"\U0001FB87", L"\U0001FB88", L"\u2590", L"\U0001FB89", L"\U0001FB8A", L"\U0001FB8B", L"\u2588"}; const wchar_t **bar_heights[] = {bar_heights_bottom, bar_heights_top, bar_heights_left, bar_heights_right}; // static struct colors the_color_redefinitions[MAX_COLOR_REDEFINITION]; static void parse_color(char *color_string, struct colors *color) { if (color_string[0] == '#') { if (!can_change_color()) { cleanup_terminal_ncurses(); fprintf(stderr, "Your terminal can not change color definitions, " "please use one of the predefined colors.\n"); exit(EXIT_FAILURE); } color->color = COLOR_REDEFINITION; sscanf(++color_string, "%02hx%02hx%02hx", &color->R, &color->G, &color->B); } } /* static void remember_color_definition(NCURSES_COLOR_T color_number) { int index = color_number - 1; // array starts from zero and colors - not if(the_color_redefinitions[index].color == 0) { the_color_redefinitions[index].color = color_number; color_content(color_number, &the_color_redefinitions[index].R, &the_color_redefinitions[index].G, &the_color_redefinitions[index].B); } } */ // ncurses use color range [0, 1000], and we - [0, 255] #define CURSES_COLOR_COEFFICIENT(X) ((X)*1000.0 / 0xFF + 0.5) #define COLORS_STRUCT_NORMALIZE(X) \ CURSES_COLOR_COEFFICIENT(X.R), CURSES_COLOR_COEFFICIENT(X.G), CURSES_COLOR_COEFFICIENT(X.B) static NCURSES_COLOR_T change_color_definition(NCURSES_COLOR_T color_number, char *const color_string, NCURSES_COLOR_T predef_color) { struct colors color = {0}; parse_color(color_string, &color); NCURSES_COLOR_T return_color_number = predef_color; if (color.color == COLOR_REDEFINITION) { // remember_color_definition(color_number); init_color(color_number, COLORS_STRUCT_NORMALIZE(color)); return_color_number = color_number; } return return_color_number; } static void get_screen_coords(int line, int col, int max_value, enum orientation orientation, int *x, int *y) { switch (orientation) { case ORIENT_LEFT: *x = line; *y = col; break; case ORIENT_RIGHT: *x = max_value - line; *y = col; break; case ORIENT_TOP: *x = col; *y = line; break; default: *x = col; *y = max_value - line; break; } } void init_terminal_ncurses(char *const fg_color_string, char *const bg_color_string, int predef_fg_color, int predef_bg_color, int gradient, int gradient_count, char **gradient_colors, int *width, int *lines) { initscr(); curs_set(0); timeout(0); noecho(); start_color(); use_default_colors(); getmaxyx(stdscr, *lines, *width); clear(); NCURSES_COLOR_T color_pair_number = 16; NCURSES_COLOR_T bg_color_number; bg_color_number = change_color_definition(0, bg_color_string, predef_bg_color); if (!gradient) { NCURSES_COLOR_T fg_color_number; fg_color_number = change_color_definition(1, fg_color_string, predef_fg_color); init_pair(color_pair_number, fg_color_number, bg_color_number); } else if (gradient) { // 0 -> col1, 1-> col1<=>col2, 2 -> col2 and so on short unsigned int rgb[2 * gradient_count - 1][3]; char next_color[14]; gradient_size = *lines; if (gradient_size > COLORS) gradient_size = COLORS - 1; if (gradient_size > COLOR_PAIRS) gradient_size = COLOR_PAIRS - 1; if (gradient_size > MAX_COLOR_REDEFINITION) gradient_size = MAX_COLOR_REDEFINITION - 1; for (int i = 0; i < gradient_count; i++) { int col = (i + 1) * 2 - 2; sscanf(gradient_colors[i] + 1, "%02hx%02hx%02hx", &rgb[col][0], &rgb[col][1], &rgb[col][2]); } // sscanf(gradient_color_1 + 1, "%02hx%02hx%02hx", &rgb[0][0], &rgb[0][1], &rgb[0][2]); // sscanf(gradient_color_2 + 1, "%02hx%02hx%02hx", &rgb[1][0], &rgb[1][1], &rgb[1][2]); int individual_size = gradient_size / (gradient_count - 1); for (int i = 0; i < gradient_count - 1; i++) { int col = (i + 1) * 2 - 2; if (i == gradient_count - 1) col = 2 * (gradient_count - 1) - 2; for (int j = 0; j < individual_size; j++) { for (int k = 0; k < 3; k++) { rgb[col + 1][k] = rgb[col][k] + (rgb[col + 2][k] - rgb[col][k]) * (j / (individual_size * 0.85)); if (rgb[col + 1][k] > 255) rgb[col][k] = 0; if (j > individual_size * 0.85) rgb[col + 1][k] = rgb[col + 2][k]; } sprintf(next_color, "#%02x%02x%02x", rgb[col + 1][0], rgb[col + 1][1], rgb[col + 1][2]); change_color_definition(color_pair_number, next_color, color_pair_number); init_pair(color_pair_number, color_pair_number, bg_color_number); color_pair_number++; } } int left = individual_size * (gradient_count - 1); int col = 2 * (gradient_count)-2; while (left < gradient_size) { sprintf(next_color, "#%02x%02x%02x", rgb[col][0], rgb[col][1], rgb[col][2]); change_color_definition(color_pair_number, next_color, color_pair_number); init_pair(color_pair_number, color_pair_number, bg_color_number); color_pair_number++; left++; } color_pair_number--; } attron(COLOR_PAIR(color_pair_number)); if (bg_color_number != -1) bkgd(COLOR_PAIR(color_pair_number)); for (int y = 0; y < *lines; y++) { for (int x = 0; x < *width; x++) { mvaddch(y, x, ' '); } } refresh(); } void change_colors(int cur_height, int tot_height) { tot_height /= gradient_size; if (tot_height < 1) tot_height = 1; cur_height /= tot_height; if (cur_height > gradient_size - 1) cur_height = gradient_size - 1; attron(COLOR_PAIR(cur_height + 16)); } void get_terminal_dim_ncurses(int *width, int *height) { getmaxyx(stdscr, *height, *width); gradient_size = *height; clear(); // clearing in case of resieze } #define TERMINAL_RESIZED -1 int draw_terminal_ncurses(int is_tty, int dimension_value, int dimension_bar, int bars_count, int bar_width, int bar_spacing, int rest, const int bars[], int previous_frame[], int gradient, int x_axis_info, enum orientation orientation) { const int max_value = dimension_value - 1; // output: check if terminal has been resized if (!is_tty) { if (x_axis_info) dimension_value++; int terminal_width, terminal_height; if (orientation == ORIENT_LEFT || orientation == ORIENT_RIGHT) { terminal_width = dimension_value; terminal_height = dimension_bar; } else { terminal_width = dimension_bar; terminal_height = dimension_value; } if (LINES != terminal_height || COLS != terminal_width) { return TERMINAL_RESIZED; if (x_axis_info) dimension_value--; } } // Compute how much of the screen we possibly need to update ahead-of-time. int max_update_value = 0; for (int bar = 0; bar < bars_count; bar++) { max_update_value = max(max_update_value, max(bars[bar], previous_frame[bar])); } max_update_value = (max_update_value + num_bar_heights) / num_bar_heights; for (int line = 0; line < max_update_value; line++) { if (gradient) { change_colors(line, max_value); } for (int bar = 0; bar < bars_count; bar++) { if (bars[bar] == previous_frame[bar]) { continue; } int cur_col = bar * bar_width + bar * bar_spacing + rest; int bar_line_height = bars[bar] / num_bar_heights; int previous_bar_line_heigh = previous_frame[bar] / num_bar_heights; if (bars[bar] >= line * num_bar_heights + 1) { int bar_step; if (bar_line_height == line) { // The "cap" of the bar occurs at this [line]. bar_step = bars[bar] % num_bar_heights - 1; } else if (previous_bar_line_heigh <= line) { // The bar is full at this line and wasn't before. bar_step = num_bar_heights - 1; } else { // No update necessary since last frame. continue; } for (int col = cur_col, i = 0; i < bar_width; i++, col++) { int x, y; get_screen_coords(line, col, max_value, orientation, &x, &y); if (is_tty) { mvaddch(y, x, 0x41 + bar_step); } else { mvaddwstr(y, x, bar_heights[orientation][bar_step]); } } } else if (previous_bar_line_heigh >= line) { // This bar was taller during the last frame than during this frame, so // clear the excess characters. for (int col = cur_col, i = 0; i < bar_width; i++, col++) { int x, y; get_screen_coords(line, col, max_value, orientation, &x, &y); mvaddch(y, x, ' '); } } } } refresh(); return 0; } // general: cleanup void cleanup_terminal_ncurses(void) { echo(); #ifdef __FreeBSD__ system("vidcontrol -f >/dev/null 2>&1"); #else system("setfont >/dev/null 2>&1"); system("setfont /usr/share/consolefonts/Lat2-Fixed16.psf.gz >/dev/null 2>&1"); #endif /*for(int i = 0; i < gradient_size; ++i) { if(the_color_redefinitions[i].color) { init_color(the_color_redefinitions[i].color, the_color_redefinitions[i].R, the_color_redefinitions[i].G, the_color_redefinitions[i].B); } } */ standend(); endwin(); system("clear"); } cava-0.10.2/output/terminal_ncurses.h000066400000000000000000000012731462072613000175760ustar00rootroot00000000000000#include "../config.h" void init_terminal_ncurses(char *const fg_color_string, char *const bg_color_string, int predef_fg_color, int predef_bg_color, int gradient, int gradient_count, char **gradient_colors, int *width, int *height); void get_terminal_dim_ncurses(int *width, int *height); int draw_terminal_ncurses(int is_tty, int terminal_height, int terminal_width, int bars_count, int bar_width, int bar_spacing, int rest, const int bars[], int previous_frame[], int gradient, int x_axis_info, enum orientation orientation); void cleanup_terminal_ncurses(void); cava-0.10.2/output/terminal_noncurses.c000066400000000000000000000325721462072613000201340ustar00rootroot00000000000000#include #include #include #include #include #ifdef _MSC_VER #include #include #include #else #include #include #include #endif #include #define MAX_GRADIENT_COLOR_DEFS 8 wchar_t *frame_buffer; wchar_t *barstring[8]; wchar_t *spacestring; int buf_length; char *ttyframe_buffer; char *ttybarstring[8]; char *ttyspacestring; int ttybuf_length; int setecho(int fd, int onoff) { #ifdef _MSC_VER HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); DWORD mode = 0; GetConsoleMode(hStdin, &mode); if (onoff == 0) SetConsoleMode(hStdin, mode & (~ENABLE_ECHO_INPUT)); else SetConsoleMode(hStdin, mode & (ENABLE_ECHO_INPUT)); #else struct termios t; if (tcgetattr(fd, &t) == -1) return -1; if (onoff == 0) { t.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON); t.c_cc[VTIME] = 0; t.c_cc[VMIN] = 0; } else { t.c_lflag |= (ECHO | ECHOE | ECHOK | ECHONL | ICANON); t.c_cc[VTIME] = 0; t.c_cc[VMIN] = 1; } if (tcsetattr(fd, TCSANOW, &t) == -1) return -1; #endif return 0; } struct colors { short unsigned int rgb[3]; }; struct colors *gradient_colors; struct colors parse_color(char *color_string) { struct colors color; sscanf(++color_string, "%02hx%02hx%02hx", &color.rgb[0], &color.rgb[1], &color.rgb[2]); return color; } // general: cleanup void free_terminal_noncurses(void) { free(frame_buffer); free(ttyframe_buffer); free(spacestring); free(ttyspacestring); for (int i = 0; i < 8; i++) { free(barstring[i]); free(ttybarstring[i]); } free(gradient_colors); } int init_terminal_noncurses(int tty, char *const fg_color_string, char *const bg_color_string, int col, int bgcol, int gradient, int gradient_count, char **gradient_color_strings, int width, int lines, int bar_width) { free_terminal_noncurses(); if (tty) { ttybuf_length = sizeof(char) * width * lines * 10; ttyframe_buffer = (char *)malloc(ttybuf_length); ttyspacestring = (char *)malloc(sizeof(char) * (bar_width + 1)); // clearing barstrings for (int n = 0; n < 8; n++) { ttybarstring[n] = (char *)malloc(sizeof(char) * (bar_width + 1)); ttybarstring[n][0] = '\0'; } ttyspacestring[0] = '\0'; ttyframe_buffer[0] = '\0'; // creating barstrings for drawing for (int n = 0; n < bar_width; n++) { strcat(ttybarstring[0], "H"); strcat(ttybarstring[1], "A"); strcat(ttybarstring[2], "B"); strcat(ttybarstring[3], "C"); strcat(ttybarstring[4], "D"); strcat(ttybarstring[5], "E"); strcat(ttybarstring[6], "F"); strcat(ttybarstring[7], "G"); strcat(ttyspacestring, " "); } } else if (!tty) { buf_length = sizeof(wchar_t) * width * lines * 10; frame_buffer = (wchar_t *)malloc(buf_length); spacestring = (wchar_t *)malloc(sizeof(wchar_t) * (bar_width + 1)); // clearing barstrings for (int n = 0; n < 8; n++) { barstring[n] = (wchar_t *)malloc(sizeof(wchar_t) * (bar_width + 1)); barstring[n][0] = '\0'; } spacestring[0] = '\0'; frame_buffer[0] = '\0'; // creating barstrings for drawing for (int n = 0; n < bar_width; n++) { wcscat(barstring[0], L"\u2588"); wcscat(barstring[1], L"\u2581"); wcscat(barstring[2], L"\u2582"); wcscat(barstring[3], L"\u2583"); wcscat(barstring[4], L"\u2584"); wcscat(barstring[5], L"\u2585"); wcscat(barstring[6], L"\u2586"); wcscat(barstring[7], L"\u2587"); wcscat(spacestring, L" "); } } col += 30; #ifdef _MSC_VER HANDLE hStdOut = NULL; CONSOLE_CURSOR_INFO curInfo; hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); GetConsoleCursorInfo(hStdOut, &curInfo); curInfo.bVisible = FALSE; SetConsoleCursorInfo(hStdOut, &curInfo); setlocale(LC_ALL, "en_US.utf8"); SetConsoleOutputCP(CP_UTF8); system("cls"); #else #ifndef __FreeBSD__ system("setterm -cursor off"); #endif system("clear"); #endif // output: reset console printf("\033[0m\n"); if (col == 38) { struct colors fg_color = parse_color(fg_color_string); printf("\033[38;2;%d;%d;%dm", fg_color.rgb[0], fg_color.rgb[1], fg_color.rgb[2]); } else { printf("\033[%dm", col); // setting color } if (gradient) { struct colors gradient_color_defs[MAX_GRADIENT_COLOR_DEFS]; for (int i = 0; i < gradient_count; i++) { gradient_color_defs[i] = parse_color(gradient_color_strings[i]); } gradient_colors = (struct colors *)malloc((lines * 2) * sizeof(struct colors)); int individual_size = lines / (gradient_count - 1); float rest = lines / (float)(gradient_count - 1) - individual_size; float rest_total = 0; int gradient_lines = 0; for (int i = 0; i < gradient_count - 1; i++) { individual_size = lines / (gradient_count - 1); if (rest_total > 1.0) { individual_size++; rest_total = rest_total - 1.0; } for (int n = 0; n < individual_size; n++) { for (int c = 0; c < 3; c++) { float next_color = gradient_color_defs[i + 1].rgb[c] - gradient_color_defs[i].rgb[c]; next_color *= n / (float)individual_size; gradient_colors[gradient_lines].rgb[c] = gradient_color_defs[i].rgb[c] + next_color; } gradient_lines++; } rest_total = rest_total + rest; } gradient_colors[lines - 1] = gradient_color_defs[gradient_count - 1]; } if (bgcol != 0) { bgcol += 40; if (bgcol == 48) { struct colors bg_color = parse_color(bg_color_string); printf("\033[48;2;%d;%d;%dm", bg_color.rgb[0], bg_color.rgb[1], bg_color.rgb[2]); } else { printf("\033[%dm", bgcol); } for (int n = lines; n >= 0; n--) { for (int i = 0; i < width; i++) { printf(" "); // setting backround color } if (n != 0) printf("\n"); else printf("\r"); } printf("\033[%dA", lines); // moving cursor back up } #ifdef _MSC_VER setecho(1, 0); #else setecho(STDIN_FILENO, 0); #endif return 0; } void get_terminal_dim_noncurses(int *width, int *lines) { #ifdef _MSC_VER CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); *width = csbi.srWindow.Right - csbi.srWindow.Left + 1; *lines = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; #else struct winsize dim; ioctl(STDOUT_FILENO, TIOCGWINSZ, &dim); *lines = (int)dim.ws_row; *width = (int)dim.ws_col; #endif } int draw_terminal_noncurses(int tty, int lines, int width, int number_of_bars, int bar_width, int bar_spacing, int rest, int bars[], int previous_frame[], int gradient, int x_axis_info) { int current_cell, prev_cell, same_line, new_line, cx; same_line = 0; new_line = 0; cx = 0; if (!tty) { // output: check if terminal has been resized if (x_axis_info) lines++; int new_lines; int new_width; get_terminal_dim_noncurses(&new_width, &new_lines); if (new_lines != (lines) || new_width != width) return -1; if (x_axis_info) lines--; } if (tty) ttyframe_buffer[0] = '\0'; else if (!tty) frame_buffer[0] = '\0'; for (int current_line = lines - 1; current_line >= 0; current_line--) { if (gradient) { if (tty) { cx += snprintf(ttyframe_buffer + cx, ttybuf_length - cx, "\033[38;2;%d;%d;%dm", gradient_colors[current_line].rgb[0], gradient_colors[current_line].rgb[1], gradient_colors[current_line].rgb[2]); } else if (!tty) { cx += swprintf(frame_buffer + cx, buf_length - cx, L"\033[38;2;%d;%d;%dm", gradient_colors[current_line].rgb[0], gradient_colors[current_line].rgb[1], gradient_colors[current_line].rgb[2]); } } int same_bar = 0; int center_adjusted = 0; for (int i = 0; i < number_of_bars; i++) { current_cell = bars[i] - current_line * 8; prev_cell = previous_frame[i] - current_line * 8; // same as last frame if ((current_cell < 1 && prev_cell < 1) || (current_cell > 7 && prev_cell > 7) || (current_cell == prev_cell)) { same_bar++; } else { if (tty) { if (same_line > 0) { cx += snprintf(ttyframe_buffer + cx, ttybuf_length - cx, "\033[%dB", same_line); // move down new_line += same_line; same_line = 0; } if (same_bar > 0) { cx += snprintf(ttyframe_buffer + cx, ttybuf_length - cx, "\033[%dC", (bar_width + bar_spacing) * same_bar); // move forward same_bar = 0; } if (!center_adjusted && rest) { cx += snprintf(ttyframe_buffer + cx, ttybuf_length - cx, "\033[%dC", rest); center_adjusted = 1; } if (current_cell < 1) cx += snprintf(ttyframe_buffer + cx, ttybuf_length - cx, "%s", ttyspacestring); else if (current_cell > 7) cx += snprintf(ttyframe_buffer + cx, ttybuf_length - cx, "%s", ttybarstring[0]); else cx += snprintf(ttyframe_buffer + cx, ttybuf_length - cx, "%s", ttybarstring[current_cell]); if (bar_spacing) cx += snprintf(ttyframe_buffer + cx, ttybuf_length - cx, "\033[%dC", bar_spacing); } else if (!tty) { if (same_line > 0) { cx += swprintf(frame_buffer + cx, buf_length - cx, L"\033[%dB", same_line); // move down new_line += same_line; same_line = 0; } if (same_bar > 0) { cx += swprintf(frame_buffer + cx, buf_length - cx, L"\033[%dC", (bar_width + bar_spacing) * same_bar); // move forward same_bar = 0; } if (!center_adjusted && rest) { cx += swprintf(frame_buffer + cx, buf_length - cx, L"\033[%dC", rest); center_adjusted = 1; } if (current_cell < 1) cx += swprintf(frame_buffer + cx, buf_length - cx, spacestring); else if (current_cell > 7) cx += swprintf(frame_buffer + cx, buf_length - cx, barstring[0]); else cx += swprintf(frame_buffer + cx, buf_length - cx, barstring[current_cell]); if (bar_spacing) cx += swprintf(frame_buffer + cx, buf_length - cx, L"\033[%dC", bar_spacing); } } } if (same_bar != number_of_bars) { if (current_line != 0) { if (tty) cx += snprintf(ttyframe_buffer + cx, ttybuf_length - cx, "\n"); else if (!tty) cx += swprintf(frame_buffer + cx, buf_length - cx, L"\n"); new_line++; } } else { same_line++; } } if (same_line != lines) { if (tty) printf("%s\r\033[%dA", ttyframe_buffer, new_line); else if (!tty) printf("%ls\r\033[%dA", frame_buffer, new_line); fflush(stdout); } return 0; } void cleanup_terminal_noncurses(void) { #ifdef _MSC_VER setecho(1, 1); HANDLE hStdOut = NULL; CONSOLE_CURSOR_INFO curInfo; hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); GetConsoleCursorInfo(hStdOut, &curInfo); curInfo.bVisible = TRUE; SetConsoleCursorInfo(hStdOut, &curInfo); system("cls"); #else setecho(STDIN_FILENO, 1); #ifdef __FreeBSD__ system("vidcontrol -f >/dev/null 2>&1"); #else system("setfont >/dev/null 2>&1"); system("setfont /usr/share/consolefonts/Lat2-Fixed16.psf.gz >/dev/null 2>&1"); system("setterm -cursor on"); #endif system("clear"); #endif printf("\033[0m\n"); } cava-0.10.2/output/terminal_noncurses.h000066400000000000000000000011241462072613000201260ustar00rootroot00000000000000int init_terminal_noncurses(int inAtty, char *const fg_color_string, char *const bg_color_string, int col, int bgcol, int gradient, int gradient_count, char **gradient_colors, int w, int h, int bar_width); void get_terminal_dim_noncurses(int *w, int *h); int draw_terminal_noncurses(int inAtty, int lines, int width, int number_of_bars, int bar_width, int bar_spacing, int rest, int bars[], int previous_frame[], int gradient, int x_axis_info); void cleanup_terminal_noncurses(void); cava-0.10.2/run_all_tests.sh000077500000000000000000000006641462072613000157300ustar00rootroot00000000000000#!/bin/bash set -e ## run these commands before testing: # squeezelite -v -m 51:fb:32:f8:e6:9f -z # sudo modprobe snd-aloop # arecord -D hw:Loopback,1 -c 2 -r 44100 > /tmp/fifo & TESTCFGS="example_files/test_configs/*" for f in $TESTCFGS do echo "testing $f" ./cava -p $f > /dev/null echo "OK!" done echo "all tets completed successfully" ## clean up: # killall squeezelite # sudo rmmod snd_aloop # killall arecord exit 0cava-0.10.2/third_party/000077500000000000000000000000001462072613000150365ustar00rootroot00000000000000cava-0.10.2/third_party/incbin.h000066400000000000000000000372441462072613000164630ustar00rootroot00000000000000/** * @file incbin.h * @author Dale Weiler * @brief Utility for including binary files * * Facilities for including binary files into the current translation unit and * making use from them externally in other translation units. */ #ifndef INCBIN_HDR #define INCBIN_HDR #include #if defined(__AVX512BW__) || \ defined(__AVX512CD__) || \ defined(__AVX512DQ__) || \ defined(__AVX512ER__) || \ defined(__AVX512PF__) || \ defined(__AVX512VL__) || \ defined(__AVX512F__) # define INCBIN_ALIGNMENT_INDEX 6 #elif defined(__AVX__) || \ defined(__AVX2__) # define INCBIN_ALIGNMENT_INDEX 5 #elif defined(__SSE__) || \ defined(__SSE2__) || \ defined(__SSE3__) || \ defined(__SSSE3__) || \ defined(__SSE4_1__) || \ defined(__SSE4_2__) || \ defined(__neon__) || \ defined(__ARM_NEON) || \ defined(__ALTIVEC__) # define INCBIN_ALIGNMENT_INDEX 4 #elif ULONG_MAX != 0xffffffffu # define INCBIN_ALIGNMENT_INDEX 3 # else # define INCBIN_ALIGNMENT_INDEX 2 #endif /* Lookup table of (1 << n) where `n' is `INCBIN_ALIGNMENT_INDEX' */ #define INCBIN_ALIGN_SHIFT_0 1 #define INCBIN_ALIGN_SHIFT_1 2 #define INCBIN_ALIGN_SHIFT_2 4 #define INCBIN_ALIGN_SHIFT_3 8 #define INCBIN_ALIGN_SHIFT_4 16 #define INCBIN_ALIGN_SHIFT_5 32 #define INCBIN_ALIGN_SHIFT_6 64 /* Actual alignment value */ #define INCBIN_ALIGNMENT \ INCBIN_CONCATENATE( \ INCBIN_CONCATENATE(INCBIN_ALIGN_SHIFT, _), \ INCBIN_ALIGNMENT_INDEX) /* Stringize */ #define INCBIN_STR(X) \ #X #define INCBIN_STRINGIZE(X) \ INCBIN_STR(X) /* Concatenate */ #define INCBIN_CAT(X, Y) \ X ## Y #define INCBIN_CONCATENATE(X, Y) \ INCBIN_CAT(X, Y) /* Deferred macro expansion */ #define INCBIN_EVAL(X) \ X #define INCBIN_INVOKE(N, ...) \ INCBIN_EVAL(N(__VA_ARGS__)) /* Variable argument count for overloading by arity */ #define INCBIN_VA_ARG_COUNTER(_1, _2, _3, N, ...) N #define INCBIN_VA_ARGC(...) INCBIN_VA_ARG_COUNTER(__VA_ARGS__, 3, 2, 1, 0) /* Green Hills uses a different directive for including binary data */ #if defined(__ghs__) # if (__ghs_asm == 2) # define INCBIN_MACRO ".file" /* Or consider the ".myrawdata" entry in the ld file */ # else # define INCBIN_MACRO "\tINCBIN" # endif #else # define INCBIN_MACRO ".incbin" #endif #ifndef _MSC_VER # define INCBIN_ALIGN \ __attribute__((aligned(INCBIN_ALIGNMENT))) #else # define INCBIN_ALIGN __declspec(align(INCBIN_ALIGNMENT)) #endif #if defined(__arm__) || /* GNU C and RealView */ \ defined(__arm) || /* Diab */ \ defined(_ARM) /* ImageCraft */ # define INCBIN_ARM #endif #ifdef __GNUC__ /* Utilize .balign where supported */ # define INCBIN_ALIGN_HOST ".balign " INCBIN_STRINGIZE(INCBIN_ALIGNMENT) "\n" # define INCBIN_ALIGN_BYTE ".balign 1\n" #elif defined(INCBIN_ARM) /* * On arm assemblers, the alignment value is calculated as (1 << n) where `n' is * the shift count. This is the value passed to `.align' */ # define INCBIN_ALIGN_HOST ".align " INCBIN_STRINGIZE(INCBIN_ALIGNMENT_INDEX) "\n" # define INCBIN_ALIGN_BYTE ".align 0\n" #else /* We assume other inline assembler's treat `.align' as `.balign' */ # define INCBIN_ALIGN_HOST ".align " INCBIN_STRINGIZE(INCBIN_ALIGNMENT) "\n" # define INCBIN_ALIGN_BYTE ".align 1\n" #endif /* INCBIN_CONST is used by incbin.c generated files */ #if defined(__cplusplus) # define INCBIN_EXTERNAL extern "C" # define INCBIN_CONST extern const #else # define INCBIN_EXTERNAL extern # define INCBIN_CONST const #endif /** * @brief Optionally override the linker section into which size and data is * emitted. * * @warning If you use this facility, you might have to deal with * platform-specific linker output section naming on your own. */ #if !defined(INCBIN_OUTPUT_SECTION) # if defined(__APPLE__) # define INCBIN_OUTPUT_SECTION ".const_data" # else # define INCBIN_OUTPUT_SECTION ".rodata" # endif #endif /** * @brief Optionally override the linker section into which data is emitted. * * @warning If you use this facility, you might have to deal with * platform-specific linker output section naming on your own. */ #if !defined(INCBIN_OUTPUT_DATA_SECTION) # define INCBIN_OUTPUT_DATA_SECTION INCBIN_OUTPUT_SECTION #endif /** * @brief Optionally override the linker section into which size is emitted. * * @warning If you use this facility, you might have to deal with * platform-specific linker output section naming on your own. * * @note This is useful for Harvard architectures where program memory cannot * be directly read from the program without special instructions. With this you * can chose to put the size variable in RAM rather than ROM. */ #if !defined(INCBIN_OUTPUT_SIZE_SECTION) # define INCBIN_OUTPUT_SIZE_SECTION INCBIN_OUTPUT_SECTION #endif #if defined(__APPLE__) # include "TargetConditionals.h" # if defined(TARGET_OS_IPHONE) && !defined(INCBIN_SILENCE_BITCODE_WARNING) # warning "incbin is incompatible with bitcode. Using the library will break upload to App Store if you have bitcode enabled. Add `#define INCBIN_SILENCE_BITCODE_WARNING` before including this header to silence this warning." # endif /* The directives are different for Apple branded compilers */ # define INCBIN_SECTION INCBIN_OUTPUT_SECTION "\n" # define INCBIN_GLOBAL(NAME) ".globl " INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "\n" # define INCBIN_INT ".long " # define INCBIN_MANGLE "_" # define INCBIN_BYTE ".byte " # define INCBIN_TYPE(...) #else # define INCBIN_SECTION ".section " INCBIN_OUTPUT_SECTION "\n" # define INCBIN_GLOBAL(NAME) ".global " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "\n" # if defined(__ghs__) # define INCBIN_INT ".word " # else # define INCBIN_INT ".int " # endif # if defined(__USER_LABEL_PREFIX__) # define INCBIN_MANGLE INCBIN_STRINGIZE(__USER_LABEL_PREFIX__) # else # define INCBIN_MANGLE "" # endif # if defined(INCBIN_ARM) /* On arm assemblers, `@' is used as a line comment token */ # define INCBIN_TYPE(NAME) ".type " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME ", %object\n" # elif defined(__MINGW32__) || defined(__MINGW64__) /* Mingw doesn't support this directive either */ # define INCBIN_TYPE(NAME) # else /* It's safe to use `@' on other architectures */ # define INCBIN_TYPE(NAME) ".type " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME ", @object\n" # endif # define INCBIN_BYTE ".byte " #endif /* List of style types used for symbol names */ #define INCBIN_STYLE_CAMEL 0 #define INCBIN_STYLE_SNAKE 1 /** * @brief Specify the prefix to use for symbol names. * * @note By default this is "g". * * @code * #define INCBIN_PREFIX incbin * #include "incbin.h" * INCBIN(Foo, "foo.txt"); * * // Now you have the following symbols instead: * // const unsigned char incbinFoo[]; * // const unsigned char *const incbinFoo; * // const unsigned int incbinFoo; * @endcode */ #if !defined(INCBIN_PREFIX) # define INCBIN_PREFIX g #endif /** * @brief Specify the style used for symbol names. * * Possible options are * - INCBIN_STYLE_CAMEL "CamelCase" * - INCBIN_STYLE_SNAKE "snake_case" * * @note By default this is INCBIN_STYLE_CAMEL * * @code * #define INCBIN_STYLE INCBIN_STYLE_SNAKE * #include "incbin.h" * INCBIN(foo, "foo.txt"); * * // Now you have the following symbols: * // const unsigned char foo_data[]; * // const unsigned char *const foo_end; * // const unsigned int foo_size; * @endcode */ #if !defined(INCBIN_STYLE) # define INCBIN_STYLE INCBIN_STYLE_CAMEL #endif /* Style lookup tables */ #define INCBIN_STYLE_0_DATA Data #define INCBIN_STYLE_0_END End #define INCBIN_STYLE_0_SIZE Size #define INCBIN_STYLE_1_DATA _data #define INCBIN_STYLE_1_END _end #define INCBIN_STYLE_1_SIZE _size /* Style lookup: returning identifier */ #define INCBIN_STYLE_IDENT(TYPE) \ INCBIN_CONCATENATE( \ INCBIN_STYLE_, \ INCBIN_CONCATENATE( \ INCBIN_EVAL(INCBIN_STYLE), \ INCBIN_CONCATENATE(_, TYPE))) /* Style lookup: returning string literal */ #define INCBIN_STYLE_STRING(TYPE) \ INCBIN_STRINGIZE( \ INCBIN_STYLE_IDENT(TYPE)) \ /* Generate the global labels by indirectly invoking the macro with our style * type and concatenating the name against them. */ #define INCBIN_GLOBAL_LABELS(NAME, TYPE) \ INCBIN_INVOKE( \ INCBIN_GLOBAL, \ INCBIN_CONCATENATE( \ NAME, \ INCBIN_INVOKE( \ INCBIN_STYLE_IDENT, \ TYPE))) \ INCBIN_INVOKE( \ INCBIN_TYPE, \ INCBIN_CONCATENATE( \ NAME, \ INCBIN_INVOKE( \ INCBIN_STYLE_IDENT, \ TYPE))) /** * @brief Externally reference binary data included in another translation unit. * * Produces three external symbols that reference the binary data included in * another translation unit. * * The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with * "Data", as well as "End" and "Size" after. An example is provided below. * * @param TYPE Optional array type. Omitting this picks a default of `unsigned char`. * @param NAME The name given for the binary data * * @code * INCBIN_EXTERN(Foo); * * // Now you have the following symbols: * // extern const unsigned char Foo[]; * // extern const unsigned char *const Foo; * // extern const unsigned int Foo; * @endcode * * You may specify a custom optional data type as well as the first argument. * @code * INCBIN_EXTERN(custom_type, Foo); * * // Now you have the following symbols: * // extern const custom_type Foo[]; * // extern const custom_type *const Foo; * // extern const unsigned int Foo; * @endcode */ #define INCBIN_EXTERN(...) \ INCBIN_CONCATENATE(INCBIN_EXTERN_, INCBIN_VA_ARGC(__VA_ARGS__))(__VA_ARGS__) #define INCBIN_EXTERN_1(NAME, ...) \ INCBIN_EXTERN_2(unsigned char, NAME) #define INCBIN_EXTERN_2(TYPE, NAME) \ INCBIN_EXTERNAL const INCBIN_ALIGN TYPE \ INCBIN_CONCATENATE( \ INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \ INCBIN_STYLE_IDENT(DATA))[]; \ INCBIN_EXTERNAL const INCBIN_ALIGN TYPE *const \ INCBIN_CONCATENATE( \ INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \ INCBIN_STYLE_IDENT(END)); \ INCBIN_EXTERNAL const unsigned int \ INCBIN_CONCATENATE( \ INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \ INCBIN_STYLE_IDENT(SIZE)) /** * @brief Externally reference textual data included in another translation unit. * * Produces three external symbols that reference the textual data included in * another translation unit. * * The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with * "Data", as well as "End" and "Size" after. An example is provided below. * * @param NAME The name given for the textual data * * @code * INCBIN_EXTERN(Foo); * * // Now you have the following symbols: * // extern const char Foo[]; * // extern const char *const Foo; * // extern const unsigned int Foo; * @endcode */ #define INCTXT_EXTERN(NAME) \ INCBIN_EXTERN_2(char, NAME) /** * @brief Include a binary file into the current translation unit. * * Includes a binary file into the current translation unit, producing three symbols * for objects that encode the data and size respectively. * * The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with * "Data", as well as "End" and "Size" after. An example is provided below. * * @param TYPE Optional array type. Omitting this picks a default of `unsigned char`. * @param NAME The name to associate with this binary data (as an identifier.) * @param FILENAME The file to include (as a string literal.) * * @code * INCBIN(Icon, "icon.png"); * * // Now you have the following symbols: * // const unsigned char Icon[]; * // const unsigned char *const Icon; * // const unsigned int Icon; * @endcode * * You may specify a custom optional data type as well as the first argument. * These macros are specialized by arity. * @code * INCBIN(custom_type, Icon, "icon.png"); * * // Now you have the following symbols: * // const custom_type Icon[]; * // const custom_type *const Icon; * // const unsigned int Icon; * @endcode * * @warning This must be used in global scope * @warning The identifiers may be different if INCBIN_STYLE is not default * * To externally reference the data included by this in another translation unit * please @see INCBIN_EXTERN. */ #ifdef _MSC_VER # define INCBIN(NAME, FILENAME) \ INCBIN_EXTERN(NAME) #else # define INCBIN(...) \ INCBIN_CONCATENATE(INCBIN_, INCBIN_VA_ARGC(__VA_ARGS__))(__VA_ARGS__) # if defined(__GNUC__) # define INCBIN_1(...) _Pragma("GCC error \"Single argument INCBIN not allowed\"") # elif defined(__clang__) # define INCBIN_1(...) _Pragma("clang error \"Single argument INCBIN not allowed\"") # else # define INCBIN_1(...) /* Cannot do anything here */ # endif # define INCBIN_2(NAME, FILENAME) \ INCBIN_3(unsigned char, NAME, FILENAME) # define INCBIN_3(TYPE, NAME, FILENAME) INCBIN_COMMON(TYPE, NAME, FILENAME, /* No terminator for binary data */) # define INCBIN_COMMON(TYPE, NAME, FILENAME, TERMINATOR) \ __asm__(INCBIN_SECTION \ INCBIN_GLOBAL_LABELS(NAME, DATA) \ INCBIN_ALIGN_HOST \ INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(DATA) ":\n" \ INCBIN_MACRO " \"" FILENAME "\"\n" \ TERMINATOR \ INCBIN_GLOBAL_LABELS(NAME, END) \ INCBIN_ALIGN_BYTE \ INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(END) ":\n" \ INCBIN_BYTE "1\n" \ INCBIN_GLOBAL_LABELS(NAME, SIZE) \ INCBIN_ALIGN_HOST \ INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(SIZE) ":\n" \ INCBIN_INT INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(END) " - " \ INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(DATA) "\n" \ INCBIN_ALIGN_HOST \ ".text\n" \ ); \ INCBIN_EXTERN(TYPE, NAME) #endif /** * @brief Include a textual file into the current translation unit. * * This behaves the same as INCBIN except it produces char compatible arrays * and implicitly adds a null-terminator byte, thus the size of data included * by this is one byte larger than that of INCBIN. * * Includes a textual file into the current translation unit, producing three * symbols for objects that encode the data and size respectively. * * The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with * "Data", as well as "End" and "Size" after. An example is provided below. * * @param NAME The name to associate with this binary data (as an identifier.) * @param FILENAME The file to include (as a string literal.) * * @code * INCTXT(Readme, "readme.txt"); * * // Now you have the following symbols: * // const char Readme[]; * // const char *const Readme; * // const unsigned int Readme; * @endcode * * @warning This must be used in global scope * @warning The identifiers may be different if INCBIN_STYLE is not default * * To externally reference the data included by this in another translation unit * please @see INCBIN_EXTERN. */ #if defined(_MSC_VER) # define INCTXT(NAME, FILENAME) \ INCBIN_EXTERN(NAME) #else # define INCTXT(NAME, FILENAME) \ INCBIN_COMMON(char, NAME, FILENAME, INCBIN_BYTE "0\n") #endif #endifcava-0.10.2/todo000066400000000000000000000003471462072613000134010ustar00rootroot00000000000000TODO ---- * config option print cut-off frequencies on x-axis * config option different color for different threshold amplitude * possibility to save settings to config file * openGL * plug-in api * new demo video * JACK support cava-0.10.2/util.h000066400000000000000000000012061462072613000136320ustar00rootroot00000000000000#pragma once #ifndef _MSC_VER #define max(a, b) \ ({ \ __typeof__(a) _a = (a); \ __typeof__(b) _b = (b); \ _a > _b ? _a : _b; \ }) #endif #define ARRAY_SIZE(x) ((sizeof(x) / sizeof(0 [x])) / ((size_t)(!(sizeof(x) % sizeof(0 [x])))))