0

Decided to make a simple mp3 player for terminal. But while I was doing animation I had a problem - it blinks when the frame changes. Heres a video of it: https://youtu.be/in4VLPOfzHw. And the code:

import time, os, glob, eyed3, math, sys
from colorama import init
from mutagen.mp3 import MP3


mpts = glob.glob('*.mp3')
dark_grey = '\033[1;30;40m'
light_grey = '\033[0;37;40m'
white = '\033[1;37;40m'
lime = '\033[1;32;40m'
red = '\033[0;31;40m'
i = 0
song_list = []

for mpt in mpts:
    song = MP3(mpt)
    duration = math.ceil(song.info.length)
    m_duration = duration // 60
    s_duration = duration % 60
    song = eyed3.load(mpt)
    name = song.tag.title
    song_list.append([name, [m_duration, s_duration]])

init()

# draw
while True:
    # cassette
    res = ''
    i += 1
    res += light_grey + '  ■̅̅̅̅̅̅̅̅̅̅̅̅■   \n'
    res += dark_grey + ' |'
    res += light_grey + '|############|'
    res += dark_grey + '| \n'
    res += dark_grey + ' |'
    res += light_grey + '|'
    if i % 4 == 0:
        res += white + ' (/)====(/) '
    elif i % 4 == 1:
        res += white + ' (-)====(-) '
    elif i % 4 == 2:
        res += white + ' (\\)====(\\) '
    elif i % 4 == 3:
        res += white + ' (|)====(|) '
    res += light_grey + '|'
    res += dark_grey + '| \n'
    res += dark_grey + ' |'
    res += light_grey + '|############|'
    res += dark_grey + '|\n'
    res += light_grey + '  ■____________■   \n'
    # green line
    res += lime + ' ___________________________________\n\n'
    # song list
    res += red + ' #  NAME                        TIME\n'
    for i1 in range(len(song_list)):
        res += dark_grey + ' ' + str(i1+1) + '.'
        res += white + ' ' + song_list[i1][0] + ' '*(28 - len(song_list[i1][0])) + f'{song_list[i1][1][0]}:{song_list[i1][1][1]}\n'
    os.system('cls')
    sys.stdout.write(res)
    sys.stdout.flush()
    time.sleep(0.4)

Can it be fixed or sould I try to make in some other language instead of python?

2 Answers2

0

It's the shelling out to cls that's doing it. Since you're already using ANSI codes for other stuff, try something like:

clear = '\033c'


...
while True:
...
    print(clear)

Note that you'll never be able to completely get rid of the screen flicker using the "clear the screen then redraw it" technique, but this will shave several milliseconds from every loop and should decrease the flickering.

Kirk Strauser
  • 30,189
  • 5
  • 49
  • 65
0

The idea is to avoid cleaning the whole screen (os.system('cls')). We could simply move the cursor to top and reprint everything. However moving cursor to top is almost impossible. One workaround I found is to print a lot of special characters that move cursor up one line until all the way to the top.

Reference:

cmd console game; reduction of blinking

The first solution of using \b does not work for me on a windows machine. So I go for the ender_scythe's solution. You have to print an empty line on first run to avoid the issue he/she mentioned. Here is the sample code that does not blink at all:

import time
import os

i = 0
dark_grey = '\033[1;30;40m'
light_grey = '\033[0;37;40m'
white = '\033[1;37;40m'
lime = '\033[1;32;40m'
red = '\033[0;31;40m'


def my_cls(nrow = 0):
    if nrow == 0:
        os.system('cls')
    else:
        print('\033[F'*nrow)

def my_display(chars):
    print(''.join(chars))
    return len(chars)

nrow = 0
while True:
    my_cls(nrow)
    # cassette
    res = []
    i+=1
    if i == 1:
        res.append('\n')
    res.append(light_grey + '  ■̅̅̅̅̅̅̅̅̅̅̅̅■   \n')
    res.append(dark_grey + ' |')
    res.append(light_grey + '|###########|')
    res.append(dark_grey + '| \n')
    res.append(dark_grey + ' |')
    res.append(light_grey + '|')
    if i % 4 == 0:
        res.append(white + ' (/)====(/) ')
    elif i % 4 == 1:
        res.append(white + ' (-)====(-) ')
    elif i % 4 == 2:
        res.append(white + ' (\\)====(\\) ')
    elif i % 4 == 3:
        res.append(white + ' (|)====(|) ')
    res.append(light_grey + '|')
    res.append(dark_grey + '| \n')
    res.append(dark_grey + ' |')
    res.append(light_grey + '|############|')
    res.append(dark_grey + '|\n')
    res.append(light_grey + '  ■____________■   \n')
    # green line
    res.append(lime + ' ___________________________________\n\n')
    # song list
    res.append(red + ' #  NAME                        TIME\n')
    nrow = my_display(res)
    time.sleep(0.4)
Z Li
  • 4,133
  • 1
  • 4
  • 19