Giter Club home page Giter Club logo

judsound's Introduction

Alex's GitHub Den

I am Alexandre Courtiol, a quantitative wildlife biologist based at IZW Berlin.

For info on my research group, check out www.datazoogang.de

This page is motivated by the fact that most people using GitHub (including me) fail to organise their repositories using a coherent hierarchical system.

Instead all the repos lay at the root, forming a growing mess.

I have thus created this page as a guide to my GitHub den: it indicates what to find where.

I have also included a few repos to which I contributed and which are not stored under my personal GitHub account.

I did this for myself, but perhaps it can be useful for others too (if only as an inspiration).

R packages maintained by me released on CRAN

  • IsoriX & IsoriX_project: isoscape computation and inference of spatial origins using mixed models
  • lay: a simple and efficient implementation of rowwise jobs
  • timevarcorr: computes how the correlation between 2 time-series changes over time

R packages maintained by me but not released on CRAN

  • coronaR & excess_mortality_COVID19: workflow to monitor COVID progress (probably no longer working)
  • dfuzz: to tidy columns of strings (experimental)
  • hyenaR: to wrangle the data from the Ngorongoro Hyena Project (private)
  • inferpref: to infer preferences from mating patterns (private)
  • manyfold: to explore data by folding columns (experimental)
  • packtrack: to monitor use of packages (experimental)

R packages or alternative material reproducing analyses/results of some of my scientific papers

  • accipiteR: for a paper about how Northern goshawks cope with the urban environment
  • gallbladdeR: for a paper about the evolution of gallbladders (private)
  • isoMM: for a paper in prep about isoscapes and mixed models (private)
  • mallaRd: for a paper about the breeding behaviour of mallards in Berlin
  • matingRhinos: for a paper about mate choice and mating success in white rhinos
  • mammalianMI: for a paper about how to quantify maternal investment in mammals
  • rangeRinPA & rangeRinPA_private: for a paper on the number of rangers working in natural protected areas
  • seeadleR_private: for an upcoming paper on the changes in distribution of White-tailed Sea Eagles in Germany
  • SileR: for a paper about survivorship on Asian elephants
  • twinR & twinR-private: for a paper about the relation between twinning rates and fertility in humans
  • vullioud2018: for a paper on dominance in spotted hyenas
  • winteR & winteR_old_private: for a paper on bat hibernation and climate change

R packages maintained by others to which I contributed

Please refer to the original repos to know more about these packages.

Note that I also contributed to other packages not hosted by GitHub (e.g. spaMM).

Debugging material for reporting or fixing issues, or drafting new features

Experimental largely unfinished projects that are not R packages

  • choosiness: an individual based model to study choosiness built (old project with Robert Schwieger)
  • mating_pattern: an algorithm to infer mating preferences (old project with Robert Schwieger)
  • IUCN: an attempt to parse IUCN data (for a group project with students of the Freie University, Berlin)
  • IsoriX_hexsticker: an attempt at creating an hexsticker for IsoriX (private fork)
  • Vullioud_PhD: old material from Colin Vullioud

Teaching material

Consulting work

Miscellaneous

  • awesome-ukraine-support: useful links for ukrainians (fork)
  • courtiol: the repo to modify the page you are reading right now
  • drat: to provide some R packages
  • DZG_website: the website for my group (made with R)
  • judsound: to build an alarm clock & music player with a raspberry pie
  • todo: an attempt at creating a todo list for everything in life (private)

judsound's People

Contributors

courtiol avatar

Watchers

 avatar  avatar  avatar

judsound's Issues

Empty arrays are falsy

Which means instead of this:

if alarms != []:

the right way to check if an array has something in it is:

if alarms:
   # do something with it

Same goes for strings (anything other than '' is true), dicts, sets, etc.

Reading from file is inefficient

def list_alarms(self, vol):

Look at this code:

        file = open(self.file_to_alarms, "r")
        alarm_text = file.readlines()
        alarms = [[alarm_text[i][0], alarm_text[i][1], alarm_text[i][2], alarm_text[i][3]] for i in range(len(alarm_text))]

Here, at first you read in the whole file. This particular file is never gonna be huge, but loading whole files into memory is more or less never a good idea, since in most cases you'll be processing them in pieces; in this case line by line. You probably didn't learn this yet, but the proper way of doing that is to simply iterate over the file. So instead of loading it in its entirety and then iterating by creating indices using range(len(...)), this is what it should look like:

        with open(self.file_to_alarms, "r") as file:
            alarms = []
            for line in file:
                alarms.append([int(digit) for digit in line.strip()])

The .strip() call removes the linebreak that is included at the end of the line (if there is more than one line in the file). The conversion to int is obviously necessary and missing in your original code above, so the function in its current state produces an array of strings (i.e. is broken).

What this version does better is that it only reads one line at a time, processes it, and immediately releases its memory. Unless you have a really good reason, always read files this way and forget that .readlines() exists.

One issue with my version is that it's not guaranteed to return a list of four ints, while yours does. On the other hand, yours will throw an error if for some reason, the line is shorter than four characters. But in reality, none of these should be a problem since the file is produced somewhere else and its integrity should be guaranteed there, while here you should assume it's well-formed because it doesn't come from an untrusted or unreliable source. If you want to make sure the lists are of the right length, you could do this instead:

        with open(self.file_to_alarms, "r") as file:
            alarms = []
            for line in file:
                digits = [int(digit) for digit in line.strip()]
                assert len(digits) == 4, f'Size mismatch: { len(digits) } characters instead of 4'
                alarms.append(digits)

The assertion will throw an error if the condition is not satisfied, but again, I think this is overkill.

Yes, it's longer, but:

  • it does more (conversion to int)
  • it replaces repetition plus hard-coded indices (last line in the top code box) with iteration
  • it's clearer
  • it can still be turned into a one-liner (that will be shorter than the original, btw.) if you really want to optimize for number of lines instead of readability

Inform when no alarm exist

When listing the alarms, I need to better handle the case where no alarm has been set.
A audio message would be useful.

Use f-strings for string creation

return [str(time_to_convert[0]) + str(time_to_convert[1]), str(time_to_convert[2]) + str(time_to_convert[3])]

def convert_hhmm_to_hm(self, time):  # time_to_convert is waaaay to long, and what other time is there in this function?
    return [f'{ time[0] }{ time[1] }', f'{ time[2] }{ time[3] }']

Change sound volume setting

It seems that a more appropriate setup would be to retain the last volume used for any given player or track within the player.

This can be shortened

Instead of

                if button_index == 0:
                    self.clock.set_alarm(add = [1, 0, 0, 0])
                elif button_index == 1:
                    self.clock.set_alarm(add = [0, 1, 0, 0])
                elif button_index == 2:
                    self.clock.set_alarm(add = [0, 0, 1, 0])
                elif button_index == 3:
                    self.clock.set_alarm(add = [0, 0, 0, 1])

Why not

                delta = [0, 0, 0, 0]
                delta[button_index] = 1
                self.clock.set_alarm(add=delta)

Feedback for change in volume

For now when the volume is changed, the user does not realize by how much the volume has changed.
So we would need a sound that is produced while the rotary dial is turned to indicate that.
The sound should either be very short or quite continuous for this to work.
https://pixabay.com/sound-effects/ seems to be a good source for sounds.

Create class Box in main.py

It would make the code a little cleaner to pack everything focussed on the physical box within one class.

Use `with` when working with files

The with statement creates a block which queues up an operation when the block is exited. In case of opening files, it allows you to omit the file.close() call. It's used like this:

with open(filename) as infile:
    for line in infile:
        print(line)
# here 'infile' is closed automatically

File filter without using regexes

self.tracks_files = list(filter(

Not sure whether you already learned about the ability to filter inside a list comprehension:

        self.tracks_files = [file for file in files_in_path_music if file.endswith('mp3') or file.endswith('wav')]

The comment below there mentions that filenames should start with a number, which this test doesn't detect, but neither does the regex in the original code.

Changing modes

For now the modes are changing in circle when pressing for a long time on the rotary encoder.
I think a better experience would be that when pressing long, the user would be asked to select among up to 4 modes by pressing on one of the top button.
This would be more direct and would allow for more modes.

Careful when using mutable objects as default parameters

def __init__(self, path_music, tracks_dictionary = {}):

The problem is that the default value doesn't mean "create an empty dict every time no value is provided", but "use this exact dict that is created in the function definition". So if you call a function without providing an alternative value, and modify the dict (same applies to lists, sets, etc.), then all following calls that also use the default value will see that change. They will all work on the exact same dict object. So do this instead:

def func(x=None):
    if x is None:
        x = {}

Find alternative to time.sleep() for Clock

In the class Clock, several methods use time.sleep() to make sure a given sound is fully played until the next one is being produced. The timing is thus hardcoded, which is annoying and not robust to change.
Instead I should check the status of the player and decide what to do if something is being played already (wait, stop, overlap).

What is this chain of `if`s doing?

if self.alarm[0] > 2:

I don't know what you are planning to do with this method, but from the pure mathematical point of view this is highly questionable.

If you are planning to have functionality that shifts the alarm by a certain number of hours and minutes, then I'd rather do that with proper mixed radix integers, 24 and 60, instead of tracking each digit separately.

Sphinx is the usual way to write docs

Here's the URL

It uses reStructuredText as syntax, which is similar to Markdown but better suitable for technical documents, as it allows you to e.g. mark a string as a method and will automatically make it a link to the file containing the description of that method's class, and automatically create a table of contents and such. I think it should also be possible to set it up to extract the docstrings from the code, so you could have the code and the documentation together if you think that's better.

I think GitHub will convert reST to HTML as it does with Markdown, so no need to write everything twice.

Don't use the string value here

self.mode_current = "alarm"

First, having the same string here and in the preceding line with the if is redundant, and creates room for typos (correct string in the if, string with a typo in the assignment). I'd suggest something like:

    def change_mode(self, mode):
        if mode == "alarm":
            self.clock.reset_soft(vol = 0)
        elif mode not in ["alarm_validation", "player_night"]:
            raise ValueError('Unknown mode: ' + mode)

        self.mode_current = mode
        tracks = { # this dictionary should be outside of this function, possibly something like self.sounds
            "alarm": "alarm_mode.wav",
            "alarm_validation": "alarm_validation.mp3",
            "player_night": "player_night_mode.wav",
        }
        # NB: no spaces around equal signs inside function calls
        self.player_system.play_sound(track_name=tracks[mode], vol=self.volume_current)
        print(self.mode_current)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.