• technoway

    I looked up the documentation for dialog.alert, and was directed to look at console.alert.

    I found this topic from 3 years ago about a similar hang with console.alert.

    console.alert with SceneView
    https://forum.omz-software.com/topic/1699/console-alert-with-sceneview

    posted in Pythonista read more
  • technoway

    I downloaded that app. I ran it under the latest Pythonist 3 beta, and got the following output in the console window.

    No compatible devices found.

    So, I didn't full test all functionality, but I got no errors.

    posted in Pythonista read more
  • technoway

    Thanks omz. I ended up using the total play time to wait.

    I had thought of that, but polling for a time with short sleeps, so that the wait can be interrupted, is probably less efficient than a notification, although admittedly only slightly so. It certainly is a lot simpler.

    posted in Pythonista read more
  • technoway

    Thank you for posting this! I just wrote a Morse code sender class that vibrates.

    I also found "AudioServicesStopSystemSound" using Google. That will stop vibrations mid-stream.

    Do you know if there is a way to detect when all vibrations have been played?

    I found "AudioServicesAddSystemSoundCompletion" at:

    https://developer.apple.com/documentation/audiotoolbox/1405244-audioservicesaddsystemsoundcompl

    I have not yet figured out whether I can use that function, and if so, how to use it.

    posted in Pythonista read more
  • technoway

    I uploaded a new version of the code.

    The "stop" method was a kludge before, and had some race conditions with the "run" method. While these never happened, they could happen if the timing was just right. Now the method is fully synchronized. All audio control, including stopping audio, is now handled in the "run" thread and the "stop" method became much simpler.

    Update: 11/10/2017 - I uploaded again. I did numerous numerical optimizations to make the code more efficient. Most significantly, the rise-fall envelope samples are now cached in a list so they don't have to be recomputed for every tone pulse. I did some polishing of names, methods, and comments. The code is now a bit shorter.

    Update: 11/11/2017 - I uploaded again. Now the tone generator uses raised cosine pulse-shaping.

    Update: 11/15/2017 - I updated the code yet again yesterday. I realized that the dot and dash tone pulses could be cached for a specific sending speed and a specific tone frequency, and then just used over and over again, as opposed to synthesizing the tone pulses repeatedly. I also synthesized some fixed-interval silences, which depend only on the sending speed. This greatly reduces the loading on the processor, at the expense of using some memory.

    posted in Pythonista read more
  • technoway

    numpy supports matrices and vectors (arrays), and supports various mathematical operations and algorithms on these types, including several linear algebra operations. It support much more than that.

    numpy comes installed with Pythonista.

    posted in Pythonista read more
  • technoway

    It would be complicated to use a regular expression to do this.

    If the files are not too large, you can read the file into memory, and check the entire file at once. It's a better general solution to read the lines sequentially though.

    If you read the lines sequentially, you might have to read two lines at a time and merge them the first time, and then read one line at a time after that merging each new line with the last line, so you can handle cases like this:

    This is line one of the file that ends in iPho-
    ne and this is line two that contains the word iPad.
    

    You would always keep the last line around, remove any hyphen at the end, and append the next line, while keeping the original line to do this again after you read the next line. Then you would check this merged line. You'd only need to merge a line if the last line ended with a hyphen character.

    Below is code that reads the lines sequentially, but without the line-merge feature, so this code will not handle words that wrap from one line to the next. I used a generator to obtain each line to make it easier to modify this code to add that feature. I just typed this code into an editor, I have not run this code at all, so I don't even know if it's syntactically correct, but it should be very close to what you need.

    If you don't need to handle words wrapping between lines, you can remove the generator, and just use a regular for-loop that iterates over the file handle. In that case, check if found_word_count == len_word_list inside of the loop, and break when that expression is true.

    def make_iterable_item_generator(iterable_item):
        """ Make a generator for any iterable item. """
        for item in iterable_item:
            yield item
    
    def file_contains_words(infh, word_list):
        """ Return True iff file contains all words in the passed word list.
            There must be no duplicate words in word_list.
            infh is an open file handle to the file to test.
        """
        found_word_count = 0
        # Create a list of boolean flags, one flag for each word in word_list.
        len_word_list = len(word_list)
        word_not_found_list = [True for i in range(0, len_word_list)]
        # Create a generator to read each line of the file.
        ingen = make_iterable_item_generator(infh)
        try:
            # Stop checking when all words are found.
            while found_word_count < len_word_list:
                line = ingen.next()
                for i in range(0, len_word_list):
                    if word_not_found_list[i]:
                        if word_list[i] in line:
                            word_not_found_list[i] = False
                            found_word_count += 1
        except StopIteration:
            pass
        return found_word_count == len_word_list
    

    posted in Editorial read more
  • technoway

    Each time the "dont_stop_me_now" function is called, the return address is saved on the call stack; so that if the function ever did return, it would return to the caller. So, if you were to try to stop the program enough times, eventually it would run out of stack memory. This would take a very, very, long time though.

    I'm not sure what Pythonista will do if it runs out of internal stack memory. I expect it would abort the program, but that's just a guess. Actually, all of that is a guess - but Python has to have a call stack, or it couldn't support recursion.

    posted in Pythonista read more
  • technoway

    One way to do cleanup an object when it leaves scope is using the following class pattern and implement the __init__, __enter__, and __exit__ methods.
    This script just prints some text. It's just to show how the __enter__ method is used in a with statement, and how the __exit__ method is called automatically when leaving scope.

    from myclass import MyClass
    
    class MyExampleClass:
        """ Class to demonstrate cleanup when leaving scope. """
    
        def __init__(self):
            """ Initialize this class instance. """
            # self.my_obj doesn't have to be assigned to a class instance.
            # It can any other python type.
            self.my_obj = MyClass()
    
        def __enter__(self):
            """ This method is called in a "with" statement line to return
                this instance.
            """
            return self
    
        def __exit__(self):
            """ This method is called when this class instance leaves the
                scope in a "with" statement.
            """
            self.my_obj.do_cleanup()
            self.my_obj = None
    
        def do_cleanup(self):
            """ Do something. """
            print('cleaning up.\n')
    
        def do_something(self):
            """ Do something. """
            print('doing something.\n')
    
        def do_something_else(self):
            """ Do something else. """
            print('doing something else.\n')
    
    if __name__ == "__main__":
        # Instead of the usual:  "obj = MyClass()", do this:
        with MyClass() as obj:
            obj.do_something()
            obj.do_something_else()
        # Leaving scope obj.__exit__() is automatically called, and
        # the __exit__ method calls self.do_cleanup()
    

    Of course, you could use del in the do_cleanup() method, but I would typically just set the the variable to None and let the garbage collector handle cleaning up the memory for the object when it either needs to to allocate more memory, or it decides that it's time.

    Adding the __enter and __exit__ methods doesn't preclude using the class without a "with" statement, but then you'll have to explicitly call the do_cleanup method when you're done with the object, i.e.:

    obj = MyClass()
    obj.do_something()
    obj.do_something_else()
    obj->do_cleanup()
    

    The __enter and __exit__ methods are implemented in Python file objects, so you can write:

    with open('filename.ext', 'w') as outfile:
        outfile.write('Do not read this.\n')
        outfile.write('Do not read this either.\n')
        outfile.write('Stop it!\n')
    # outfile.close() is called here after leaving the scope above.
    

    Unfortunately, this only works with a with statement, so leaving the scope of an if-statement or a while loop won't work. However, at the cost of extra indentation, you can add a with statement almost anywhere in a function or method.

    posted in General Discussion read more
  • technoway

    JonB - This code defines the MorseCodeSender class, which can be used to send Morse code

    This will also run as a standalone program to either send the default text "Lorum Ipsum", or to send text passed on the command line.

    This could be plugged into an amateur radio SSB transmitter and used to send Morse code over the air. Morse code has the advantage that it get through with low transmit power when there is a lot of noise on the frequency and speech will be unintelligible. This is because it can be filtered to a very narrow bandwidth to minimize noise, and because our brains are good at picking out a tone in noise.

    There are technical requirements on the energy that falls outside of the narrow transmit bandwidth, and 8-bit samples won't meet that requirement. With 16-bit samples, side-channel noise can theoretically be around 90 dB down, which far exceeds what's required legally.

    A look at the "send" method and the private "run" method, both defined towards the bottom of the class definition, will make the high-level design clear.

    https://github.com/hallahanbill/technoway/blob/master/mcsender.py

    I uploaded a newer version that cleans up some cosmetic issues. The earlier version also had some unnecessary code, but it did work.

    posted in Pythonista read more

Internal error.

Oops! Looks like something went wrong!