Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
практика научная / Практика_отчёт_БИК2205.docx
Скачиваний:
0
Добавлен:
13.05.2026
Размер:
380.41 Кб
Скачать
  1. Приложение

    1. Исходный код программы

  1. from scipy.signal import firwin, lfilter, kaiserord #type: ignore

  2. from soundfile import write as sf_write #type: ignore

  3. from librosa import load as lbrs_load

  4. from librosa.display import waveshow

  5. from matplotlib import pyplot as plt #type: ignore

  6. from time import perf_counter_ns

  7. from os.path import isfile

  8. import numpy.typing as npt

  9. import typing as typ

  10. import numpy as np

  11. import curses #type: ignore

  12.  

  13. #Функция подготовки окна консоли к использованию

  14. def init_cnvs(canvas):

  15.     win = curses.initscr()

  16.     curses.curs_set(0)

  17.     canvas.border()

  18.     canvas.refresh()

  19.     return win

  20.  

  21. #Отрисовка текста на экране в выбранной позиции

  22. def draw_text(canvas,r: int,c: int,text: str) -> None:

  23.     canvas.addstr(r,c,text)

  24.     canvas.refresh()

  25.     curses.napms(500)

  26.  

  27. #Считывание строки, введённой пользователем

  28. def get_text(canvas,r: int, c: int) -> str:

  29.     curses.curs_set(1)

  30.     canvas.refresh()

  31.     text: str = canvas.getstr(r,c)

  32.     curses.curs_set(0)

  33.     canvas.border()

  34.     canvas.refresh()

  35.     curses.flushinp()

  36.     return text

  37.  

  38. #Считывание символа, введённого пользователем

  39. def get_char(canvas,r: int, c: int) -> str:

  40.     curses.curs_set(1)

  41.     canvas.refresh()

  42.     char: str = canvas.getkey(r,c)

  43.     curses.curs_set(0)

  44.     canvas.border()

  45.     canvas.refresh()

  46.     curses.flushinp()

  47.     return char

  48.  

  49. #Фильтрация

  50. def filtration(samples: npt.NDArray,sr: float,cutoff_hz: typ.Tuple[int,int],bts: npt.DTypeLike) -> npt.NDArray:

  51.     nyq_rate: float = sr/2.0 #Частота Найквиста

  52.     trans_width: float = 5.0/nyq_rate #Ширина перехдной зоны

  53.     ripple_db: float = 15.0 #Величина затухание вне области пропускания

  54.     N, beta = kaiserord(ripple_db, trans_width) #Порядок и параметр Кайзера

  55.     filter_coeffs: npt.NDArray = firwin(N,cutoff_hz,window=('kaiser',beta),pass_zero='bandpass',fs=sr) #Получение коэффициентов фильтра

  56.     filtered_samples: npt.NDArray = lfilter(filter_coeffs,1.0,samples,axis=1) #Фильтрация

  57.     filtered_samples[0][abs(filtered_samples[0])<=1/((ripple_db/10)**10)] = 0 #Фильтрация по затуханию

  58.     filtered_samples[1][abs(filtered_samples[1])<=1/((ripple_db/10)**10)] = 0 #Фильтрация по затуханию

  59.     filtered_samples = filtered_samples.astype(bts)

  60.     return filtered_samples

  61.  

  62. #Сведение всех отфильтрованных сигналов в один

  63. def signal_mixing(f_samples: typ.List[npt.NDArray]) -> typ.List[typ.List]:

  64.     counter: int = 0

  65.     mixed_signal: typ.List[typ.List] = [[],[]]

  66.     while counter != len(f_samples[0][0]):

  67.         if f_samples[0][0][counter] != 0:

  68.             #

  69.             mixed_signal[0].append(f_samples[0][0][counter])

  70.             mixed_signal[1].append(f_samples[0][1][counter])

  71.             #

  72.         elif f_samples[1][0][counter] != 0:

  73.             #

  74.             mixed_signal[0].append(f_samples[1][0][counter])

  75.             mixed_signal[1].append(f_samples[1][1][counter])

  76.             #  

  77.         elif f_samples[2][0][counter] != 0:

  78.             #

  79.             mixed_signal[0].append(f_samples[2][0][counter])

  80.             mixed_signal[1].append(f_samples[2][1][counter])

  81.             #  

  82.         else:

  83.             #

  84.             mixed_signal[0].append(f_samples[3][0][counter])

  85.             mixed_signal[1].append(f_samples[3][1][counter])

  86.             #

  87.         counter += 1

  88.     return mixed_signal

  89.  

  90. #Кодирование

  91. def encoder(samples: typ.List[typ.List]) -> typ.List[typ.List]:

  92.     #Необходимые для кодирования величины

  93.     array_diff = [[0],[0]]

  94.     array_diff[0][0] = samples[0][0]

  95.     array_diff[1][0] = samples[1][0]

  96.     counter = 1

  97.     while counter != len(samples[0]):

  98.         array_diff[0].append(samples[0][counter]-samples[0][counter-1])

  99.         array_diff[1].append(samples[1][counter]-samples[1][counter-1])

  100.         counter += 1

  101.     return array_diff

  102.  

  103. #Декодирование

  104. def decoder(samples: typ.List[typ.List]) -> typ.List[typ.List]:

  105.     #Необходимые для декодирования величины

  106.     array_rslt = [[0],[0]]

  107.     array_rslt[0][0] = samples[0][0]

  108.     array_rslt[1][0] = samples[1][0]

  109.     counter = 1

  110.     while counter != len(samples[0]):

  111.         array_rslt[0].append(samples[0][counter]+array_rslt[0][counter-1])

  112.         array_rslt[1].append(samples[1][counter]+array_rslt[1][counter-1])

  113.         counter += 1

  114.     return array_rslt

  115.  

  116. #Вывод волнового представления аудио

  117. def show_waveform(array: npt.ArrayLike,number: int,sr: float,title: str='Waveform',label: str='Waveform') -> None:

  118.     plt.figure(number)

  119.     if type(array) == 'nd.array':

  120.         waveshow(array,sr=sr,label=label)

  121.     else:

  122.         waveshow(np.array(array),sr=sr,label=label)

  123.     if label != 'Waveform':

  124.         plt.legend()

  125.     plt.title(title)

  126.  

  127. #Инициализация окна при запуске программы

  128. w = curses.wrapper(init_cnvs)

  129. #Проверка размеров окна на подходящие для работы

  130. if curses.COLS < 71 or curses.LINES < 21:

  131.     curses.endwin()

  132.     print(f'Размер окна консоли слишком мал и составляет {curses.COLS} на {curses.LINES} пикселей.\

  133.     \nУвеличьте размер окна консоли до 71 на 21 пикселей и запустите программу заново.')

  134.     exit()

  135. else:

  136.     pass

  137.  

  138. #Считывание аудиофайла

  139. draw_text(w,1,1,'Вас приветствует Кривая Имитация Реализации Кодека Aptx (К.И.Р.К.А.)!')

  140. draw_text(w,2,1,'Для дальнейшей работы необходимо указать путь к .wav файлу.')

  141. audio_file_input: str = get_text(w,3,1) #Исходный файл

  142. if isfile(audio_file_input) == True: #Проверка существования файла

  143.     draw_text(w,4,1,'Файл успешно найден! Загружаю.')

  144.     samples_orig, sample_rate = lbrs_load(audio_file_input,sr=44100,mono=False,duration=None,dtype='float64')

  145.     draw_text(w,5,1,'Загрузка завершена.')

  146. else:

  147.     draw_text(w,4,1,'Файл не найден, повторите попытку ещё раз.')

  148.     draw_text(w,5,1,'Программа завершится через две секунды.')

  149.     draw_text(w,6,1,'До свидания!')

  150.     curses.napms(1500)

  151.     exit()

  152.  

  153. #Фильтрация по диапазонам (Адаптивное кодирование)

  154. friq_bands: typ.Tuple[typ.Tuple[int,int],typ.Tuple[int,int],typ.Tuple[int,int],typ.Tuple[int,int]]\

  155. = ((1,5500),(5501,11000),(11001,16500),(16501,22000)) #Необходимые диапазоны частот

  156. bytes_for_each_fb: typ.Tuple[npt.DTypeLike,npt.DTypeLike,npt.DTypeLike,npt.DTypeLike]\

  157. = ('float64','float32','float16','float16') #Кол-во байт на значение отсчётов в каждом диапазоне

  158. filtered_samples: typ.List[npt.NDArray] = [] #Список под разбитое по диапазонам аудио

  159. counter: int = 0

  160. perf: int = perf_counter_ns()

  161. draw_text(w,7,1,'Произвожу фильтрацию по диапазонам частот.')

  162. for i in friq_bands:

  163.     filtered_samples.append(filtration(samples_orig,sample_rate,i,bytes_for_each_fb[counter]))

  164.     counter += 1

  165.     draw_text(w,8,1,f'{counter} диапазон выделен!')

  166. counter = 0

  167. draw_text(w,8,1,f'Готово! Управилась за {(perf_counter_ns()-perf)/10**9:0.3f} с.')

  168. #Структура filtered_samples[диапазон][канал][значение]

  169.  

  170. #Объединение в один «аудиофайл»

  171. filtered_audio: typ.List[typ.List] = signal_mixing(filtered_samples)

  172. del filtered_samples

  173.  

  174. #Кодирование

  175. draw_text(w,9,1,'Произвожу кодирование.')

  176. perf = perf_counter_ns()

  177. encoded_audio: typ.List[typ.List] = encoder(filtered_audio)

  178. draw_text(w,10,1,f'Готово! Управилась за {(perf_counter_ns()-perf)/10**9:0.3f} с.')

  179.  

  180. #Декодирование

  181. draw_text(w,11,1,'Произвожу декодирование.')

  182. perf = perf_counter_ns()

  183. decoded_audio: typ.List[typ.List] = decoder(encoded_audio)

  184. draw_text(w,12,1,f'Готово! Управилась за {(perf_counter_ns()-perf)/10**9:0.3f} с.')

  185. del encoded_audio

  186.  

  187. #Вывод на экран волнового представления аудио

  188. draw_text(w,13,1,'Формирую графики.')

  189. perf = perf_counter_ns()

  190. show_waveform(samples_orig,1,sample_rate,'Original audio')

  191. show_waveform(filtered_audio,2,sample_rate,'Filtered audio')

  192. show_waveform(decoded_audio,3,sample_rate,'Encoded-decoded audio')

  193. show_waveform(samples_orig,4,sample_rate,label='Original')

  194. show_waveform(filtered_audio,4,sample_rate,'Original and filtered audio','Filtered')

  195. draw_text(w,14,1,f'Готово! Управилась за {(perf_counter_ns()-perf)/10**9:0.3f} с.')

  196. del perf

  197. del samples_orig

  198.  

  199. #Указание путей для вывода результата и запись в аудиофайл

  200. draw_text(w,16,1,f'Я закончила работу. Желаете вывести результат? y|n')

  201. flag: str = get_char(w,17,1)

  202. if flag == 'y':

  203.     draw_text(w,17,1,f'ОК. Итоговый или только после фильтрации? r|f')

  204.     flag = get_char(w,18,1)

  205.     if flag == 'r':

  206.         draw_text(w,18,1,f'ОК. Укажите путь к файлу вывода (с .wav).')

  207.         audio_file_output_decoded: str = get_text(w,19,1) #Файл вывода для итогового аудио

  208.         sf_write(audio_file_output_decoded,np.array(decoded_audio,dtype='float64').T,sample_rate,subtype='PCM_16') #Запись результата в аудиофайл

  209.         draw_text(w,19,1,f'Я закончила! Не забудьте про графики!')

  210.     elif flag == 'f':

  211.         draw_text(w,18,1,f'ОК. Укажите путь к файлу вывода (с .wav).')

  212.         audio_file_output_filtered: str = get_text(w,19,1) #Файл вывода для фильтрованного аудио

  213.         sf_write(audio_file_output_filtered,np.array(filtered_audio,dtype='float64').T,sample_rate,subtype='PCM_16') #Запись результата в аудиофайл

  214.         draw_text(w,19,1,f'Я закончила, до свидания! Не забудьте про графики!')

  215.     else:

  216.         draw_text(w,18,1,f'Что ж. Без результатов, так без результатов.')

  217.         draw_text(w,19,1,f'Хорошо. Тогда я закончила! Не забудьте про графики!')

  218. elif flag == 'n':

  219.     draw_text(w,17,1,f'Хорошо. Тогда я закончила! Не забудьте закрыть графики!')   

  220.  

  221. plt.show()

  222. curses.endwin()

Соседние файлы в папке практика научная