.cache/clangd/index/main.cpp.47C66B394CD74271.idx
.cache/clangd/index/main.cpp.47C66B394CD74271.idx
This is a binary file and will not be displayed.
.cache/clangd/index/qr.h.B46974D52593BF02.idx
.cache/clangd/index/qr.h.B46974D52593BF02.idx
This is a binary file and will not be displayed.
+6
-58
flake.nix
+6
-58
flake.nix
···
40
40
41
41
buildPhase = ''
42
42
export LDFLAGS="-static -static-libgcc -static-libstdc++"
43
-
43
+
44
44
# Check if BASS files exist in libs directory
45
45
if [ -f "libs/bass.h" ] && [ -f "libs/bass.lib" ]; then
46
46
echo "BASS files found in libs/ - building with audio integration"
···
50
50
sed -i 's|#include "libs/bass.h"|// #include "libs/bass.h"|' main.cpp
51
51
sed -i 's|libs/bass.lib||' CMakeLists.txt
52
52
fi
53
-
53
+
54
54
cmake -DCMAKE_BUILD_TYPE=Release \
55
55
-DCMAKE_SYSTEM_NAME=Windows \
56
56
-DCMAKE_C_COMPILER=$CC \
···
66
66
};
67
67
68
68
deploy-to-xp = pkgs.writeShellScriptBin "deploy-to-xp" ''
69
+
echo "rebuilding program"
70
+
nix build --rebuild
71
+
69
72
XP_DIR="$HOME/Documents/xp-drive"
70
73
mkdir -p "$XP_DIR"
71
74
72
75
echo "Deploying Shortwave Radio to $XP_DIR..."
73
76
74
77
# Copy executable with force overwrite
75
-
if cp -f ${self'.packages.shortwave}/bin/Shortwave.exe "$XP_DIR/"; then
78
+
if cp -f result/bin/Shortwave.exe "$XP_DIR/"; then
76
79
echo "✓ Copied Shortwave.exe"
77
80
else
78
81
echo "✗ Failed to copy Shortwave.exe"
···
96
99
ls -la "$XP_DIR"/*.{exe,dll} 2>/dev/null || echo "No files found"
97
100
'';
98
101
99
-
setup-dev = pkgs.writeShellScriptBin "setup-dev" ''
100
-
echo "Setting up development environment for Shortwave Radio..."
101
-
102
-
# Get dynamic paths from nix packages
103
-
GCC_BASE="${pkgs.pkgsCross.mingw32.buildPackages.gcc}/i686-w64-mingw32"
104
-
SYS_INCLUDE="$GCC_BASE/sys-include"
105
-
MINGW_MAIN_INCLUDE="${pkgs.pkgsCross.mingw32.windows.mingw_w64}/include"
106
-
CPP_INCLUDE="${pkgs.lib.getDev pkgs.pkgsCross.mingw32.buildPackages.gcc}/include/c++/10.3.0"
107
-
CPP_TARGET_INCLUDE="$CPP_INCLUDE/i686-w64-mingw32"
108
-
109
-
# Create .clangd config with correct paths
110
-
cat > .clangd << EOF
111
-
CompileFlags:
112
-
Add:
113
-
- -target
114
-
- i686-w64-mingw32
115
-
- -DWINVER=0x0501
116
-
- -D_WIN32_WINNT=0x0501
117
-
- -DWIN32_LEAN_AND_MEAN
118
-
- -D_WIN32
119
-
- -DWIN32
120
-
- -std=c++17
121
-
- -fno-builtin
122
-
- -isystem
123
-
- $SYS_INCLUDE
124
-
- -isystem
125
-
- $MINGW_MAIN_INCLUDE
126
-
- -isystem
127
-
- $CPP_INCLUDE
128
-
- -isystem
129
-
- $CPP_TARGET_INCLUDE
130
-
Remove:
131
-
- -I*/gcc/*/include
132
-
EOF
133
-
134
-
# Create compile_commands.json
135
-
cat > compile_commands.json << EOF
136
-
[
137
-
{
138
-
"directory": "$(pwd)",
139
-
"command": "i686-w64-mingw32-g++ -DWINVER=0x0501 -D_WIN32_WINNT=0x0501 -DWIN32_LEAN_AND_MEAN -D_WIN32 -DWIN32 -std=c++17 -isystem \"$SYS_INCLUDE\" -isystem \"$MINGW_MAIN_INCLUDE\" -isystem \"$CPP_INCLUDE\" -isystem \"$CPP_TARGET_INCLUDE\" -c main.cpp",
140
-
"file": "main.cpp"
141
-
}
142
-
]
143
-
EOF
144
-
145
-
echo "Generated .clangd config and compile_commands.json with include paths"
146
-
echo "Development environment ready for Shortwave Radio development"
147
-
echo "Include paths:"
148
-
echo " C standard library: $SYS_INCLUDE"
149
-
echo " MinGW headers: $MINGW_MAIN_INCLUDE"
150
-
echo " C++ headers: $CPP_INCLUDE"
151
-
'';
152
-
153
102
default = self'.packages.shortwave;
154
103
};
155
104
···
159
108
cmake
160
109
pkgsCross.mingw32.buildPackages.gcc
161
110
self'.packages.deploy-to-xp
162
-
self'.packages.setup-dev
163
111
];
164
112
165
113
shellHook = ''
+291
-24
main.cpp
+291
-24
main.cpp
···
30
30
{15.770f, "Radio Paradise", "Eclectic music mix", "http://stream.radioparadise.com/mp3-128"},
31
31
{17.895f, "Jazz Radio", "Smooth jazz", "http://jazz-wr04.ice.infomaniak.ch/jazz-wr04-128.mp3"},
32
32
{21.500f, "Classical Music", "Classical radio", "http://stream.wqxr.org/wqxr"},
33
-
{31.100f, "Chillout Lounge", "Relaxing music", "http://air.radiorecord.ru:805/chil_320"}
34
33
};
35
34
36
35
#define NUM_STATIONS (sizeof(g_stations) / sizeof(RadioStation))
···
48
47
int isPlaying;
49
48
float staticVolume;
50
49
float radioVolume;
51
-
50
+
52
51
// Station tracking
53
52
RadioStation* currentStation;
53
+
54
+
// VU meter levels (0.0 to 1.0)
55
+
float vuLevelLeft;
56
+
float vuLevelRight;
54
57
} AudioState;
55
58
56
59
// Radio state
···
71
74
void DrawTuningDial(HDC hdc, int x, int y, int radius, float frequency);
72
75
void DrawFrequencyDisplay(HDC hdc, int x, int y, float frequency);
73
76
void DrawSignalMeter(HDC hdc, int x, int y, int strength);
77
+
void DrawVUMeter(HDC hdc, int x, int y, float leftLevel, float rightLevel);
74
78
void DrawVolumeKnob(HDC hdc, int x, int y, int radius, float volume);
75
79
void DrawPowerButton(HDC hdc, int x, int y, int radius, int power);
76
80
int IsPointInCircle(int px, int py, int cx, int cy, int radius);
···
90
94
int StartBassStreaming(RadioStation* station);
91
95
void StopBassStreaming();
92
96
97
+
// Static noise functions
98
+
DWORD CALLBACK StaticStreamProc(HSTREAM handle, void* buffer, DWORD length, void* user);
99
+
void StartStaticNoise();
100
+
void StopStaticNoise();
101
+
void UpdateStaticVolume(float signalStrength);
102
+
103
+
// VU meter functions
104
+
void UpdateVULevels();
105
+
93
106
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow) {
94
107
// Allocate console for debugging
95
108
AllocConsole();
···
146
159
147
160
ShowWindow(hwnd, nCmdShow);
148
161
UpdateWindow(hwnd);
162
+
163
+
// Set timer for VU meter updates (30 FPS)
164
+
SetTimer(hwnd, 1, 33, NULL);
149
165
150
166
MSG msg = {};
151
167
while (GetMessage(&msg, NULL, 0, 0)) {
···
177
193
RECT rect;
178
194
GetClientRect(hwnd, &rect);
179
195
196
+
// Update VU levels before drawing
197
+
if (g_radio.power) {
198
+
UpdateVULevels();
199
+
}
200
+
180
201
DrawRadioInterface(hdc, &rect);
181
202
182
203
EndPaint(hwnd, &ps);
···
262
283
if (g_radio.signalStrength < 0) g_radio.signalStrength = 0;
263
284
if (g_radio.signalStrength > 100) g_radio.signalStrength = 100;
264
285
286
+
UpdateStaticVolume(g_radio.signalStrength);
265
287
InvalidateRect(hwnd, NULL, TRUE);
266
288
break;
267
289
}
···
287
309
if (g_radio.signalStrength < 0) g_radio.signalStrength = 0;
288
310
if (g_radio.signalStrength > 100) g_radio.signalStrength = 100;
289
311
312
+
UpdateStaticVolume(g_radio.signalStrength);
290
313
InvalidateRect(hwnd, NULL, TRUE);
291
314
break;
292
315
}
···
312
335
if (g_radio.signalStrength < 0) g_radio.signalStrength = 0;
313
336
if (g_radio.signalStrength > 100) g_radio.signalStrength = 100;
314
337
338
+
UpdateStaticVolume(g_radio.signalStrength);
315
339
InvalidateRect(hwnd, NULL, TRUE);
316
340
break;
317
341
}
···
337
361
if (g_radio.signalStrength < 0) g_radio.signalStrength = 0;
338
362
if (g_radio.signalStrength > 100) g_radio.signalStrength = 100;
339
363
364
+
UpdateStaticVolume(g_radio.signalStrength);
340
365
InvalidateRect(hwnd, NULL, TRUE);
341
366
break;
342
367
}
···
371
396
break;
372
397
}
373
398
return 0;
399
+
400
+
case WM_TIMER: {
401
+
// Timer for VU meter updates
402
+
if (g_radio.power) {
403
+
InvalidateRect(hwnd, NULL, FALSE);
404
+
}
405
+
return 0;
406
+
}
374
407
}
375
408
376
409
return DefWindowProc(hwnd, uMsg, wParam, lParam);
···
415
448
416
449
// Draw signal meter
417
450
DrawSignalMeter(hdc, 450, 150, g_radio.signalStrength);
451
+
452
+
// Draw VU meter
453
+
DrawVUMeter(hdc, 450, 180, g_audio.vuLevelLeft, g_audio.vuLevelRight);
418
454
419
455
// Draw power button
420
456
DrawPowerButton(hdc, 500, 120, 25, g_radio.power);
···
510
546
Ellipse(hdc, x - radius, y - radius, x + radius, y + radius);
511
547
DeleteObject(borderPen);
512
548
513
-
// Draw frequency markings
549
+
// Draw tick marks and frequency markings (270 degree sweep)
550
+
HPEN tickPen = CreatePen(PS_SOLID, 1, RGB(60, 40, 20));
551
+
SelectObject(hdc, tickPen);
552
+
553
+
// Draw major tick marks and frequency labels
514
554
SetTextColor(hdc, RGB(0, 0, 0));
515
555
HFONT smallFont = CreateFont(10, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
516
556
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
···
519
559
SelectObject(hdc, smallFont);
520
560
SetTextAlign(hdc, TA_CENTER);
521
561
562
+
// 270 degree sweep from -135 to +135 degrees
522
563
for (int i = 0; i < 12; i++) {
523
-
float angle = (float)i * 3.14159f / 6.0f;
524
-
int markX = x + (int)((radius - 15) * cos(angle));
525
-
int markY = y + (int)((radius - 15) * sin(angle));
564
+
float angle = -3.14159f * 0.75f + (float)i * (3.14159f * 1.5f) / 11.0f;
526
565
566
+
// Major tick marks
567
+
int tickStartX = x + (int)((radius - 8) * cos(angle));
568
+
int tickStartY = y + (int)((radius - 8) * sin(angle));
569
+
int tickEndX = x + (int)((radius - 2) * cos(angle));
570
+
int tickEndY = y + (int)((radius - 2) * sin(angle));
571
+
MoveToEx(hdc, tickStartX, tickStartY, NULL);
572
+
LineTo(hdc, tickEndX, tickEndY);
573
+
574
+
// Frequency labels
575
+
int markX = x + (int)((radius - 18) * cos(angle));
576
+
int markY = y + (int)((radius - 18) * sin(angle));
527
577
char mark[8];
528
578
sprintf(mark, "%d", 10 + i * 2);
529
579
TextOut(hdc, markX, markY - 5, mark, strlen(mark));
530
580
}
531
581
532
-
// Draw pointer based on frequency
533
-
float angle = (frequency - 10.0f) / 24.0f * 3.14159f;
582
+
// Draw minor tick marks between major ones
583
+
for (int i = 0; i < 11; i++) {
584
+
float angle = -3.14159f * 0.75f + ((float)i + 0.5f) * (3.14159f * 1.5f) / 11.0f;
585
+
int tickStartX = x + (int)((radius - 5) * cos(angle));
586
+
int tickStartY = y + (int)((radius - 5) * sin(angle));
587
+
int tickEndX = x + (int)((radius - 2) * cos(angle));
588
+
int tickEndY = y + (int)((radius - 2) * sin(angle));
589
+
MoveToEx(hdc, tickStartX, tickStartY, NULL);
590
+
LineTo(hdc, tickEndX, tickEndY);
591
+
}
592
+
593
+
// Draw range limit markers at start and end positions
594
+
HPEN limitPen = CreatePen(PS_SOLID, 2, RGB(255, 0, 0));
595
+
SelectObject(hdc, limitPen);
596
+
597
+
// Start position (-135 degrees, 10 MHz)
598
+
float startAngle = -3.14159f * 0.75f;
599
+
int startX = x + (int)((radius - 12) * cos(startAngle));
600
+
int startY = y + (int)((radius - 12) * sin(startAngle));
601
+
int startEndX = x + (int)(radius * cos(startAngle));
602
+
int startEndY = y + (int)(radius * sin(startAngle));
603
+
MoveToEx(hdc, startX, startY, NULL);
604
+
LineTo(hdc, startEndX, startEndY);
605
+
606
+
// End position (+135 degrees, 34 MHz)
607
+
float endAngle = 3.14159f * 0.75f;
608
+
int endX = x + (int)((radius - 12) * cos(endAngle));
609
+
int endY = y + (int)((radius - 12) * sin(endAngle));
610
+
int endEndX = x + (int)(radius * cos(endAngle));
611
+
int endEndY = y + (int)(radius * sin(endAngle));
612
+
MoveToEx(hdc, endX, endY, NULL);
613
+
LineTo(hdc, endEndX, endEndY);
614
+
615
+
DeleteObject(tickPen);
616
+
DeleteObject(limitPen);
617
+
618
+
// Draw pointer based on frequency (270 degree sweep)
619
+
float normalizedFreq = (frequency - 10.0f) / 24.0f;
620
+
float angle = -3.14159f * 0.75f + normalizedFreq * (3.14159f * 1.5f);
534
621
int pointerX = x + (int)((radius - 10) * cos(angle));
535
622
int pointerY = y + (int)((radius - 10) * sin(angle));
536
623
···
599
686
}
600
687
}
601
688
689
+
void DrawVUMeter(HDC hdc, int x, int y, float leftLevel, float rightLevel) {
690
+
// Draw VU meter background
691
+
RECT meterBg = {x, y, x + 80, y + 40};
692
+
HBRUSH bgBrush = CreateSolidBrush(RGB(20, 20, 20));
693
+
FillRect(hdc, &meterBg, bgBrush);
694
+
DeleteObject(bgBrush);
695
+
696
+
// Draw border
697
+
HPEN borderPen = CreatePen(PS_SOLID, 1, RGB(100, 100, 100));
698
+
SelectObject(hdc, borderPen);
699
+
Rectangle(hdc, meterBg.left, meterBg.top, meterBg.right, meterBg.bottom);
700
+
DeleteObject(borderPen);
701
+
702
+
// Draw "VU" label
703
+
SetTextColor(hdc, RGB(200, 200, 200));
704
+
SetBkMode(hdc, TRANSPARENT);
705
+
HFONT smallFont = CreateFont(10, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
706
+
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
707
+
CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
708
+
DEFAULT_PITCH | FF_SWISS, "Arial");
709
+
SelectObject(hdc, smallFont);
710
+
TextOut(hdc, x + 2, y + 2, "VU", 2);
711
+
712
+
// Draw left channel meter
713
+
int leftWidth = (int)(leftLevel * 70);
714
+
if (leftWidth > 0) {
715
+
RECT leftBar = {x + 5, y + 12, x + 5 + leftWidth, y + 18};
716
+
COLORREF leftColor = leftLevel > 0.8f ? RGB(255, 0, 0) :
717
+
leftLevel > 0.6f ? RGB(255, 255, 0) : RGB(0, 255, 0);
718
+
HBRUSH leftBrush = CreateSolidBrush(leftColor);
719
+
FillRect(hdc, &leftBar, leftBrush);
720
+
DeleteObject(leftBrush);
721
+
}
722
+
723
+
// Draw right channel meter
724
+
int rightWidth = (int)(rightLevel * 70);
725
+
if (rightWidth > 0) {
726
+
RECT rightBar = {x + 5, y + 22, x + 5 + rightWidth, y + 28};
727
+
COLORREF rightColor = rightLevel > 0.8f ? RGB(255, 0, 0) :
728
+
rightLevel > 0.6f ? RGB(255, 255, 0) : RGB(0, 255, 0);
729
+
HBRUSH rightBrush = CreateSolidBrush(rightColor);
730
+
FillRect(hdc, &rightBar, rightBrush);
731
+
DeleteObject(rightBrush);
732
+
}
733
+
734
+
// Draw channel labels
735
+
TextOut(hdc, x + 77, y + 10, "L", 1);
736
+
TextOut(hdc, x + 77, y + 20, "R", 1);
737
+
738
+
// Draw scale marks
739
+
HPEN scalePen = CreatePen(PS_SOLID, 1, RGB(80, 80, 80));
740
+
SelectObject(hdc, scalePen);
741
+
for (int i = 1; i < 10; i++) {
742
+
int markX = x + 5 + (i * 7);
743
+
MoveToEx(hdc, markX, y + 30, NULL);
744
+
LineTo(hdc, markX, y + 32);
745
+
}
746
+
DeleteObject(scalePen);
747
+
DeleteObject(smallFont);
748
+
}
749
+
602
750
void DrawPowerButton(HDC hdc, int x, int y, int radius, int power) {
603
751
// Draw button background
604
752
COLORREF buttonColor = power ? RGB(255, 0, 0) : RGB(100, 100, 100);
···
641
789
float angle = GetAngleFromPoint(mouseX, mouseY, 150, 200);
642
790
643
791
// Convert angle to frequency (10-34 MHz range)
644
-
// Normalize angle from -PI to PI to 0-1 range
645
-
float normalizedAngle = (angle + 3.14159f) / (2.0f * 3.14159f);
792
+
// Map 270 degree sweep from -135 to +135 degrees
793
+
float normalizedAngle = (angle + 3.14159f * 0.75f) / (3.14159f * 1.5f);
794
+
795
+
// Clamp to valid range
796
+
if (normalizedAngle < 0.0f) normalizedAngle = 0.0f;
797
+
if (normalizedAngle > 1.0f) normalizedAngle = 1.0f;
646
798
647
799
// Map to frequency range
648
800
g_radio.frequency = 10.0f + normalizedAngle * 24.0f;
···
668
820
669
821
if (g_radio.signalStrength < 0) g_radio.signalStrength = 0;
670
822
if (g_radio.signalStrength > 100) g_radio.signalStrength = 100;
823
+
824
+
UpdateStaticVolume(g_radio.signalStrength);
671
825
}
672
826
673
827
void UpdateVolumeFromMouse(int mouseX, int mouseY) {
···
682
836
// Clamp volume
683
837
if (g_radio.volume < 0.0f) g_radio.volume = 0.0f;
684
838
if (g_radio.volume > 1.0f) g_radio.volume = 1.0f;
839
+
840
+
// Update static volume when main volume changes
841
+
UpdateStaticVolume(g_radio.signalStrength);
685
842
}
686
843
687
844
int InitializeAudio() {
688
845
// Initialize BASS with more detailed error reporting
689
846
printf("Initializing BASS audio system...\n");
690
-
847
+
691
848
if (!BASS_Init(-1, 44100, 0, 0, NULL)) {
692
849
DWORD error = BASS_ErrorGetCode();
693
850
printf("BASS initialization failed (Error: %lu)\n", error);
694
-
851
+
695
852
// Try alternative initialization methods
696
853
printf("Trying alternative audio device...\n");
697
854
if (!BASS_Init(0, 44100, 0, 0, NULL)) {
···
706
863
return -1;
707
864
}
708
865
}
709
-
866
+
710
867
printf("BASS initialized successfully\n");
711
-
868
+
712
869
// Get BASS version info
713
870
DWORD version = BASS_GetVersion();
714
-
printf("BASS version: %d.%d.%d.%d\n",
871
+
printf("BASS version: %d.%d.%d.%d\n",
715
872
HIBYTE(HIWORD(version)), LOBYTE(HIWORD(version)),
716
873
HIBYTE(LOWORD(version)), LOBYTE(LOWORD(version)));
717
-
874
+
718
875
g_audio.currentStream = 0;
719
876
g_audio.staticStream = 0;
720
877
g_audio.isPlaying = 0;
721
878
g_audio.staticVolume = 0.8f;
722
879
g_audio.radioVolume = 0.0f;
723
880
g_audio.currentStation = NULL;
881
+
g_audio.vuLevelLeft = 0.0f;
882
+
g_audio.vuLevelRight = 0.0f;
724
883
725
884
return 0;
726
885
}
727
886
728
887
void CleanupAudio() {
729
888
StopBassStreaming();
730
-
889
+
731
890
// Free BASS
732
891
BASS_Free();
733
892
printf("BASS cleaned up\n");
···
736
895
void StartAudio() {
737
896
if (!g_audio.isPlaying) {
738
897
g_audio.isPlaying = 1;
739
-
printf("Audio started\n");
898
+
StartStaticNoise();
899
+
printf("Audio started with static\n");
740
900
}
741
901
}
742
902
···
744
904
if (g_audio.isPlaying) {
745
905
g_audio.isPlaying = 0;
746
906
StopBassStreaming();
907
+
StopStaticNoise();
747
908
printf("Audio stopped\n");
748
909
}
749
910
}
···
805
966
806
967
// Create BASS stream from URL with more options
807
968
printf("Creating BASS stream...\n");
808
-
g_audio.currentStream = BASS_StreamCreateURL(station->streamUrl, 0,
969
+
g_audio.currentStream = BASS_StreamCreateURL(station->streamUrl, 0,
809
970
BASS_STREAM_BLOCK | BASS_STREAM_STATUS | BASS_STREAM_AUTOFREE, NULL, 0);
810
971
811
972
if (g_audio.currentStream) {
812
973
printf("Successfully connected to stream: %s\n", station->name);
813
-
974
+
814
975
// Get stream info
815
976
BASS_CHANNELINFO info;
816
977
if (BASS_ChannelGetInfo(g_audio.currentStream, &info)) {
817
-
printf("Stream info: %lu Hz, %lu channels, type=%lu\n",
978
+
printf("Stream info: %lu Hz, %lu channels, type=%lu\n",
818
979
info.freq, info.chans, info.ctype);
819
980
}
820
-
981
+
821
982
// Set volume based on signal strength and radio volume
822
983
float volume = g_radio.volume * (g_radio.signalStrength / 100.0f);
823
984
BASS_ChannelSetAttribute(g_audio.currentStream, BASS_ATTRIB_VOL, volume);
824
985
printf("Set volume to: %.2f\n", volume);
825
-
986
+
826
987
// Start playing
827
988
if (BASS_ChannelPlay(g_audio.currentStream, FALSE)) {
828
989
printf("Stream playback started\n");
···
830
991
DWORD error = BASS_ErrorGetCode();
831
992
printf("Failed to start playback (BASS Error: %lu)\n", error);
832
993
}
833
-
994
+
834
995
g_audio.currentStation = station;
835
996
return 1;
836
997
} else {
···
860
1021
g_audio.currentStation = NULL;
861
1022
}
862
1023
1024
+
// Static noise generation callback
1025
+
DWORD CALLBACK StaticStreamProc(HSTREAM handle, void* buffer, DWORD length, void* user) {
1026
+
short* samples = (short*)buffer;
1027
+
DWORD sampleCount = length / sizeof(short);
1028
+
1029
+
// Get current time for oscillation
1030
+
static DWORD startTime = GetTickCount();
1031
+
DWORD currentTime = GetTickCount();
1032
+
float timeSeconds = (currentTime - startTime) / 1000.0f;
1033
+
1034
+
// Create subtle volume oscillations (5-7% variation)
1035
+
// Use multiple sine waves at different frequencies for natural variation
1036
+
float oscillation1 = sin(timeSeconds * 0.7f) * 0.03f; // 3% slow oscillation
1037
+
float oscillation2 = sin(timeSeconds * 2.3f) * 0.02f; // 2% medium oscillation
1038
+
float oscillation3 = sin(timeSeconds * 5.1f) * 0.015f; // 1.5% fast oscillation
1039
+
float volumeVariation = 1.0f + oscillation1 + oscillation2 + oscillation3;
1040
+
1041
+
// Generate white noise with volume variation
1042
+
for (DWORD i = 0; i < sampleCount; i++) {
1043
+
// Generate random value between -32767 and 32767
1044
+
short baseNoise = (short)((rand() % 65535) - 32767);
1045
+
1046
+
// Apply volume variation
1047
+
samples[i] = (short)(baseNoise * volumeVariation);
1048
+
}
1049
+
1050
+
return length;
1051
+
}
1052
+
1053
+
void StartStaticNoise() {
1054
+
if (!g_audio.staticStream) {
1055
+
// Create a stream for static noise generation
1056
+
g_audio.staticStream = BASS_StreamCreate(SAMPLE_RATE, CHANNELS, 0, StaticStreamProc, NULL);
1057
+
1058
+
if (g_audio.staticStream) {
1059
+
// Set initial volume based on signal strength
1060
+
UpdateStaticVolume(g_radio.signalStrength);
1061
+
1062
+
// Start playing static
1063
+
BASS_ChannelPlay(g_audio.staticStream, FALSE);
1064
+
printf("Static noise started\n");
1065
+
} else {
1066
+
printf("Failed to create static stream\n");
1067
+
}
1068
+
}
1069
+
}
1070
+
1071
+
void StopStaticNoise() {
1072
+
if (g_audio.staticStream) {
1073
+
BASS_StreamFree(g_audio.staticStream);
1074
+
g_audio.staticStream = 0;
1075
+
printf("Static noise stopped\n");
1076
+
}
1077
+
}
1078
+
1079
+
void UpdateStaticVolume(float signalStrength) {
1080
+
if (g_audio.staticStream) {
1081
+
// Static volume is inverse of signal strength
1082
+
// Strong signal = less static, weak signal = more static
1083
+
float staticLevel = (100.0f - signalStrength) / 100.0f;
1084
+
float volume = g_radio.volume * staticLevel * g_audio.staticVolume;
1085
+
1086
+
// Ensure minimum static when radio is on but no strong signal
1087
+
if (g_radio.power && signalStrength < 50.0f) {
1088
+
volume = fmax(volume, g_radio.volume * 0.1f);
1089
+
}
1090
+
1091
+
BASS_ChannelSetAttribute(g_audio.staticStream, BASS_ATTRIB_VOL, volume);
1092
+
}
1093
+
}
1094
+
1095
+
void UpdateVULevels() {
1096
+
// Initialize levels to zero
1097
+
g_audio.vuLevelLeft = 0.0f;
1098
+
g_audio.vuLevelRight = 0.0f;
1099
+
1100
+
// Get levels from current stream if playing
1101
+
if (g_audio.currentStream && BASS_ChannelIsActive(g_audio.currentStream) == BASS_ACTIVE_PLAYING) {
1102
+
DWORD level = BASS_ChannelGetLevel(g_audio.currentStream);
1103
+
if (level != -1) {
1104
+
// Extract left and right channel levels
1105
+
g_audio.vuLevelLeft = (float)LOWORD(level) / 32768.0f;
1106
+
g_audio.vuLevelRight = (float)HIWORD(level) / 32768.0f;
1107
+
}
1108
+
}
1109
+
1110
+
// Add static contribution if static is playing
1111
+
if (g_audio.staticStream && BASS_ChannelIsActive(g_audio.staticStream) == BASS_ACTIVE_PLAYING) {
1112
+
DWORD staticLevel = BASS_ChannelGetLevel(g_audio.staticStream);
1113
+
if (staticLevel != -1) {
1114
+
float staticLeft = (float)LOWORD(staticLevel) / 32768.0f;
1115
+
float staticRight = (float)HIWORD(staticLevel) / 32768.0f;
1116
+
1117
+
// Combine with existing levels (simulate mixing)
1118
+
g_audio.vuLevelLeft = fmin(1.0f, g_audio.vuLevelLeft + staticLeft * 0.3f);
1119
+
g_audio.vuLevelRight = fmin(1.0f, g_audio.vuLevelRight + staticRight * 0.3f);
1120
+
}
1121
+
}
1122
+
1123
+
// Apply some smoothing/decay for more realistic VU behavior
1124
+
static float lastLeft = 0.0f, lastRight = 0.0f;
1125
+
g_audio.vuLevelLeft = g_audio.vuLevelLeft * 0.7f + lastLeft * 0.3f;
1126
+
g_audio.vuLevelRight = g_audio.vuLevelRight * 0.7f + lastRight * 0.3f;
1127
+
lastLeft = g_audio.vuLevelLeft;
1128
+
lastRight = g_audio.vuLevelRight;
1129
+
}