Browse Source

Puts the generation logic in a seperate file. Adds stereo

master
Joshua Moerman 11 years ago
parent
commit
5ee2bee289
  1. 6
      SpectogramPrototype.xcodeproj/project.pbxproj
  2. 2
      SpectogramPrototype/AudioFile.h
  3. 15
      SpectogramPrototype/AudioFile.m
  4. 16
      SpectogramPrototype/Spectographer.h
  5. 78
      SpectogramPrototype/Spectographer.m
  6. 55
      SpectogramPrototype/ViewController.m

6
SpectogramPrototype.xcodeproj/project.pbxproj

@ -29,6 +29,7 @@
426665BC1869EF4B005D62AC /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 426665BB1869EF4B005D62AC /* CoreAudio.framework */; }; 426665BC1869EF4B005D62AC /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 426665BB1869EF4B005D62AC /* CoreAudio.framework */; };
426665C11869F194005D62AC /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 426665C01869F194005D62AC /* AudioToolbox.framework */; }; 426665C11869F194005D62AC /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 426665C01869F194005D62AC /* AudioToolbox.framework */; };
426665C51869F50B005D62AC /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 426665C41869F50B005D62AC /* MediaPlayer.framework */; }; 426665C51869F50B005D62AC /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 426665C41869F50B005D62AC /* MediaPlayer.framework */; };
42ABF54B187035F900B20D82 /* Spectographer.m in Sources */ = {isa = PBXBuildFile; fileRef = 42ABF54A187035F900B20D82 /* Spectographer.m */; };
42E12A91186F122400866CB3 /* testMusic.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 42E12A90186F122400866CB3 /* testMusic.mp3 */; }; 42E12A91186F122400866CB3 /* testMusic.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 42E12A90186F122400866CB3 /* testMusic.mp3 */; };
42E12A94186F1F4C00866CB3 /* AudioFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 42E12A93186F1F4C00866CB3 /* AudioFile.m */; }; 42E12A94186F1F4C00866CB3 /* AudioFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 42E12A93186F1F4C00866CB3 /* AudioFile.m */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
@ -73,6 +74,8 @@
426665BB1869EF4B005D62AC /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; }; 426665BB1869EF4B005D62AC /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; };
426665C01869F194005D62AC /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; 426665C01869F194005D62AC /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
426665C41869F50B005D62AC /* MediaPlayer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaPlayer.framework; path = System/Library/Frameworks/MediaPlayer.framework; sourceTree = SDKROOT; }; 426665C41869F50B005D62AC /* MediaPlayer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaPlayer.framework; path = System/Library/Frameworks/MediaPlayer.framework; sourceTree = SDKROOT; };
42ABF549187035F900B20D82 /* Spectographer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Spectographer.h; sourceTree = "<group>"; };
42ABF54A187035F900B20D82 /* Spectographer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Spectographer.m; sourceTree = "<group>"; };
42E12A90186F122400866CB3 /* testMusic.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = testMusic.mp3; sourceTree = "<group>"; }; 42E12A90186F122400866CB3 /* testMusic.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = testMusic.mp3; sourceTree = "<group>"; };
42E12A92186F1F4C00866CB3 /* AudioFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioFile.h; sourceTree = "<group>"; }; 42E12A92186F1F4C00866CB3 /* AudioFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioFile.h; sourceTree = "<group>"; };
42E12A93186F1F4C00866CB3 /* AudioFile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AudioFile.m; sourceTree = "<group>"; }; 42E12A93186F1F4C00866CB3 /* AudioFile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AudioFile.m; sourceTree = "<group>"; };
@ -150,6 +153,8 @@
424F84BD18661F8000687D3B /* Main_iPad.storyboard */, 424F84BD18661F8000687D3B /* Main_iPad.storyboard */,
424F84C018661F8000687D3B /* ViewController.h */, 424F84C018661F8000687D3B /* ViewController.h */,
424F84C118661F8000687D3B /* ViewController.m */, 424F84C118661F8000687D3B /* ViewController.m */,
42ABF549187035F900B20D82 /* Spectographer.h */,
42ABF54A187035F900B20D82 /* Spectographer.m */,
42E12A92186F1F4C00866CB3 /* AudioFile.h */, 42E12A92186F1F4C00866CB3 /* AudioFile.h */,
42E12A93186F1F4C00866CB3 /* AudioFile.m */, 42E12A93186F1F4C00866CB3 /* AudioFile.m */,
426665B31869A7CC005D62AC /* RuledScrollView.h */, 426665B31869A7CC005D62AC /* RuledScrollView.h */,
@ -293,6 +298,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
42E12A94186F1F4C00866CB3 /* AudioFile.m in Sources */, 42E12A94186F1F4C00866CB3 /* AudioFile.m in Sources */,
42ABF54B187035F900B20D82 /* Spectographer.m in Sources */,
426665B81869CEFE005D62AC /* FFTTest.m in Sources */, 426665B81869CEFE005D62AC /* FFTTest.m in Sources */,
424F84C218661F8000687D3B /* ViewController.m in Sources */, 424F84C218661F8000687D3B /* ViewController.m in Sources */,
424F84B918661F8000687D3B /* AppDelegate.m in Sources */, 424F84B918661F8000687D3B /* AppDelegate.m in Sources */,

2
SpectogramPrototype/AudioFile.h

@ -16,6 +16,6 @@
+ (AudioFile*) audioFileFromURL:(NSURL*) url; + (AudioFile*) audioFileFromURL:(NSURL*) url;
// Reads nSamples of data (left channel), return actual number of samples read // Reads nSamples of data (left channel), return actual number of samples read
- (unsigned int) fillArray:(float*)array withNumberOfSamples:(unsigned int)nSamples; - (unsigned int) fillLeft:(float*)left andRight:(float*)right withNumberOfSamples:(unsigned int)nSamples;
@end @end

15
SpectogramPrototype/AudioFile.m

@ -62,7 +62,7 @@
#pragma mark #pragma mark
#pragma mark Usage #pragma mark Usage
- (unsigned int)fillArray:(float *)array withNumberOfSamples:(unsigned int)nSamples{ - (unsigned int)fillLeft:(float *)left andRight:(float *)right withNumberOfSamples:(unsigned int)nSamples {
AudioBufferList bufferList; AudioBufferList bufferList;
bufferList.mNumberBuffers = 1; bufferList.mNumberBuffers = 1;
bufferList.mBuffers[0].mNumberChannels = 2; bufferList.mBuffers[0].mNumberChannels = 2;
@ -74,15 +74,16 @@
assert(err == 0); assert(err == 0);
short * buffer = bufferList.mBuffers[0].mData; short * buffer = bufferList.mBuffers[0].mData;
float * end = array + nSamples; float * leftEnd = left + nSamples;
for(unsigned int i = 0; i < nFrames; ++i){ for(unsigned int i = 0; i < nFrames; ++i){
*array++ = *buffer++ / 32768.0; *left++ = *buffer++ / 32768.0;
// skip right channel *right++ = *buffer++ / 32768.0;
buffer++;
} }
while(array != end){ // assume left and right are of the same size
*array++ = 0.0; while(left != leftEnd){
*left++ = 0.0;
*right++ = 0.0;
} }
free(bufferList.mBuffers[0].mData); free(bufferList.mBuffers[0].mData);

16
SpectogramPrototype/Spectographer.h

@ -0,0 +1,16 @@
//
// Spectographer.h
// SpectogramPrototype
//
// Created by Joshua Moerman on 29/12/13.
// Copyright (c) 2013 Joshua Moerman. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface Spectographer : NSObject
- (void)openAudioFile:(NSURL*)url;
- (CGImageRef)generate;
@end

78
SpectogramPrototype/Spectographer.m

@ -0,0 +1,78 @@
//
// Spectographer.m
// SpectogramPrototype
//
// Created by Joshua Moerman on 29/12/13.
// Copyright (c) 2013 Joshua Moerman. All rights reserved.
//
#import "Spectographer.h"
#import "FFTTest.h"
#import "AudioFile.h"
UInt8 clamp_to_uint8(float x){
if(x >= 1.0) return 255;
if(x <= 0.0) return 0;
return 255.0 * x;
}
@interface Spectographer (){
FFTTest * FFTHandler;
AudioFile * audioFile;
float * left;
float * right;
}
@end
@implementation Spectographer
- (id)init{
if(self = [super init]){
FFTHandler = [[FFTTest alloc] init];
left = calloc(FFTHandler.acceptedSize, sizeof(float));
right = calloc(FFTHandler.acceptedSize, sizeof(float));
}
return self;
}
- (void)openAudioFile:(NSURL *)url{
audioFile = [AudioFile audioFileFromURL: url];
assert(audioFile);
}
- (CGImageRef)generate{
unsigned int size = FFTHandler.acceptedSize;
unsigned int width = size/4;
unsigned int height = size/8;
char * rgba = calloc(width*height*4, sizeof(char));
for(unsigned int x = 0; x < width; ++x){
[audioFile fillLeft:left andRight:right withNumberOfSamples:size];
[FFTHandler inPlaceFFT:left forSize:size];
[FFTHandler inPlaceFFT:right forSize:size];
for(unsigned int y = 0; y < height; ++y){
unsigned int yy = height - y - 1;
rgba[4*width*yy + 4*x + 0] = clamp_to_uint8(100.0 * left[y]);
rgba[4*width*yy + 4*x + 1] = clamp_to_uint8(100.0 * right[y]);
rgba[4*width*yy + 4*x + 2] = clamp_to_uint8(10.0 * (left[y] + right[y]));
rgba[4*width*yy + 4*x + 3] = 0;
}
}
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
assert(colorSpace);
CGContextRef bitmapContext = CGBitmapContextCreate(rgba, width, height, 8, 4*width, colorSpace, (CGBitmapInfo)kCGImageAlphaNoneSkipLast);
assert(bitmapContext);
CGImageRef cgImage = CGBitmapContextCreateImage(bitmapContext);
assert(cgImage);
CGContextRelease(bitmapContext);
CGColorSpaceRelease(colorSpace);
free(rgba);
return cgImage;
}
@end

55
SpectogramPrototype/ViewController.m

@ -11,8 +11,7 @@
#import "ViewController.h" #import "ViewController.h"
#import "RuledScrollView.h" #import "RuledScrollView.h"
#import "FFTTest.h" #import "Spectographer.h"
#import "AudioFile.h"
typedef enum { typedef enum {
iPad, iPad,
@ -38,16 +37,9 @@ device get_device(){
return device; return device;
} }
UInt8 clamp_to_uint8(float x){
if(x >= 1.0) return 255;
if(x <= 0.0) return 0;
return 255.0 * x;
}
@interface ViewController () <MPMediaPickerControllerDelegate> { @interface ViewController () <MPMediaPickerControllerDelegate> {
Spectographer * spectographer;
UIPopoverController * pop; UIPopoverController * pop;
FFTTest * fft_handler;
float * data;
} }
- (void) openAudioFile:(NSURL*)filePath; - (void) openAudioFile:(NSURL*)filePath;
@property (nonatomic, strong) UILabel* header; @property (nonatomic, strong) UILabel* header;
@ -73,51 +65,22 @@ UInt8 clamp_to_uint8(float x){
} }
- (void)openAudioFile:(NSURL *)filePath{ - (void)openAudioFile:(NSURL *)filePath{
AudioFile * audioFile = [AudioFile audioFileFromURL:filePath]; if(!spectographer)
spectographer = [[Spectographer alloc] init];
if(!fft_handler)
fft_handler = [[FFTTest alloc] init];
unsigned int size = fft_handler.acceptedSize;
unsigned int width = size/4;
unsigned int height = size/8;
if(!data) [spectographer openAudioFile:filePath];
data = calloc(size, sizeof(float)); CGImageRef image = [spectographer generate];
char * rgba = calloc(width*height*4, sizeof(char));
for(unsigned int x = 0; x < width; ++x){
[audioFile fillArray:data withNumberOfSamples:size];
[fft_handler inPlaceFFT:data forSize:size];
for(unsigned int y = 0; y < height; ++y){
unsigned int yy = height - y - 1;
rgba[4*width*yy + 4*x + 0] = clamp_to_uint8(100.0 * data[y]);
rgba[4*width*yy + 4*x + 1] = clamp_to_uint8(50.0 * data[y]);
rgba[4*width*yy + 4*x + 2] = clamp_to_uint8(10.0 * data[y]);
rgba[4*width*yy + 4*x + 3] = 0;
}
}
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); UIImage * newUIImage = [UIImage imageWithCGImage:image];
assert(colorSpace);
CGContextRef bitmapContext = CGBitmapContextCreate(rgba, width, height, 8, 4*width, colorSpace, (CGBitmapInfo)kCGImageAlphaNoneSkipLast);
assert(bitmapContext);
CGImageRef cgImage = CGBitmapContextCreateImage(bitmapContext);
assert(cgImage);
UIImage * newUIImage = [UIImage imageWithCGImage:cgImage];
assert(newUIImage); assert(newUIImage);
CGColorSpaceRelease(colorSpace); CGImageRelease(image);
CGContextRelease(bitmapContext);
CGImageRelease(cgImage);
free(rgba);
UIImageView * view = [[UIImageView alloc] initWithImage:newUIImage]; UIImageView * view = [[UIImageView alloc] initWithImage:newUIImage];
view.frame = CGRectMake(0, 0, width, height);
[contentView removeFromSuperview]; [contentView removeFromSuperview];
contentView = view; contentView = view;
scrollView.zoomScale = 1.0;
[scrollView.content addSubview:contentView]; [scrollView.content addSubview:contentView];
contentView.autoresizingMask = UIViewAutoresizingNone; contentView.autoresizingMask = UIViewAutoresizingNone;