def run_command(args: List[str], progress: Progress, start: int = 0, duration: Optional[int] = None) -> None: """ Start a new process running specified command and wait for it to complete. :duration: If not None, the progress percentage will be updated based upon the amount of time the process has been running. Can be terminated by setting progress.abort to True """ progress.pct = 0.0 start_time = time.time() with subprocess.Popen(args) as proc: done = False while not done and not progress.abort: rcode = proc.poll() if rcode is not None: done = True proc.wait() else: if duration is not None: elapsed = min(duration, 1000.0 * (time.time() - start_time)) progress.pct = 100.0 * elapsed / float(duration) progress.pct_text = Duration(int(elapsed) + start).format() time.sleep(0.25) if progress.abort: proc.terminate() proc.wait() progress.pct = 100.0
def _generate(self, destination: MP3FileWriter, progress: Progress) -> None: """generate output file, combining all input files""" assert destination._metadata is not None output: Optional[AudioSegment] = None num_files = float(len(destination._files)) for index, mp3file in enumerate(destination._files, 1): progress.pct = 50.0 * index / num_files progress.text = f'Adding {mp3file.filename.name}' if progress.abort: return seg = AudioSegment.from_mp3(str(mp3file.filename)) if mp3file.start is not None and mp3file.start > 0: if mp3file.end is not None: seg = seg[mp3file.start:mp3file.end] else: seg = seg[mp3file.start:] elif mp3file.end is not None: seg = seg[:mp3file.end] if mp3file.headroom is not None: seg = seg.normalize(mp3file.headroom) if output is None: output = seg else: output = output.append(seg, crossfade=int(mp3file.overlap)) tags: Dict[str, Any] = { "artist": destination._metadata.artist, "title": destination._metadata.title } if destination._metadata.album: tags["album"] = destination._metadata.album assert output is not None progress.text = f'Encoding MP3 file "{destination.filename.name}"' progress.pct = 50.0 if progress.abort: return dest_dir = destination.filename.parent if not dest_dir.exists(): dest_dir.mkdir(parents=True) parameters = [ '-ar', str(destination._metadata.sample_rate), '-ac', str(destination._metadata.channels), ] #parameters.append(f'-acodec copy') output.export(str(destination.filename), format="mp3", bitrate=f'{destination._metadata.bitrate}k', parameters=parameters, tags=tags) progress.pct = 100.0
def render(self, filename: str, document: DG.Document, progress: Progress) -> None: """Renders the given document as a PDF file""" # pagesize is a tuple of (width, height) # see reportlab.lib.pagesizes for detains doc = self.render_document(filename, document) elements: List[Flowable] = [] num_elts = float(len(document._elements)) for index, elt in enumerate(document._elements): progress.pct = 100.0 * float(index) / num_elts elements.append(self.renderers[type(elt)](elt)) doc.build(elements) progress.pct = 100.0
def _generate(self, destination: MP3FileWriter, progress: Progress) -> None: """ generate output file, combining all input files """ num_files = float(len(destination._files)) contents: List[Dict] = [] metadata: Optional[Dict] = None if destination._metadata is not None: metadata = destination._metadata.as_dict() for index, mp3file in enumerate(destination._files, 1): progress.pct = 100.0 * index / num_files progress.text = f'Adding {mp3file.filename.name}' src: Dict[str, Union[str, int]] = { 'filename': mp3file.filename.name } if mp3file.start is not None: src['start'] = mp3file.start if mp3file.end is not None: src['end'] = mp3file.end if mp3file.headroom is not None: src['headroom'] = mp3file.headroom contents.append(src) results: Dict[str, Union[List, Optional[Dict]]] = { 'contents': contents, 'metadata': metadata, } self.output[destination.filename.name] = self.flatten(results)
def _generate(self, destination: MP3FileWriter, progress: Progress) -> None: """generate output file, combining all input files""" output: Optional[AudioSegment] = None num_files = float(len(destination._files)) for index, mp3file in enumerate(destination._files, 1): progress.pct = 50.0 * index / num_files progress.text = f'Adding {mp3file.filename.name}' if progress.abort: return seg = AudioSegment.from_mp3(str(mp3file.filename)) if mp3file.start is not None: if mp3file.end is not None: seg = seg[mp3file.start:mp3file.end] else: seg = seg[mp3file.start:] elif mp3file.end is not None: seg = seg[:mp3file.end] if mp3file.headroom is not None: seg = seg.normalize(mp3file.headroom) if output is None: output = seg else: output += seg tags = None if destination._metadata is not None: tags = { "artist": Song.clean(destination._metadata.artist), "title": Song.clean(destination._metadata.title) } if destination._metadata.album: tags["album"] = Song.clean(destination._metadata.album) assert output is not None progress.text = f'Encoding MP3 file "{destination.filename.name}"' progress.pct = 50.0 if progress.abort: return dest_dir = destination.filename.parent if not dest_dir.exists(): dest_dir.mkdir(parents=True) output.export(str(destination.filename), format="mp3", bitrate=destination.bitrate, tags=tags) progress.pct = 100.0
def search(self, parser: MP3Parser, progress: Progress) -> None: """ Walk self._fullpath searching for all songs and sub-directories. This function will block until all of the songs and directories have been checked. """ try: max_workers = len(os.sched_getaffinity(0)) + 2 # type: ignore except AttributeError: cpu_count = os.cpu_count() if cpu_count is None: max_workers = 3 else: max_workers = cpu_count + 2 with futures.ThreadPoolExecutor(max_workers=max_workers) as pool: todo = set(self.search_async(pool, parser, 0)) done: Set[futures.Future] = set() while todo and not progress.abort: completed, not_done = futures.wait( todo, timeout=0.25, return_when=futures.FIRST_COMPLETED) todo.update(set(not_done)) for future in completed: if progress.abort: break try: err = future.exception() if err is not None: progress.text = f'Error: {err}' else: result = future.result() if isinstance(result, list): todo.update(set(result)) elif result is not None: progress.text = result.filename except (futures.TimeoutError, futures.CancelledError): pass except KeyboardInterrupt: progress.abort = True todo.remove(future) done.add(future) num_tasks = len(todo) + len(done) if num_tasks > 0: progress.pct = 100.0 * len(done) / num_tasks
def play_with_pyaudio(seg: AudioSegment, progress: Progress) -> None: """use pyaudio library to play audio segment""" pya = pyaudio.PyAudio() stream = pya.open(format=pya.get_format_from_width(seg.sample_width), channels=seg.channels, rate=seg.frame_rate, output=True) try: chunks = utils.make_chunks(seg, 500) scale: float = 1.0 if chunks: scale = 100.0 / float(len(chunks)) for index, chunk in enumerate(chunks): if progress.abort: break progress.pct = index * scale stream.write(chunk._data) finally: stream.stop_stream() stream.close() pya.terminate()