Browse Source

Added FFT sound visualization

Thomas Buck 8 years ago
parent
commit
66aba82c33
6 changed files with 219 additions and 28 deletions
  1. 7
    0
      CaseLights/AppDelegate.h
  2. 20
    26
      CaseLights/AppDelegate.m
  3. 186
    0
      CaseLights/AudioVisualizer.m
  4. 1
    1
      CaseLights/Info.plist
  5. 3
    1
      CaseLights/Serial.m
  6. 2
    0
      README.md

+ 7
- 0
CaseLights/AppDelegate.h View File

15
 
15
 
16
 @interface AppDelegate : NSObject <NSApplicationDelegate, EZMicrophoneDelegate>
16
 @interface AppDelegate : NSObject <NSApplicationDelegate, EZMicrophoneDelegate>
17
 
17
 
18
+@property (weak) IBOutlet NSApplication *application;
19
+
20
+@property (strong) EZMicrophone *microphone;
21
+
18
 - (void)clearDisplayUI;
22
 - (void)clearDisplayUI;
19
 - (void)updateDisplayUI:(NSArray *)displayIDs;
23
 - (void)updateDisplayUI:(NSArray *)displayIDs;
20
 
24
 
21
 - (void)setLightsR:(unsigned char)r G:(unsigned char)g B:(unsigned char)b;
25
 - (void)setLightsR:(unsigned char)r G:(unsigned char)g B:(unsigned char)b;
22
 
26
 
27
++ (double)map:(double)val FromMin:(double)fmin FromMax:(double)fmax ToMin:(double)tmin ToMax:(double)tmax;
28
++ (void)convertH:(double)h S:(double)s V:(double)v toR:(unsigned char *)r G:(unsigned char *)g B:(unsigned char *)b;
29
+
23
 @end
30
 @end
24
 
31
 

+ 20
- 26
CaseLights/AppDelegate.m View File

64
 @interface AppDelegate ()
64
 @interface AppDelegate ()
65
 
65
 
66
 @property (weak) IBOutlet NSMenu *statusMenu;
66
 @property (weak) IBOutlet NSMenu *statusMenu;
67
-@property (weak) IBOutlet NSApplication *application;
68
 
67
 
69
 @property (weak) IBOutlet NSMenu *menuColors;
68
 @property (weak) IBOutlet NSMenu *menuColors;
70
 @property (weak) IBOutlet NSMenu *menuAnimations;
69
 @property (weak) IBOutlet NSMenu *menuAnimations;
89
 @property (strong) NSTimer *animation;
88
 @property (strong) NSTimer *animation;
90
 @property (strong) Serial *serial;
89
 @property (strong) Serial *serial;
91
 @property (strong) NSMenuItem *lastLEDMode;
90
 @property (strong) NSMenuItem *lastLEDMode;
92
-@property (strong) EZMicrophone *microphone;
93
 
91
 
94
 @end
92
 @end
95
 
93
 
880
     [application orderFrontStandardAboutPanel:self];
878
     [application orderFrontStandardAboutPanel:self];
881
 }
879
 }
882
 
880
 
883
-- (void)updateBuffer:(float *)buffer withBufferSize:(UInt32)bufferSize {
884
-    if (microphone == nil) {
885
-        return; // Old buffer from before we changed mode
886
-    }
887
-    
888
-    [AudioVisualizer updateBuffer:buffer withBufferSize:bufferSize];
889
-}
890
-
891
 // ------------------------------------------------------
881
 // ------------------------------------------------------
892
 // ----------------- Microphone Delegate ----------------
882
 // ----------------- Microphone Delegate ----------------
893
 // ------------------------------------------------------
883
 // ------------------------------------------------------
903
     // EZAudioPlot, EZAudioPlotGL, or whatever visualization you would like to do with
893
     // EZAudioPlot, EZAudioPlotGL, or whatever visualization you would like to do with
904
     // the microphone data.
894
     // the microphone data.
905
     dispatch_async(dispatch_get_main_queue(),^{
895
     dispatch_async(dispatch_get_main_queue(),^{
896
+        if (weakSelf.microphone == nil) {
897
+            return;
898
+        }
899
+        
906
         // buffer[0] = left channel, buffer[1] = right channel
900
         // buffer[0] = left channel, buffer[1] = right channel
907
-        [weakSelf updateBuffer:buffer[0] withBufferSize:bufferSize];
901
+        [AudioVisualizer updateBuffer:buffer[0] withBufferSize:bufferSize];
908
     });
902
     });
909
 }
903
 }
910
 
904
 
956
     if ([GPUStats getGPUUsage:&usage freeVRAM:&freeVRAM usedVRAM:&usedVRAM] != 0) {
950
     if ([GPUStats getGPUUsage:&usage freeVRAM:&freeVRAM usedVRAM:&usedVRAM] != 0) {
957
         NSLog(@"Error reading GPU information\n");
951
         NSLog(@"Error reading GPU information\n");
958
     } else {
952
     } else {
959
-        double h = [self map:[usage doubleValue] FromMin:0.0 FromMax:100.0 ToMin:GPU_COLOR_MIN ToMax:GPU_COLOR_MAX];
953
+        double h = [AppDelegate map:[usage doubleValue] FromMin:0.0 FromMax:100.0 ToMin:GPU_COLOR_MIN ToMax:GPU_COLOR_MAX];
960
         
954
         
961
 #ifdef DEBUG
955
 #ifdef DEBUG
962
         NSLog(@"GPU Usage: %.3f%%\n", [usage doubleValue]);
956
         NSLog(@"GPU Usage: %.3f%%\n", [usage doubleValue]);
963
 #endif
957
 #endif
964
         
958
         
965
         unsigned char r, g, b;
959
         unsigned char r, g, b;
966
-        [self convertH:h S:1.0 V:1.0 toR:&r G:&g B:&b];
960
+        [AppDelegate convertH:h S:1.0 V:1.0 toR:&r G:&g B:&b];
967
         [self setLightsR:r G:g B:b];
961
         [self setLightsR:r G:g B:b];
968
     }
962
     }
969
 }
963
 }
975
     if ([GPUStats getGPUUsage:&usage freeVRAM:&freeVRAM usedVRAM:&usedVRAM] != 0) {
969
     if ([GPUStats getGPUUsage:&usage freeVRAM:&freeVRAM usedVRAM:&usedVRAM] != 0) {
976
         NSLog(@"Error reading GPU information\n");
970
         NSLog(@"Error reading GPU information\n");
977
     } else {
971
     } else {
978
-        double h = [self map:[freeVRAM doubleValue] FromMin:0.0 FromMax:([freeVRAM doubleValue] + [usedVRAM doubleValue]) ToMin:RAM_COLOR_MIN ToMax:RAM_COLOR_MAX];
972
+        double h = [AppDelegate map:[freeVRAM doubleValue] FromMin:0.0 FromMax:([freeVRAM doubleValue] + [usedVRAM doubleValue]) ToMin:RAM_COLOR_MIN ToMax:RAM_COLOR_MAX];
979
         
973
         
980
 #ifdef DEBUG
974
 #ifdef DEBUG
981
         NSLog(@"VRAM %.2fGB Free + %.2fGB Used = %.2fGB mapped to color %.2f!\n", [freeVRAM doubleValue] / (1024.0 * 1024.0 * 1024.0), [usedVRAM doubleValue] / (1024.0 * 1024.0 * 1024.0), ([freeVRAM doubleValue] + [usedVRAM doubleValue]) / (1024.0 * 1024.0 * 1024.0), h);
975
         NSLog(@"VRAM %.2fGB Free + %.2fGB Used = %.2fGB mapped to color %.2f!\n", [freeVRAM doubleValue] / (1024.0 * 1024.0 * 1024.0), [usedVRAM doubleValue] / (1024.0 * 1024.0 * 1024.0), ([freeVRAM doubleValue] + [usedVRAM doubleValue]) / (1024.0 * 1024.0 * 1024.0), h);
982
 #endif
976
 #endif
983
         
977
         
984
         unsigned char r, g, b;
978
         unsigned char r, g, b;
985
-        [self convertH:h S:1.0 V:1.0 toR:&r G:&g B:&b];
979
+        [AppDelegate convertH:h S:1.0 V:1.0 toR:&r G:&g B:&b];
986
         [self setLightsR:r G:g B:b];
980
         [self setLightsR:r G:g B:b];
987
     }
981
     }
988
 }
982
 }
990
 - (void)visualizeCPUUsage:(NSTimer *)timer {
984
 - (void)visualizeCPUUsage:(NSTimer *)timer {
991
     JSKMCPUUsageInfo cpuUsageInfo = [JSKSystemMonitor systemMonitor].cpuUsageInfo;
985
     JSKMCPUUsageInfo cpuUsageInfo = [JSKSystemMonitor systemMonitor].cpuUsageInfo;
992
     
986
     
993
-    double h = [self map:cpuUsageInfo.usage FromMin:0.0 FromMax:100.0 ToMin:CPU_COLOR_MIN ToMax:CPU_COLOR_MAX];
987
+    double h = [AppDelegate map:cpuUsageInfo.usage FromMin:0.0 FromMax:100.0 ToMin:CPU_COLOR_MIN ToMax:CPU_COLOR_MAX];
994
     
988
     
995
 #ifdef DEBUG
989
 #ifdef DEBUG
996
     NSLog(@"CPU Usage: %.3f%%\n", cpuUsageInfo.usage);
990
     NSLog(@"CPU Usage: %.3f%%\n", cpuUsageInfo.usage);
997
 #endif
991
 #endif
998
     
992
     
999
     unsigned char r, g, b;
993
     unsigned char r, g, b;
1000
-    [self convertH:h S:1.0 V:1.0 toR:&r G:&g B:&b];
994
+    [AppDelegate convertH:h S:1.0 V:1.0 toR:&r G:&g B:&b];
1001
     [self setLightsR:r G:g B:b];
995
     [self setLightsR:r G:g B:b];
1002
 }
996
 }
1003
 
997
 
1004
 - (void)visualizeRAMUsage:(NSTimer *)timer {
998
 - (void)visualizeRAMUsage:(NSTimer *)timer {
1005
     JSKMMemoryUsageInfo memoryUsageInfo = [JSKSystemMonitor systemMonitor].memoryUsageInfo;
999
     JSKMMemoryUsageInfo memoryUsageInfo = [JSKSystemMonitor systemMonitor].memoryUsageInfo;
1006
     
1000
     
1007
-    double h = [self map:memoryUsageInfo.freeMemory FromMin:0.0 FromMax:(memoryUsageInfo.usedMemory + memoryUsageInfo.freeMemory) ToMin:RAM_COLOR_MIN ToMax:RAM_COLOR_MAX];
1001
+    double h = [AppDelegate map:memoryUsageInfo.freeMemory FromMin:0.0 FromMax:(memoryUsageInfo.usedMemory + memoryUsageInfo.freeMemory) ToMin:RAM_COLOR_MIN ToMax:RAM_COLOR_MAX];
1008
     
1002
     
1009
 #ifdef DEBUG
1003
 #ifdef DEBUG
1010
     NSLog(@"RAM %.2fGB Free + %.2fGB Used = %.2fGB mapped to color %.2f!\n", memoryUsageInfo.freeMemory / (1024.0 * 1024.0 * 1024.0), memoryUsageInfo.usedMemory / (1024.0 * 1024.0 * 1024.0), (memoryUsageInfo.freeMemory + memoryUsageInfo.usedMemory) / (1024.0 * 1024.0 * 1024.0), h);
1004
     NSLog(@"RAM %.2fGB Free + %.2fGB Used = %.2fGB mapped to color %.2f!\n", memoryUsageInfo.freeMemory / (1024.0 * 1024.0 * 1024.0), memoryUsageInfo.usedMemory / (1024.0 * 1024.0 * 1024.0), (memoryUsageInfo.freeMemory + memoryUsageInfo.usedMemory) / (1024.0 * 1024.0 * 1024.0), h);
1011
 #endif
1005
 #endif
1012
     
1006
     
1013
     unsigned char r, g, b;
1007
     unsigned char r, g, b;
1014
-    [self convertH:h S:1.0 V:1.0 toR:&r G:&g B:&b];
1008
+    [AppDelegate convertH:h S:1.0 V:1.0 toR:&r G:&g B:&b];
1015
     [self setLightsR:r G:g B:b];
1009
     [self setLightsR:r G:g B:b];
1016
 }
1010
 }
1017
 
1011
 
1031
         temp = GPU_TEMP_MIN;
1025
         temp = GPU_TEMP_MIN;
1032
     }
1026
     }
1033
     
1027
     
1034
-    double h = [self map:temp FromMin:GPU_TEMP_MIN FromMax:GPU_TEMP_MAX ToMin:GPU_COLOR_MIN ToMax:GPU_COLOR_MAX];
1028
+    double h = [AppDelegate map:temp FromMin:GPU_TEMP_MIN FromMax:GPU_TEMP_MAX ToMin:GPU_COLOR_MIN ToMax:GPU_COLOR_MAX];
1035
     
1029
     
1036
 #ifdef DEBUG
1030
 #ifdef DEBUG
1037
     NSLog(@"GPU Temp %.2f mapped to color %.2f!\n", temp, h);
1031
     NSLog(@"GPU Temp %.2f mapped to color %.2f!\n", temp, h);
1038
 #endif
1032
 #endif
1039
     
1033
     
1040
     unsigned char r, g, b;
1034
     unsigned char r, g, b;
1041
-    [self convertH:h S:1.0 V:1.0 toR:&r G:&g B:&b];
1035
+    [AppDelegate convertH:h S:1.0 V:1.0 toR:&r G:&g B:&b];
1042
     [self setLightsR:r G:g B:b];
1036
     [self setLightsR:r G:g B:b];
1043
 }
1037
 }
1044
 
1038
 
1058
         temp = CPU_TEMP_MIN;
1052
         temp = CPU_TEMP_MIN;
1059
     }
1053
     }
1060
     
1054
     
1061
-    double h = [self map:temp FromMin:CPU_TEMP_MIN FromMax:CPU_TEMP_MAX ToMin:CPU_COLOR_MIN ToMax:CPU_COLOR_MAX];
1055
+    double h = [AppDelegate map:temp FromMin:CPU_TEMP_MIN FromMax:CPU_TEMP_MAX ToMin:CPU_COLOR_MIN ToMax:CPU_COLOR_MAX];
1062
     
1056
     
1063
 #ifdef DEBUG
1057
 #ifdef DEBUG
1064
     NSLog(@"CPU Temp %.2f mapped to color %.2f!\n", temp, h);
1058
     NSLog(@"CPU Temp %.2f mapped to color %.2f!\n", temp, h);
1065
 #endif
1059
 #endif
1066
     
1060
     
1067
     unsigned char r, g, b;
1061
     unsigned char r, g, b;
1068
-    [self convertH:h S:1.0 V:1.0 toR:&r G:&g B:&b];
1062
+    [AppDelegate convertH:h S:1.0 V:1.0 toR:&r G:&g B:&b];
1069
     [self setLightsR:r G:g B:b];
1063
     [self setLightsR:r G:g B:b];
1070
 }
1064
 }
1071
 
1065
 
1103
     }
1097
     }
1104
     
1098
     
1105
     unsigned char r, g, b;
1099
     unsigned char r, g, b;
1106
-    [self convertH:h S:1.0 V:1.0 toR:&r G:&g B:&b];
1100
+    [AppDelegate convertH:h S:1.0 V:1.0 toR:&r G:&g B:&b];
1107
     [self setLightsR:r G:g B:b];
1101
     [self setLightsR:r G:g B:b];
1108
 }
1102
 }
1109
 
1103
 
1115
 // --------------------- Utilities ---------------------
1109
 // --------------------- Utilities ---------------------
1116
 // -----------------------------------------------------
1110
 // -----------------------------------------------------
1117
 
1111
 
1118
-- (double)map:(double)val FromMin:(double)fmin FromMax:(double)fmax ToMin:(double)tmin ToMax:(double)tmax {
1112
++ (double)map:(double)val FromMin:(double)fmin FromMax:(double)fmax ToMin:(double)tmin ToMax:(double)tmax {
1119
     double norm = (val - fmin) / (fmax - fmin);
1113
     double norm = (val - fmin) / (fmax - fmin);
1120
     return (norm * (tmax - tmin)) + tmin;
1114
     return (norm * (tmax - tmin)) + tmin;
1121
 }
1115
 }
1122
 
1116
 
1123
-- (void)convertH:(double)h S:(double)s V:(double)v toR:(unsigned char *)r G:(unsigned char *)g B:(unsigned char *)b {
1117
++ (void)convertH:(double)h S:(double)s V:(double)v toR:(unsigned char *)r G:(unsigned char *)g B:(unsigned char *)b {
1124
     // Adapted from:
1118
     // Adapted from:
1125
     // https://gist.github.com/hdznrrd/656996
1119
     // https://gist.github.com/hdznrrd/656996
1126
     
1120
     

+ 186
- 0
CaseLights/AudioVisualizer.m View File

2
 //  AudioVisualizer.m
2
 //  AudioVisualizer.m
3
 //  CaseLights
3
 //  CaseLights
4
 //
4
 //
5
+//  Based on the ideas in:
6
+//  http://archive.gamedev.net/archive/reference/programming/features/beatdetection/
7
+//
8
+//  The detected sound frequency of beats will be mapped to the hue of the resulting color,
9
+//  the variance of the beat is mapped to the brightness of the color. The colors
10
+//  of all detected beats will be added together to form the final displayed color.
11
+//
5
 //  Created by Thomas Buck on 01.01.16.
12
 //  Created by Thomas Buck on 01.01.16.
6
 //  Copyright © 2016 xythobuz. All rights reserved.
13
 //  Copyright © 2016 xythobuz. All rights reserved.
7
 //
14
 //
8
 
15
 
16
+// Enabling this will cause crashes when changing audio input
17
+// devices while the app is running. Select it before enabling.
18
+#define DEBUG_PLOT_FFT
19
+//#define DEBUG_PLOT_FFT_RAW
20
+
21
+#define DEBUG_LOG_BEATS
22
+
9
 #import "AudioVisualizer.h"
23
 #import "AudioVisualizer.h"
10
 #import "AppDelegate.h"
24
 #import "AppDelegate.h"
11
 
25
 
26
+#import "EZAudioFFT.h"
27
+
28
+#ifdef DEBUG_PLOT_FFT
29
+#import "EZAudioPlot.h"
30
+#endif
31
+
32
+// Parameters for fine-tuning beat detection
33
+#define FFT_BUCKET_COUNT 64
34
+#define FFT_BUCKET_HISTORY 43
35
+#define FFT_C_FACTOR 4.2
36
+#define FFT_V0_FACTOR 0.000015
37
+#define FFT_MAX_V0_COLOR 0.0002
38
+#define FFT_COLOR_DECAY 0.99
39
+
40
+// Factors for nicer debug display
41
+#define FFT_DEBUG_RAW_FACTOR 42.0
42
+#define FFT_DEBUG_FACTOR 230.0
43
+
12
 static AppDelegate *appDelegate = nil;
44
 static AppDelegate *appDelegate = nil;
45
+static EZAudioFFT *fft = nil;
46
+static int maxBufferSize = 0;
13
 
47
 
14
 @implementation AudioVisualizer
48
 @implementation AudioVisualizer
15
 
49
 
18
 }
52
 }
19
 
53
 
20
 + (void)updateBuffer:(float *)buffer withBufferSize:(UInt32)bufferSize {
54
 + (void)updateBuffer:(float *)buffer withBufferSize:(UInt32)bufferSize {
55
+    // Create Fast Fourier Transformation object
56
+    if (fft == nil) {
57
+        maxBufferSize = bufferSize;
58
+        fft = [EZAudioFFT fftWithMaximumBufferSize:maxBufferSize sampleRate:appDelegate.microphone.audioStreamBasicDescription.mSampleRate];
59
+        
60
+#ifdef DEBUG
61
+        NSLog(@"Created FFT with max. freq.: %.2f\n", appDelegate.microphone.audioStreamBasicDescription.mSampleRate / 2);
62
+#endif
63
+    }
64
+    
65
+    // Check for changing buffer sizes
66
+    if (bufferSize > maxBufferSize) {
67
+        NSLog(@"Buffer Size changed?! %d != %d\n", maxBufferSize, bufferSize);
68
+        maxBufferSize = bufferSize;
69
+        fft = [EZAudioFFT fftWithMaximumBufferSize:maxBufferSize sampleRate:appDelegate.microphone.audioStreamBasicDescription.mSampleRate];
70
+    }
71
+    
72
+    [fft computeFFTWithBuffer:buffer withBufferSize:bufferSize];
73
+    
74
+    static float history[FFT_BUCKET_COUNT][FFT_BUCKET_HISTORY];
75
+    static int nextHistory =  0;
76
+    static int samplesPerBucket = 0;
77
+    
78
+    // Initialize static variables
79
+    if (samplesPerBucket == 0) {
80
+        samplesPerBucket = bufferSize / FFT_BUCKET_COUNT;
81
+        for (int i = 0; i < FFT_BUCKET_COUNT; i++) {
82
+            for (int j = 0; j < FFT_BUCKET_HISTORY; j++) {
83
+                history[i][j] = 0.5f;
84
+            }
85
+        }
86
+    }
87
+    
88
+    // Split FFT output into a small number of 'buckets' or 'bins' and add to circular history buffer
89
+    for (int i = 0; i < FFT_BUCKET_COUNT; i++) {
90
+        float sum = 0.0f;
91
+        for (int j = 0; j < samplesPerBucket; j++) {
92
+            sum += fft.fftData[(i + samplesPerBucket) + j];
93
+        }
94
+        history[i][nextHistory] = sum / samplesPerBucket;
95
+    }
96
+    
97
+#ifdef DEBUG_PLOT_FFT
98
+    int beatCount = 0;
99
+#endif
100
+    
101
+    static unsigned char lastRed = 0, lastGreen = 0, lastBlue = 0;
102
+    lastRed = lastRed * FFT_COLOR_DECAY;
103
+    lastGreen = lastGreen * FFT_COLOR_DECAY;
104
+    lastBlue = lastBlue * FFT_COLOR_DECAY;
105
+    
106
+    // Check for any beats
107
+    for (int i = 0; i < FFT_BUCKET_COUNT; i++) {
108
+        float average = 0.0f;
109
+        for (int j = 0; j < FFT_BUCKET_HISTORY; j++) {
110
+            average += history[i][j];
111
+        }
112
+        average /= FFT_BUCKET_HISTORY;
113
+        float v = 0.0f;
114
+        for (int j = 0; j < FFT_BUCKET_HISTORY; j++) {
115
+            float tmp = history[i][j] - average;
116
+            tmp *= tmp;
117
+            v += tmp;
118
+        }
119
+        v /= FFT_BUCKET_HISTORY;
120
+        if ((history[i][nextHistory] > (FFT_C_FACTOR * average)) && (v > FFT_V0_FACTOR)) {
121
+            // Found a beat on this frequency band, map to a single color
122
+            if (v < FFT_V0_FACTOR) v = FFT_V0_FACTOR;
123
+            if (v > FFT_MAX_V0_COLOR) v = FFT_MAX_V0_COLOR;
124
+            float bright = [AppDelegate map:v FromMin:FFT_V0_FACTOR FromMax:FFT_MAX_V0_COLOR ToMin:0.0 ToMax:100.0];
125
+            float hue = [AppDelegate map:i FromMin:0.0 FromMax:FFT_BUCKET_COUNT ToMin:0.0 ToMax:360.0];
126
+            unsigned char r, g, b;
127
+            [AppDelegate convertH:hue S:1.0 V:bright toR:&r G:&g B:&b];
128
+            
129
+            // Blend with last color using averaging
130
+            int tmpR = (lastRed + r) / 2;
131
+            int tmpG = (lastGreen + g) / 2;
132
+            int tmpB = (lastBlue + b) / 2;
133
+            lastRed = tmpR;
134
+            lastGreen = tmpG;
135
+            lastBlue = tmpB;
136
+            
137
+#ifdef DEBUG_LOG_BEATS
138
+            NSLog(@"Beat in %d with c: %f v: %f", i, (history[i][nextHistory] / average), v);
139
+#endif
140
+#ifdef DEBUG_PLOT_FFT
141
+            beatCount++;
142
+#endif
143
+        }
144
+    }
145
+    
146
+    [appDelegate setLightsR:lastRed G:lastGreen B:lastBlue];
147
+
148
+#ifdef DEBUG_PLOT_FFT
149
+    static NSWindow *window = nil;
150
+    static EZAudioPlot *plot = nil;
151
+    static NSTextField *label = nil;
152
+    if ((window == nil) || (plot == nil) || (label == nil)) {
153
+        NSRect frame = NSMakeRect(450, 300, 600, 400);
154
+        window = [[NSWindow alloc] initWithContentRect:frame
155
+                                             styleMask:NSClosableWindowMask | NSTitledWindowMask | NSBorderlessWindowMask
156
+                                               backing:NSBackingStoreBuffered
157
+                                                 defer:NO];
158
+        [window setTitle:@"Debug FFT"];
159
+        
160
+        plot = [[EZAudioPlot alloc] initWithFrame:window.contentView.frame];
161
+        plot.color = [NSColor whiteColor];
162
+        plot.shouldOptimizeForRealtimePlot = NO; // Not working with 'YES' here?!
163
+        plot.shouldFill = YES;
164
+        plot.shouldCenterYAxis = NO;
165
+        plot.shouldMirror = NO;
166
+        plot.plotType = EZPlotTypeBuffer;
167
+        [window.contentView addSubview:plot];
168
+        
169
+        label = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 380, 600, 20)];
170
+        [label setTextColor:[NSColor whiteColor]];
171
+        [label setEditable:NO];
172
+        [label setBezeled:NO];
173
+        [label setDrawsBackground:NO];
174
+        [label setSelectable:NO];
175
+        [label setStringValue:@"-"];
176
+        [window.contentView addSubview:label];
177
+        
178
+        [window makeKeyAndOrderFront:appDelegate.application];
179
+        NSLog(@"Created debugging FFT Plot window...\n");
180
+    }
181
+    
182
+    // Scale so we can see something
183
+# ifdef DEBUG_PLOT_FFT_RAW
184
+    memcpy(buffer, fft.fftData, bufferSize * sizeof(float));
185
+    for (UInt32 i = 0; i < bufferSize; i++) {
186
+        buffer[i] *= FFT_DEBUG_RAW_FACTOR;
187
+# else
188
+    for (int i = 0; i < FFT_BUCKET_COUNT; i++) {
189
+        buffer[i] = history[i][nextHistory];
190
+    }
191
+    for (UInt32 i = 0; i < FFT_BUCKET_COUNT; i++) {
192
+        buffer[i] *= FFT_DEBUG_FACTOR;
193
+# endif
194
+        if (buffer[i] > 1.0f) buffer[i] = 1.0f;
195
+        if (buffer[i] < -1.0f) buffer[i] = -1.0f;
196
+    }
197
+    [plot updateBuffer:buffer withBufferSize:bufferSize];
21
     
198
     
199
+    [window setBackgroundColor:[NSColor colorWithCalibratedRed:lastRed / 255.0 green:lastGreen / 255.0 blue:lastBlue / 255.0 alpha:1.0]];
200
+    [label setStringValue:[NSString stringWithFormat:@"Beats: %d", beatCount]];
201
+#endif
202
+        
203
+    // Point to next history buffer
204
+    nextHistory++;
205
+    if (nextHistory >= FFT_BUCKET_HISTORY) {
206
+        nextHistory = 0;
207
+    }
22
 }
208
 }
23
 
209
 
24
 @end
210
 @end

+ 1
- 1
CaseLights/Info.plist View File

21
 	<key>CFBundleSignature</key>
21
 	<key>CFBundleSignature</key>
22
 	<string>????</string>
22
 	<string>????</string>
23
 	<key>CFBundleVersion</key>
23
 	<key>CFBundleVersion</key>
24
-	<string>182</string>
24
+	<string>359</string>
25
 	<key>LSApplicationCategoryType</key>
25
 	<key>LSApplicationCategoryType</key>
26
 	<string>public.app-category.utilities</string>
26
 	<string>public.app-category.utilities</string>
27
 	<key>LSMinimumSystemVersion</key>
27
 	<key>LSMinimumSystemVersion</key>

+ 3
- 1
CaseLights/Serial.m View File

9
 //  Copyright © 2015 xythobuz. All rights reserved.
9
 //  Copyright © 2015 xythobuz. All rights reserved.
10
 //
10
 //
11
 
11
 
12
+//#define DEBUG_TEXT
13
+
12
 #import <Cocoa/Cocoa.h>
14
 #import <Cocoa/Cocoa.h>
13
 #import <IOKit/IOKitLib.h>
15
 #import <IOKit/IOKitLib.h>
14
 #import <IOKit/serial/IOSerialKeys.h>
16
 #import <IOKit/serial/IOSerialKeys.h>
155
     const char *data = [string UTF8String];
157
     const char *data = [string UTF8String];
156
     size_t length = strlen(data);
158
     size_t length = strlen(data);
157
     
159
     
158
-#ifdef DEBUG
160
+#ifdef DEBUG_TEXT
159
     NSLog(@"Sending string %s", data);
161
     NSLog(@"Sending string %s", data);
160
 #endif
162
 #endif
161
     
163
     

+ 2
- 0
README.md View File

22
 
22
 
23
 You can also select one of the displays connected to the Host machine. The CaseLights App will then create a Screenshot of this display 10-times per second and calculate the average color to display it on the RGB LEDs.
23
 You can also select one of the displays connected to the Host machine. The CaseLights App will then create a Screenshot of this display 10-times per second and calculate the average color to display it on the RGB LEDs.
24
 
24
 
25
+CaseLights is also able to visualize sound coming from a system audio input. To be able to directly visualize the system sound output, install [Soundflower](https://github.com/mattingalls/Soundflower) and create a Multi-Output-Device in the Mac `Audio Midi Setup.app` consisting of `Soundflower (2ch)` and your normally used output device. Set this device as audio output. Then, in CaseLights, select `Soundflower (2ch)` as input.
26
+
25
 ## Working with Git Submodules
27
 ## Working with Git Submodules
26
 
28
 
27
 To clone this repository, enter the following:
29
 To clone this repository, enter the following:

Loading…
Cancel
Save