Skip to content

Commit

Permalink
Add mini site view for desktop menu
Browse files Browse the repository at this point in the history
  • Loading branch information
netham45 committed Oct 19, 2024
1 parent 02e79b1 commit 72b6db0
Show file tree
Hide file tree
Showing 28 changed files with 833 additions and 208 deletions.
3 changes: 1 addition & 2 deletions c_utils/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#!/usr/bin/make
CC = g++
CFLAGS = -Ofast -fopenmp -std=c++14 -mavx -march=native -mavx -msse4.1 \
-D_FORTIFY_SOURCE=2 -fstack-protector-strong -fPIE
CFLAGS = -Ofast -fopenmp -std=c++14 -mavx -march=native -mavx -msse4.1
LIBS = -lm

# Find libmp3lame
Expand Down
26 changes: 20 additions & 6 deletions c_utils/audio_processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ int AudioProcessor::processAudio(const uint8_t* inputBuffer, int32_t* outputBuff
mixSpeakers();
removeDCOffset();
equalize();
downsample();
mergeChannelsToBuffer();
downsample();
noiseShapingDither();
int samples_per_chunk = CHUNK_SIZE / (inputBitDepth / 8);
int processed_samples = samples_per_chunk * outputChannels / inputChannels;
memcpy(outputBuffer, processed_buffer, processed_samples * sizeof(int32_t));
Expand Down Expand Up @@ -85,10 +85,11 @@ void AudioProcessor::setupBiquad() {
}

void AudioProcessor::initializeSampler() {
int error = 0;
if (sampler) src_delete(sampler);
sampler = src_new(SRC_SINC_BEST_QUALITY, inputChannels, NULL);
sampler = src_new(SRC_LINEAR, inputChannels, &error);
if (downsampler) src_delete(downsampler);
downsampler = src_new(SRC_SINC_BEST_QUALITY, inputChannels, NULL);
downsampler = src_new(SRC_LINEAR, outputChannels, &error);
}

void AudioProcessor::scaleBuffer() {
Expand Down Expand Up @@ -157,11 +158,12 @@ void AudioProcessor::resample() {
if (isProcessingRequired()) {
int datalen = scale_buffer_pos / inputChannels;
src_int_to_float_array(scaled_buffer, resampler_data_in, datalen * inputChannels);
SRC_DATA sampler_config = {0};
sampler_config.data_in = resampler_data_in;
sampler_config.data_out = resampler_data_out;
sampler_config.src_ratio = (float)(outputSampleRate * OVERSAMPLING_FACTOR) / (float)inputSampleRate;
sampler_config.src_ratio = static_cast<double>(outputSampleRate * OVERSAMPLING_FACTOR) / inputSampleRate;
sampler_config.input_frames = datalen;
sampler_config.output_frames = datalen * 32;
sampler_config.output_frames = sizeof(resampler_data_out) / sizeof(float) / inputChannels;
src_process(sampler, &sampler_config);
src_float_to_int_array(resampler_data_out, resampled_buffer, sampler_config.output_frames_gen * inputChannels);
resample_buffer_pos = sampler_config.output_frames_gen * inputChannels;
Expand All @@ -175,11 +177,12 @@ void AudioProcessor::downsample() {
if (isProcessingRequired()) {
int datalen = merged_buffer_pos / outputChannels;
src_int_to_float_array(merged_buffer, resampler_data_in, datalen * outputChannels);
SRC_DATA downsampler_config = {0};
downsampler_config.data_in = resampler_data_in;
downsampler_config.data_out = resampler_data_out;
downsampler_config.src_ratio = (float)outputSampleRate / (float)(outputSampleRate * OVERSAMPLING_FACTOR);
downsampler_config.input_frames = datalen;
downsampler_config.output_frames = datalen * 32;
downsampler_config.output_frames = sizeof(resampler_data_out) / sizeof(float) / outputChannels;
src_process(downsampler, &downsampler_config);
src_float_to_int_array(resampler_data_out, processed_buffer, downsampler_config.output_frames_gen * outputChannels);
process_buffer_pos = downsampler_config.output_frames_gen * outputChannels;
Expand Down Expand Up @@ -248,7 +251,18 @@ void AudioProcessor::removeDCOffset() {
}
}

bool isProcessingRequiredCache = false;
bool isProcessingRequiredCacheSet = false;

bool AudioProcessor::isProcessingRequired() {
if (!isProcessingRequiredCacheSet) {
isProcessingRequiredCache = isProcessingRequiredCheck();
isProcessingRequiredCacheSet = true;
}
return isProcessingRequiredCache;
}

bool AudioProcessor::isProcessingRequiredCheck() {
// Check if any processing is needed
if (inputSampleRate != outputSampleRate) return true;
if (volume != 1.0f) return true;
Expand Down
15 changes: 7 additions & 8 deletions c_utils/audio_processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,26 +31,24 @@ class AudioProcessor {
float speaker_mix[MAX_CHANNELS][MAX_CHANNELS];

uint8_t receive_buffer[CHUNK_SIZE];
int32_t scaled_buffer[CHUNK_SIZE * 8];
int32_t scaled_buffer[CHUNK_SIZE * 32];
uint8_t *scaled_buffer_int8 = (uint8_t *)scaled_buffer;
int32_t resampled_buffer[CHUNK_SIZE * 128];
int32_t resampled_buffer[CHUNK_SIZE * 32];
int32_t channel_buffers[MAX_CHANNELS][CHUNK_SIZE * 32];
int32_t remixed_channel_buffers[MAX_CHANNELS][CHUNK_SIZE * 32];
int32_t merged_buffer[CHUNK_SIZE * 128];
int32_t processed_buffer[CHUNK_SIZE * 128];
int32_t merged_buffer[CHUNK_SIZE * 32];
int32_t processed_buffer[CHUNK_SIZE * 32];

int scale_buffer_pos = 0;
int process_buffer_pos = 0;
int merged_buffer_pos = 0;
int resample_buffer_pos = 0;
int channel_buffer_pos = 0;

SRC_DATA sampler_config = {0};
SRC_STATE* sampler;
SRC_DATA downsampler_config = {0};
SRC_STATE* downsampler;
float resampler_data_in[CHUNK_SIZE * MAX_CHANNELS * 32];
float resampler_data_out[CHUNK_SIZE * MAX_CHANNELS * 64];
float resampler_data_in[CHUNK_SIZE * MAX_CHANNELS * 8];
float resampler_data_out[CHUNK_SIZE * MAX_CHANNELS * 8];

Biquad* filters[MAX_CHANNELS][EQ_BANDS];
Biquad* dcFilters[MAX_CHANNELS];
Expand All @@ -71,6 +69,7 @@ class AudioProcessor {
void setupDCFilter();
void removeDCOffset();
bool isProcessingRequired();
bool isProcessingRequiredCheck();
};

#endif // AUDIO_PROCESSOR_H
4 changes: 2 additions & 2 deletions c_utils/speaker_mix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,11 +231,11 @@ void AudioProcessor::mixSpeakers() {
for (int output_channel = 0; output_channel < outputChannels; output_channel++) {
float mixed_sample = 0.0f;
for (int input_channel = 0; input_channel < inputChannels; input_channel++) {
mixed_sample += static_cast<float>(channel_buffers[input_channel][pos]) / INT32_MAX
mixed_sample += static_cast<float>(channel_buffers[input_channel][pos])
* speaker_mix[input_channel][output_channel];
}
// Apply soft clipping
mixed_sample = softClip(mixed_sample);
mixed_sample = softClip(mixed_sample / INT32_MAX);
// Convert back to int32_t
remixed_channel_buffers[output_channel][pos] = static_cast<int32_t>(mixed_sample * INT32_MAX);
}
Expand Down
75 changes: 60 additions & 15 deletions screamrouter-react/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import { BrowserRouter as Router, Routes, Route, useSearchParams, Outlet } from 'react-router-dom';
import { AppProvider, useAppContext } from './context/AppContext';
import Layout from './components/Layout';
import Dashboard from './components/Dashboard';
Expand All @@ -13,8 +13,50 @@ import AddEditSource from './components/AddEditSource';
import AddEditSink from './components/AddEditSink';
import AddEditRoute from './components/AddEditRoute';
import AddEditGroup from './components/AddEditGroup';
import DesktopMenu from './components/DesktopMenu';
import './App.css';
import './styles/darkMode.css';
import { Source, Sink, Route as RouteType } from './api/api';

const EqualizerRoute: React.FC = () => {
const [searchParams] = useSearchParams();
const { sources, sinks, routes } = useAppContext();

const type = searchParams.get('type') as 'sources' | 'sinks' | 'routes' | 'group-sink' | 'group-source';
const name = searchParams.get('name');

let item: Source | Sink | RouteType | null = null;
if (type && name) {
if (type === 'sources' || type === 'group-source') item = sources.find(s => s.name === name) || null;
else if (type === 'sinks' || type === 'group-sink') item = sinks.find(s => s.name === name) || null;
else if (type === 'routes') item = routes.find(r => r.name === name) || null;
}

if (!item) return <div>Item not found</div>;

return (
<Equalizer
item={item}
type={type}
onClose={() => window.close()}
onDataChange={() => {/* Handle data change */}}
/>
);
};

const VNCRoute: React.FC = () => {
const [searchParams] = useSearchParams();
const { sources } = useAppContext();

const ip = searchParams.get('ip');
const port = searchParams.get('port');

const source = sources.find(s => s.vnc_ip === ip && s.vnc_port === Number(port));

if (!source) return <div>Source not found</div>;

return <VNC source={source} />;
};

const AppContent: React.FC = () => {
const {
Expand Down Expand Up @@ -51,26 +93,29 @@ const AppContent: React.FC = () => {

return (
<Router basename="/site">
<Layout>
<Routes>
<Routes>
<Route path="/desktopmenu" element={<DesktopMenu />} />
<Route path="/" element={<Layout><Outlet /></Layout>}>
<Route index element={<Dashboard />} />
<Route path="sources" element={<Sources />} />
<Route path="sinks" element={<Sinks />} />
<Route path="routes" element={<RoutesComponent />} />
</Routes>
</Layout>
</Route>
<Route path="/equalizer" element={<EqualizerRoute />} />
<Route path="/vnc" element={<VNCRoute />} />
</Routes>

<AudioVisualizer
listeningToSink={listeningToSink?.name || null}
visualizingSink={visualizingSink?.name || null}
sinkIp={visualizingSink?.ip || listeningToSink?.ip || null}
/>
{showVNCModal && selectedItem && (
<VNC source={selectedItem} />
{showVNCModal && selectedItem && 'vnc_ip' in selectedItem && (
<VNC source={selectedItem as Source} />
)}
{showEqualizerModal && selectedItem && selectedItemType && (
<Equalizer
item={selectedItem}
type={selectedItemType as 'sources' | 'sinks' | 'routes'}
item={selectedItem as Source | Sink | RouteType}
type={selectedItemType as 'sources' | 'sinks' | 'routes' | 'group-sink' | 'group-source'}
onClose={() => {
setShowEqualizerModal(false);
setSelectedItem(null);
Expand All @@ -84,37 +129,37 @@ const AppContent: React.FC = () => {
)}
{showEditModal && selectedItemType === 'sources' && (
<AddEditSource
source={selectedItem}
source={selectedItem as Source}
onClose={handleEditClose}
onSave={handleEditSave}
/>
)}
{showEditModal && selectedItemType === 'sinks' && (
<AddEditSink
sink={selectedItem}
sink={selectedItem as Sink}
onClose={handleEditClose}
onSave={handleEditSave}
/>
)}
{showEditModal && selectedItemType === 'routes' && (
<AddEditRoute
route={selectedItem}
route={selectedItem as RouteType}
onClose={handleEditClose}
onSave={handleEditSave}
/>
)}
{showEditModal && selectedItemType === 'group-sink' && (
<AddEditGroup
type="sink"
group={selectedItem}
group={selectedItem as Sink}
onClose={handleEditClose}
onSave={handleEditSave}
/>
)}
{showEditModal && selectedItemType === 'group-source' && (
<AddEditGroup
type="source"
group={selectedItem}
group={selectedItem as Source}
onClose={handleEditClose}
onSave={handleEditSave}
/>
Expand Down
8 changes: 7 additions & 1 deletion screamrouter-react/src/components/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const Dashboard: React.FC = () => {
const [showEqualizerModal, setShowEqualizerModal] = useState(false);
const [showEditModal, setShowEditModal] = useState(false);
const [selectedItem, setSelectedItem] = useState<SelectedItemType>(null);
const [selectedItemType, setSelectedItemType] = useState<'sources' | 'sinks' | 'routes' | null>(null);
const [selectedItemType, setSelectedItemType] = useState<'sources' | 'sinks' | 'routes' | 'group-sink' | 'group-source' | null>(null);
const [activeSource, setActiveSource] = useState<string | null>(null);
const [sortConfig, setSortConfig] = useState<SortConfig>({ key: '', direction: 'asc' });

Expand Down Expand Up @@ -180,6 +180,7 @@ const Dashboard: React.FC = () => {
actions={actions}
sortConfig={sortConfig}
onSort={onSort}
hideExtraColumns={true}
/>
</CollapsibleSection>

Expand All @@ -199,6 +200,7 @@ const Dashboard: React.FC = () => {
visualizingSink={visualizingSink}
sortConfig={sortConfig}
onSort={onSort}
hideExtraColumns={true}
/>
</CollapsibleSection>

Expand All @@ -215,6 +217,7 @@ const Dashboard: React.FC = () => {
actions={actions}
sortConfig={sortConfig}
onSort={onSort}
hideExtraColumns={true}
/>
</CollapsibleSection>

Expand All @@ -233,6 +236,7 @@ const Dashboard: React.FC = () => {
actions={actions}
sortConfig={sortConfig}
onSort={onSort}
hideExtraColumns={true}
/>
</CollapsibleSection>

Expand All @@ -252,6 +256,7 @@ const Dashboard: React.FC = () => {
visualizingSink={visualizingSink}
sortConfig={sortConfig}
onSort={onSort}
hideExtraColumns={true}
/>
</CollapsibleSection>

Expand All @@ -268,6 +273,7 @@ const Dashboard: React.FC = () => {
actions={actions}
sortConfig={sortConfig}
onSort={onSort}
hideExtraColumns={true}
/>
</CollapsibleSection>
</div>
Expand Down
Loading

0 comments on commit 72b6db0

Please sign in to comment.