diff --git a/pyproject.toml b/pyproject.toml index b24abfb..77ea813 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "vmr-http" -version = "0.4.1" +version = "0.5.0" description = "HTTP API for controlling Voicemeeter" readme = "README.md" authors = [{ name = "onyx-and-iris", email = "code@onyxandiris.online" }] diff --git a/src/vmr_http/models/bus.py b/src/vmr_http/models/bus.py index e1ce37f..b8e76f2 100644 --- a/src/vmr_http/models/bus.py +++ b/src/vmr_http/models/bus.py @@ -11,4 +11,3 @@ class BusParams(BaseModel): gain: Optional[float] = None mute: Optional[bool] = None mono: Optional[int] = None - eq: Optional[bool] = None diff --git a/src/vmr_http/models/eq.py b/src/vmr_http/models/eq.py index 1b5a3bb..5a22036 100644 --- a/src/vmr_http/models/eq.py +++ b/src/vmr_http/models/eq.py @@ -5,6 +5,13 @@ from typing import Optional from pydantic import BaseModel +class EQParams(BaseModel): + """Parameters for an equalizer.""" + + on: Optional[bool] = None + ab: Optional[bool] = None + + class EQChannelCellParams(BaseModel): """Parameters for an equalizer channel.""" diff --git a/src/vmr_http/web/bus.py b/src/vmr_http/web/bus.py index 9c683cb..f8ae96f 100644 --- a/src/vmr_http/web/bus.py +++ b/src/vmr_http/web/bus.py @@ -9,7 +9,7 @@ from . import busmode, eq router = APIRouter() router.include_router(busmode.router, prefix='/mode', tags=['bus mode']) -router.include_router(eq.router, prefix='/eq', tags=['bus eq']) +router.include_router(eq.create_router(parent_router_kind='bus'), prefix='/eq', tags=['bus eq']) @router.patch('', tags=['bus']) diff --git a/src/vmr_http/web/eq.py b/src/vmr_http/web/eq.py index 5bacb4d..931c407 100644 --- a/src/vmr_http/web/eq.py +++ b/src/vmr_http/web/eq.py @@ -1,87 +1,96 @@ -"""module for equalizer related endpoints.""" +"""Module for equalizer related endpoints, supporting both strip and bus parents via a factory function.""" -from fastapi import APIRouter, Body, Depends +from fastapi import APIRouter, Depends from vmr_http.dependencies import get_voicemeeter_client -from vmr_http.models.eq import EQChannelCellParams - -cell_router = APIRouter() +from vmr_http.models.eq import EQChannelCellParams, EQParams -@cell_router.patch('') -@cell_router.put('') -async def update_strip_eq_channel_cell_params( - index: int, - channel_index: int, - cell_index: int, - params: EQChannelCellParams, - voicemeeter=Depends(get_voicemeeter_client), -): - """Update one or more parameters for the specified strip eq channel cell.""" - cell = voicemeeter.strip[index].eq.channel[channel_index].cell[cell_index] - updated = {} - for key, value in params.model_dump(exclude_unset=True).items(): - setattr(cell, key, value) - updated[key] = getattr(cell, key) - return updated +def create_router(parent_router_kind: str) -> APIRouter: + """Create an APIRouter for equalizer endpoints, with the specified parent kind ('strip' or 'bus').""" + if parent_router_kind not in ('strip', 'bus'): + raise ValueError(f'Invalid router kind: {parent_router_kind}') + parent_attr = parent_router_kind + def get_parent(voicemeeter, index): + return getattr(voicemeeter, parent_attr)[index] -@cell_router.get('/on') -async def get_strip_eq_channel_cell_on( - index: int, channel_index: int, cell_index: int, voicemeeter=Depends(get_voicemeeter_client) -): - """Get the current on status for the specified strip eq channel cell.""" - return {'on': voicemeeter.strip[index].eq.channel[channel_index].cell[cell_index].on} + cell_router = APIRouter() + @cell_router.patch('') + @cell_router.put('') + async def update_eq_channel_cell_params( + index: int, + channel_index: int, + cell_index: int, + params: EQChannelCellParams, + voicemeeter=Depends(get_voicemeeter_client), + ): + """Update one or more parameters for the specified eq channel cell.""" + cell = get_parent(voicemeeter, index).eq.channel[channel_index].cell[cell_index] + updated = {} + for key, value in params.model_dump(exclude_unset=True).items(): + setattr(cell, key, value) + updated[key] = getattr(cell, key) + return updated -@cell_router.get('/type') -async def get_strip_eq_channel_cell_type( - index: int, channel_index: int, cell_index: int, voicemeeter=Depends(get_voicemeeter_client) -): - """Get the current type for the specified strip eq channel cell.""" - return {'type': voicemeeter.strip[index].eq.channel[channel_index].cell[cell_index].type} + @cell_router.get('/on') + async def get_eq_channel_cell_on( + index: int, channel_index: int, cell_index: int, voicemeeter=Depends(get_voicemeeter_client) + ): + """Get the current on status for the specified eq channel cell.""" + return {'on': get_parent(voicemeeter, index).eq.channel[channel_index].cell[cell_index].on} + @cell_router.get('/type') + async def get_eq_channel_cell_type( + index: int, channel_index: int, cell_index: int, voicemeeter=Depends(get_voicemeeter_client) + ): + """Get the current type for the specified eq channel cell.""" + return {'type': get_parent(voicemeeter, index).eq.channel[channel_index].cell[cell_index].type} -@cell_router.get('/f') -async def get_strip_eq_channel_cell_f( - index: int, channel_index: int, cell_index: int, voicemeeter=Depends(get_voicemeeter_client) -): - """Get the current f value for the specified strip eq channel cell.""" - return {'f': voicemeeter.strip[index].eq.channel[channel_index].cell[cell_index].f} + @cell_router.get('/f') + async def get_eq_channel_cell_f( + index: int, channel_index: int, cell_index: int, voicemeeter=Depends(get_voicemeeter_client) + ): + """Get the current f value for the specified eq channel cell.""" + return {'f': get_parent(voicemeeter, index).eq.channel[channel_index].cell[cell_index].f} + @cell_router.get('/gain') + async def get_eq_channel_cell_gain( + index: int, channel_index: int, cell_index: int, voicemeeter=Depends(get_voicemeeter_client) + ): + """Get the current gain value for the specified eq channel cell.""" + return {'gain': get_parent(voicemeeter, index).eq.channel[channel_index].cell[cell_index].gain} -@cell_router.get('/gain') -async def get_strip_eq_channel_cell_gain( - index: int, channel_index: int, cell_index: int, voicemeeter=Depends(get_voicemeeter_client) -): - """Get the current gain value for the specified strip eq channel cell.""" - return {'gain': voicemeeter.strip[index].eq.channel[channel_index].cell[cell_index].gain} + @cell_router.get('/q') + async def get_eq_channel_cell_q( + index: int, channel_index: int, cell_index: int, voicemeeter=Depends(get_voicemeeter_client) + ): + """Get the current q value for the specified eq channel cell.""" + return {'q': get_parent(voicemeeter, index).eq.channel[channel_index].cell[cell_index].q} + router = APIRouter() + router.include_router(cell_router, prefix='/channel/{channel_index}/cell/{cell_index}') -@cell_router.get('/q') -async def get_strip_eq_channel_cell_q( - index: int, channel_index: int, cell_index: int, voicemeeter=Depends(get_voicemeeter_client) -): - """Get the current q value for the specified strip eq channel cell.""" - return {'q': voicemeeter.strip[index].eq.channel[channel_index].cell[cell_index].q} + @router.patch('') + @router.put('') + async def update_eq_params(index: int, params: EQParams, voicemeeter=Depends(get_voicemeeter_client)): + """Update one or more equalizer parameters for the specified index.""" + eq = get_parent(voicemeeter, index).eq + updated = {} + for key, value in params.model_dump(exclude_unset=True).items(): + setattr(eq, key, value) + updated[key] = getattr(eq, key) + return updated + @router.get('/on') + async def get_eq_on(index: int, voicemeeter=Depends(get_voicemeeter_client)): + """Get the current equalizer on status for the specified index.""" + return {'on': get_parent(voicemeeter, index).eq.on} -router = APIRouter() -router.include_router(cell_router, prefix='/channel/{channel_index}/cell/{cell_index}') + @router.get('/ab') + async def get_eq_ab(index: int, voicemeeter=Depends(get_voicemeeter_client)): + """Get the current equalizer A/B status for the specified index.""" + return {'ab': get_parent(voicemeeter, index).eq.ab} - -@router.patch('') -@router.put('') -async def update_strip_eq_params( - index: int, on: bool = Body(..., embed=True), voicemeeter=Depends(get_voicemeeter_client) -): - """Update one or more equalizer parameters for the specified strip index.""" - strip_eq = voicemeeter.strip[index].eq - strip_eq.on = on - return {'on': strip_eq.on} - - -@router.get('/on') -async def get_strip_eq_on(index: int, voicemeeter=Depends(get_voicemeeter_client)): - """Get the current equalizer on status for the specified strip index.""" - return {'on': voicemeeter.strip[index].eq.on} + return router diff --git a/src/vmr_http/web/strip.py b/src/vmr_http/web/strip.py index e241b73..d004f7c 100644 --- a/src/vmr_http/web/strip.py +++ b/src/vmr_http/web/strip.py @@ -11,7 +11,7 @@ router = APIRouter() router.include_router(stripcomp.router, prefix='/comp', tags=['strip comp']) router.include_router(stripgate.router, prefix='/gate', tags=['strip gate']) router.include_router(stripdenoiser.router, prefix='/denoiser', tags=['strip denoiser']) -router.include_router(eq.router, prefix='/eq', tags=['strip eq']) +router.include_router(eq.create_router(parent_router_kind='strip'), prefix='/eq', tags=['strip eq']) @router.patch('', tags=['strip']) diff --git a/uv.lock b/uv.lock index b1a8079..b4ec39e 100644 --- a/uv.lock +++ b/uv.lock @@ -1151,7 +1151,7 @@ wheels = [ [[package]] name = "vmr-http" -version = "0.4.1" +version = "0.5.0" source = { editable = "." } dependencies = [ { name = "fastapi" },