The C/C++/Objective-C/Objective-C++ Programming Languages
The C/C++/Objective-C/Objective-C++ Compiler Architecture and Processor Architecture Relationship. Understanding compiler architecture is vital for high-performance engineering. Because C and C++ are compiled languages, the code you write is translated directly into machine instructions that the processor's circuit board understands. This "close to the metal" approach is what allows for the real-time processing of complex periodic waveforms and stochastic signals.
The C Programming Language
The C programming language is a powerful and efficient language that has been widely used for system programming, embedded systems, and performance-critical applications. It provides low-level access to memory and hardware, making it ideal for tasks that require direct manipulation of resources. C is also the foundation for many other programming languages.
/* Show me how to read an existing AIF file using portsf so I can apply these filters to
an actual recording?
Reading an existing file is a slightly different process because you have to "ask" the
library for the file's properties (sample rate, number of channels, etc.) before you start
processing.
Richard Dobson's portsf library is excellent for this because it treats AIFF and WAV files
almost identically once they are opened. The library handles the conversion from the
file's native format (like 24-bit AIFF) into a float buffer for you automatically.
AIFF Filter Processor
This program opens an existing AIFF file, applies the One-Pole Low-Pass Filter we just
built, and saves the result to a new file. */
#include
#include
#include
#define BLOCK_SIZE 1024
int main(int argc, char* argv[]) {
PSF_PROPS props;
int ifd = -1, ofd = -1;
float *buffer = NULL;
// Filter State
double last_sample_l = 0.0, last_sample_r = 0.0;
double filter_coeff = 0.1; // Adjust for "muffled-ness"
if (argc < 3) {
printf("Usage: %s input.aif output.wav\n", argv[0]);
return 1;
}
if (psf_init()) return 1;
// 1. Open the input file
ifd = psf_sndOpen(argv[1], &props, 0);
if (ifd < 0) {
printf("Error: Could not open input file %s\n", argv[1]);
goto cleanup;
}
// 2. Setup the output file using the SAME properties as the input
// We can change the format to WAV here if we want
props.format = PSF_WAVE_EX;
ofd = psf_sndCreate(argv[2], &props, 0, 0, PSF_CREATE_RDWR);
if (ofd < 0) {
printf("Error: Could not create output file %s\n", argv[2]);
goto cleanup;
}
// Allocate buffer based on the number of channels in the source file
buffer = (float*)malloc(BLOCK_SIZE * props.chans * sizeof(float));
long frames_read;
printf("Processing: %s (%dHz, %d channels)...\n", argv[1], props.srate, props.chans);
// 3. The Processing Loop
while ((frames_read = psf_sndReadFrames(ifd, buffer, BLOCK_SIZE)) > 0) {
for (int i = 0; i < frames_read; i++) {
if (props.chans == 2) {
// Stereo Filtering
float left = buffer[i * 2];
float right = buffer[i * 2 + 1];
left = last_sample_l + (float)(filter_coeff * (left - last_sample_l));
right = last_sample_r + (float)(filter_coeff * (right - last_sample_r));
last_sample_l = left;
last_sample_r = right;
buffer[i * 2] = left;
buffer[i * 2 + 1] = right;
} else {
// Mono Filtering
float mono = buffer[i];
mono = last_sample_l + (float)(filter_coeff * (mono - last_sample_l));
last_sample_l = mono;
buffer[i] = mono;
}
}
psf_sndWriteFrames(ofd, buffer, frames_read);
}
printf("Done! Filtered audio saved to %s\n", argv[2]);
cleanup:
if (ifd >= 0) psf_sndClose(ifd);
if (ofd >= 0) psf_sndClose(ofd);
if (buffer) free(buffer);
psf_finish();
return 0;
}
/* Key Differences When Reading Files
psf_sndOpen
Unlike psf_sndCreate, which requires you to define the sample rate, psf_sndOpen populates
the PSF_PROPS structure for you based on the file's header. This is crucial because it
tells you if the file is 44.1kHz or 48kHz and how many channels it has.
Sample Type Conversion
One of the best features of portsf is that it handles the bit-depth conversion. Even if
your AIFF is a 24-bit file, psf_sndReadFrames converts it to normalized floating-point
(−1.0 to 1.0). This allows your filter math to work regardless of the original file's
format.
Handling Variable Channels
The code above checks props.chans. If you try to process a stereo file with mono logic (or
vice-versa), you will either get a "stuttering" sound or a crash. Always use the chans
variable from the input properties to drive your loop indexing.
Performance Tip
If you find the filter isn't "strong" enough on a real recording, you can cascade the
filters. Simply take the output of the first filter and run it through a second
(identical) filter block. This creates a "Two-Pole" filter with a much steeper volume
drop-off for high frequencies. */
The C++ Programming Language
The C++ programming language is an extension of C that adds object-oriented programming features, as well as support for generic programming and other modern programming paradigms. C++ is widely used in software development, game development, and performance-critical applications. It allows developers to write code that is both efficient and maintainable.
/* To turn raw PCM data into a standard .WAV file, we need to
prepend a 44-byte header. This header tells media players the format, sample rate, and bit
depth so they don't have to guess.
Here is the updated code. I've encapsulated the WAV header logic into a struct and used
to uniquely name the file based on the current system time. */
#include
#include
#include
#include
#include
#include
#include
#include
// Using to define our math constants
using PiRatio = std::ratio<314159, 100000>; // Approximation of Pi
struct WavHeader {
char riff[4] = {'R', 'I', 'F', 'F'};
uint32_t fileSize;
char wave[4] = {'W', 'A', 'V', 'E'};
char fmt[4] = {'f', 'm', 't', ' '};
uint32_t fmtSize = 16;
uint16_t audioFormat = 1; // PCM
uint16_t numChannels = 1; // Mono
uint32_t sampleRate = 44100;
uint32_t byteRate = 44100 * 2;
uint16_t blockAlign = 2;
uint16_t bitsPerSample = 16;
char data[4] = {'d', 'a', 't', 'a'};
uint32_t dataSize;
};
int main() {
const int sampleRate = 44100;
const double duration = 3.0;
const int totalSamples = static_cast(sampleRate * duration);
const double frequency = 440.0;
// 1. Use to create a unique filename based on timestamp
auto now = std::chrono::system_clock::now();
auto timestamp = std::chrono::duration_cast(now.time_since_epoch()).count();
std::string filename = "audio" + std::to_string(timestamp) + ".wav";
// 2. Setup for a "white noise" burst at the start
std::mt19937 rng(static_cast(timestamp));
std::uniform_real_distribution noiseDist(-0.1, 0.1);
std::vector buffer;
buffer.reserve(totalSamples);
// 3. Generate Audio Logic
const double PI = static_cast(PiRatio::num) / PiRatio::den;
for (int i = 0; i < totalSamples; ++i) {
double t = static_cast(i) / sampleRate;
// Sine wave + random noise
double sample = std::sin(2.0 * PI * frequency * t);
sample += noiseDist(rng) * std::exp(-t * 5.0); // Noise decays quickly
buffer.push_back(static_cast(sample * 32767));
}
// 4. Initialize Header
WavHeader header;
header.dataSize = buffer.size() * sizeof(int16_t);
header.fileSize = header.dataSize + sizeof(WavHeader) - 8;
// 5. Write to File
std::ofstream out(filename, std::ios::binary);
if (out) {
out.write(reinterpret_cast(&header), sizeof(WavHeader));
out.write(reinterpret_cast(buffer.data()), header.dataSize);
std::cout << "Successfully generated: " << filename << std::endl;
}
return 0;
}
The Objective-C Programming Language
Objective-C and Objective-C++ are extensions of C and C++ that add object-oriented programming capabilities. They are primarily used for macOS and iOS development, making them relevant for projects that involve multimedia applications on Apple platforms. Objective-C is a dynamic language that allows for runtime flexibility.
2. The Implementation File (AppDelegate.mm) This is where the Objective-C++ magic happens. Notice the inclusion of a C++ standard library header (<iostream>) and the use of a C++ class alongside Cocoa's NSWindow.
#import "CustomView.h"
@implementation CustomView
- (instancetype)initWithFrame:(NSRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initial color
_circleColor = [NSColor systemBlueColor];
// 1. Create the Button
NSButton *colorButton = [NSButton buttonWithTitle:@"Change Circle Color"
target:self
action:@selector(changeColor:)];
// 2. Position the button at the bottom center
CGFloat btnWidth = 160;
CGFloat btnHeight = 32;
[colorButton setFrame:NSMakeRect((frame.size.width - btnWidth) / 2,
100, // 100 points from the bottom
btnWidth,
btnHeight)];
// 3. Set button style
[colorButton setBezelStyle:NSBezelStyleRounded];
[self addSubview:colorButton];
}
return self;
}
// This method runs when the button is clicked
- (void)changeColor:(id)sender {
// Toggle between Blue and Green
if ([self.circleColor isEqual:[NSColor systemBlueColor]]) {
self.circleColor = [NSColor systemGreenColor];
} else {
self.circleColor = [NSColor systemBlueColor];
}
// IMPORTANT: Tell AppKit the view needs to be redrawn
[self setNeedsDisplay:YES];
}
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
[[NSColor windowBackgroundColor] setFill];
NSRectFill(dirtyRect);
// Use the dynamic circleColor property
[self.circleColor setStroke];
CGFloat size = 200.0;
NSRect circleRect = NSMakeRect((self.bounds.size.width - size) / 2,
(self.bounds.size.height - size) / 2,
size, size);
NSBezierPath *path = [NSBezierPath bezierPathWithOvalInRect:circleRect];
[path setLineWidth:5.0];
[path stroke];
}
// Keep the button centered if the window is resized/full-screened
- (void)layout {
[super layout];
for (NSView *subview in self.subviews) {
if ([subview isKindOfClass:[NSButton class]]) {
NSRect newFrame = subview.frame;
newFrame.origin.x = (self.bounds.size.width - newFrame.size.width) / 2;
[subview setFrame:newFrame];
}
}
}
@end
The Objective-C++ Programming Language
The Objective-C++ programming language is a hybrid of Objective-C and C++. It allows developers to combine the object-oriented features of Objective-C with the performance and flexibility of C++. This makes it particularly useful for multimedia applications that require both high performance and the ability to leverage the rich Apple frameworks.
Can I get Objective-C++ .mm files (and related .h files) for the construction of a simple macOS App Xcode project? Creating a macOS app using Objective-C++ (.mm) is a great way to bridge the gap between high-level Cocoa frameworks and powerful C++ libraries. In this setup, the .mm extension tells the compiler to treat the file as Objective-C++, allowing you to mix C++ objects and syntax directly with Objective-C. Below is a foundational structure for a programmatic macOS app (no Storyboards or XIBs) using a standard Header and implementation file. 1. The Header File (AppDelegate.h) This file defines the interface for your application delegate. Note that we use standard Objective-C syntax here so it remains compatible with the rest of the Cocoa system. Objective-C
#import <Cocoa/Cocoa.h>
@interface AppDelegate : NSObject
@property (strong, nonatomic) NSWindow *window;
@end
2. The Implementation File (AppDelegate.mm)
This is where the Objective-C++ magic happens. Notice the inclusion of a C++ standard library header (#import "AppDelegate.h"
#include <iostream> // Standard C++ header
#include <vector>
// A simple C++ class defined within the .mm file
class Particle {
public:
void logStatus() {
std::cout << "C++ Particle object is active." << std::endl;
}
};
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// 1. Trigger C++ Logic
Particle p;
p.logStatus();
// 2. Setup the UI
NSRect frame = NSMakeRect(0, 0, 480, 270);
self.window = [[NSWindow alloc] initWithContentRect:frame
styleMask:(NSWindowStyleMaskTitled |
NSWindowStyleMaskClosable |
NSWindowStyleMaskResizable)
backing:NSBackingStoreBuffered
defer:NO];
[self.window setTitle:@"My Objective-C++ App"];
[self.window makeKeyAndOrderFront:nil];
NSLog(@"Cocoa Window has been initialized.");
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert cleanup code here
}
@end
3. The Entry Point (main.mm)
In an Objective-C++ project, your main file should also use the .mm extension if you plan to initialize C++ globals or use C++ logic during startup.
#import <Cocoa/Cocoa.h>
#import "AppDelegate.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSApplication *app = [NSApplication sharedApplication];
AppDelegate *delegate = [[AppDelegate alloc] init];
[app setDelegate:delegate];
[app run];
}
return 0;
}
Key Configurations in Xcode
To make this work in a fresh Xcode project, ensure the following:
File Extensions: Ensure your implementation files are strictly .mm. If they remain .m, the compiler will throw errors the moment it encounters a C++ keyword like class or std::vector.
CLANG_CXX_LANGUAGE_STANDARD: In Build Settings, search for "C++ Language Standard." It is usually best to set this to C++20 or GNU++20 for modern features.
CLANG_CXX_LIBRARY: Ensure this is set to libc++ (the default for macOS).
Common Pitfall: The "Incompatible Header"
If you include a C++ header in your .h file, any other .m (pure Objective-C) file that imports that header will fail to compile.
Solution: Keep C++ includes inside the .mm file or wrap them in #ifdef __cplusplus guards.
Would you like me to show you how to wrap a specific C++ library (like OpenCV or a custom physics engine) so it can be used by an Objective-C View Controller?