{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "e7f34da7",
   "metadata": {},
   "source": [
    "# 20-24 · Звук и музыка\n",
    "\n",
    "Практика к разделу [«Звук и музыка»](../../site/chapters/glava-20/20-24-zvuk.html)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "de0c1134",
   "metadata": {},
   "source": [
    "## Цель\n",
    "\n",
    "Загрузить звук один раз и убедиться, что повторное воспроизведение не требует повторной загрузки с диска."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c94a3482",
   "metadata": {},
   "source": [
    "## Рабочий пример"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "5db43595",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-03T10:12:21.438652Z",
     "iopub.status.busy": "2026-09-03T10:12:21.438442Z",
     "iopub.status.idle": "2026-09-03T10:12:21.628303Z",
     "shell.execute_reply": "2026-09-03T10:12:21.627635Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "pygame-ce 2.5.8 (SDL 2.32.10, Python 3.14.6)\n",
      "5 воспроизведений уже загруженного звука заняли (сек): 0.0001\n"
     ]
    }
   ],
   "source": [
    "import time\n",
    "from pathlib import Path\n",
    "\n",
    "import pygame\n",
    "\n",
    "pygame.init()\n",
    "pygame.mixer.init()\n",
    "screen = pygame.display.set_mode((600, 400))\n",
    "\n",
    "# Путь к ассету собираем от зафиксированного каталога, а не строкой \"../../...\":\n",
    "# в ноутбуке текущая директория — это каталог самого ноутбука, а в обычном\n",
    "# .py-файле здесь был бы Path(__file__).resolve().parent (раздел 20.19).\n",
    "BASE_DIR = Path.cwd()\n",
    "put_k_zvuku = BASE_DIR.parents[1] / \"projects\" / \"pygame\" / \"bouncing-ball\" / \"assets\" / \"otskok.wav\"\n",
    "zvuk_otskoka = pygame.mixer.Sound(str(put_k_zvuku))   # загружаем ОДИН раз\n",
    "\n",
    "nachalo = time.perf_counter()\n",
    "for _ in range(5):\n",
    "    zvuk_otskoka.play()   # только воспроизводим уже загруженный звук\n",
    "vremya_pyati_vosproizvedenij = time.perf_counter() - nachalo\n",
    "\n",
    "print(\"5 воспроизведений уже загруженного звука заняли (сек):\", round(vremya_pyati_vosproizvedenij, 4))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "55658a84",
   "metadata": {},
   "source": [
    "## Проверка результата"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "fd0dbe78",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-03T10:12:21.630830Z",
     "iopub.status.busy": "2026-09-03T10:12:21.630606Z",
     "iopub.status.idle": "2026-09-03T10:12:21.633961Z",
     "shell.execute_reply": "2026-09-03T10:12:21.633270Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Верно: звук был загружен один раз, а не при каждом play().\n"
     ]
    }
   ],
   "source": [
    "assert isinstance(zvuk_otskoka, pygame.mixer.Sound)\n",
    "# Воспроизведение уже загруженного звука — не операция чтения с диска,\n",
    "# поэтому пять вызовов play() должны укладываться в доли секунды.\n",
    "assert vremya_pyati_vosproizvedenij < 1.0\n",
    "print(\"Верно: звук был загружен один раз, а не при каждом play().\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1e93dacd",
   "metadata": {},
   "source": [
    "## Задание ★ Базовая практика\n",
    "\n",
    "Загрузите звук ещё раз в отдельную переменную и убедитесь, что это НЕ один и тот же объект Python в памяти, хотя оба указывают на один и тот же файл — то есть на диск действительно ходили дважды."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "c3b6aa9f",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-03T10:12:21.635036Z",
     "iopub.status.busy": "2026-09-03T10:12:21.634917Z",
     "iopub.status.idle": "2026-09-03T10:12:21.637627Z",
     "shell.execute_reply": "2026-09-03T10:12:21.637180Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Верно: это два отдельных объекта — именно поэтому загрузку выносят из цикла заранее.\n"
     ]
    }
   ],
   "source": [
    "zvuk_otskoka_2 = pygame.mixer.Sound(put_k_zvuku)\n",
    "assert zvuk_otskoka_2 is not zvuk_otskoka\n",
    "print(\"Верно: это два отдельных объекта — именно поэтому загрузку выносят из цикла заранее.\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Cartesian Python 3.14",
   "language": "python",
   "name": "cartesian-python314"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.14.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
