A Node.js client library for communicating with Calrec audio consoles using the CSCP (Calrec Serial Control Protocol). This library provides a robust, type-safe interface for basic control and monitoring of Calrec mixing consoles over TCP/IP.
- 🔌 TCP/IP Communication - Connect to Calrec consoles over network
- 🎛️ Basic Console Control - Control faders, mutes, routing, and more
- 📡 Real-time Monitoring - Receive live updates from the console
- 🔄 Auto-reconnection - Automatic reconnection on connection loss
- 🛡️ Type Safety - Full TypeScript support with detailed type definitions
- 🎯 Event-driven - Clean event-based API for state changes
- 📊 Unit Conversion - Built-in dB/level conversion utilities
- ⚙️ Configurable Timing - Runtime-configurable protocol timing settings
- 🚀 Async/Await - Modern async API with robust error handling
This library implements a subset of the Calrec CSCP protocol, providing control over:
- Fader Control: Level, mute (cut), PFL, and labels
- Main Fader Control: Level, PFL, and labels for main outputs
- Auxiliary Routing: Route channels to auxiliary outputs (V20+ consoles)
- Main Routing: Route channels to main outputs (V21+ consoles)
- Stereo Image Control: Configure stereo image settings (V21+ consoles)
- Console Information: Get console details and protocol version
Note: This is not a complete console control solution. Calrec consoles offer many more features and capabilities that are not covered by this protocol implementation. This library provides a solid foundation for basic control and monitoring tasks.
npm install @bitfocusas/calrec-cscp
import { CalrecClient } from '@bitfocusas/calrec-cscp';
// Create a client instance with custom settings
const client = new CalrecClient(
{
host: '192.168.1.100', // Your Calrec console IP
port: 3322, // Your configured TCP port
maxFaderCount: 42, // Maximum number of faders (1-192)
maxMainCount: 3, // Maximum number of main outputs (optional, default: 3)
autoReconnect: true,
reconnectInterval: 5000,
},
{
// Optional: Custom protocol timing settings
globalCommandRateMs: 10, // Minimum ms between any command
faderLevelRateMs: 100, // Minimum ms between fader level commands
commandResponseTimeoutMs: 20, // Timeout for command responses
}
);
// Set up event listeners
client.on('ready', async () => {
console.log('Connected and ready!');
// Example: Update settings at runtime
client.updateSettings({
faderLevelRateMs: 50, // Faster fader updates
});
});
client.on('faderLevelChange', (faderId, level) => {
console.log(`Fader ${faderId} level changed to ${level}`);
});
client.on('error', (error) => {
console.error('Connection error:', error);
});
// Connect to the console (now async)
await client.connect();
import { CalrecClient } from '@bitfocusas/calrec-cscp';
const client = new CalrecClient({
host: '192.168.1.100',
port: 3322,
maxFaderCount: 42, // Maximum number of faders (1-192)
maxMainCount: 3, // Maximum number of main outputs (optional, default: 3)
});
client.on('ready', async () => {
try {
// Get console information (optional - console may not respond)
try {
const consoleInfo = await client.getConsoleInfo();
console.log('Console:', consoleInfo.deskLabel);
console.log('Max faders:', consoleInfo.maxFaders);
} catch (error) {
console.log('Console info not available, using configured values');
}
// Get configured fader count
const maxFaders = client.getMaxFaderCount();
console.log('Configured max faders:', maxFaders);
// Set fader level (0-1023 range)
await client.setFaderLevel(1, 500);
// Set fader level in dB
await client.setFaderLevelDb(1, -10);
// Mute/unmute a fader
await client.setFaderCut(1, true);
// Get fader label
const label = await client.getFaderLabel(1);
console.log('Fader 1 label:', label);
} catch (error) {
console.error('Operation failed:', error);
}
});
// Connect to the console
await client.connect();
client.on('ready', async () => {
try {
// Set aux routing (route fader 1 to aux 1 and 2)
await client.setAuxRouting(1, [true, true, false, false]);
// Set stereo image for a fader
await client.setStereoImage(1, { leftToBoth: true, rightToBoth: false });
// Get fader assignment
const assignment = await client.getFaderAssignment(1);
console.log('Fader 1 assignment:', assignment);
} catch (error) {
console.error('Routing operation failed:', error);
}
});
// Monitor aux routing changes
client.on('auxRoutingChange', (auxId, routes) => {
console.log(`Aux ${auxId} routing changed:`, routes);
});
// Monitor all fader changes
client.on('faderLevelChange', (faderId, level) => {
console.log(`Fader ${faderId}: ${level}`);
});
client.on('faderCutChange', (faderId, isCut) => {
console.log(`Fader ${faderId} ${isCut ? 'muted' : 'unmuted'}`);
});
client.on('faderLabelChange', (faderId, label) => {
console.log(`Fader ${faderId} label: ${label}`);
});
client.on('faderAssignmentChange', (assignment) => {
console.log('Fader assignment changed:', assignment);
});
client.on('stereoImageChange', (faderId, image) => {
console.log(`Fader ${faderId} stereo image:`, image);
});
// Monitor connection state
client.on('connectionStateChange', (state) => {
console.log('Connection state:', state);
});
client.on('connect', () => {
console.log('Connected to console');
});
client.on('disconnect', () => {
console.log('Disconnected from console');
});
// Manual disconnect (now async)
await client.disconnect();
// Error handling
client.on('error', (error) => {
console.error('Client error:', error.message);
});
// Handle errors in async operations
try {
await client.setFaderLevel(1, 500);
} catch (error) {
if (error.message.includes('NAK')) {
console.error('Protocol error - command rejected by console');
} else if (error.message.includes('timeout')) {
console.error('Command timed out');
} else if (error.message.includes('not connected')) {
console.error('Client is not connected');
} else {
console.error('Unexpected error:', error);
}
}
The main client class for communicating with Calrec consoles. This client provides access to a subset of the console's capabilities through the CSCP protocol.
new CalrecClient(options: CalrecClientOptions, settings?: CalrecClientSettings)
Options:
host: string
- Console IP addressport: number
- TCP port numberautoReconnect?: boolean
- Enable auto-reconnection (default: true)reconnectInterval?: number
- Reconnection delay in ms (default: 5000)maxFaderCount?: number
- Maximum number of faders (for validation)
Settings:
globalCommandRateMs?: number
- Minimum ms between any command (default: 10)faderLevelRateMs?: number
- Minimum ms between fader level commands (default: 100)commandResponseTimeoutMs?: number
- Timeout for command responses (default: 20)
connect(): Promise<void>
- Connect to the consoledisconnect(): Promise<void>
- Disconnect from the consolegetState(): ClientState
- Get current client stategetConnectionState(): ConnectionState
- Get connection stateupdateSettings(settings: CalrecClientSettings): void
- Update protocol settings at runtime
getConsoleInfo(): Promise<ConsoleInfo>
- Get console informationgetConsoleName(): Promise<string>
- Get console name
setFaderLevel(faderId: number, level: number): Promise<void>
- Set fader level (0-1023)getFaderLevel(faderId: number): Promise<number>
- Get fader levelsetFaderLevelDb(faderId: number, db: number): Promise<void>
- Set fader level in dBgetFaderLevelDb(faderId: number): Promise<number>
- Get fader level in dBsetFaderCut(faderId: number, isCut: boolean): Promise<void>
- Mute/unmute fadergetFaderCut(faderId: number): Promise<boolean>
- Get fader cut stategetFaderLabel(faderId: number): Promise<string>
- Get fader labelsetFaderPfl(faderId: number, isPfl: boolean): Promise<void>
- Set fader PFL stategetFaderPfl(faderId: number): Promise<boolean>
- Get fader PFL stategetFaderAssignment(faderId: number): Promise<FaderAssignment>
- Get fader assignment
setMainFaderLevelDb(mainId: number, db: number): Promise<void>
- Set main fader level in dBgetMainFaderLevelDb(mainId: number): Promise<number>
- Get main fader level in dBsetMainFaderPfl(mainId: number, isPfl: boolean): Promise<void>
- Set main fader PFL stategetMainPfl(mainId: number): Promise<boolean>
- Get main fader PFL stategetMainFaderLabel(mainId: number): Promise<string>
- Get main fader label
getAvailableAux(): Promise<boolean[]>
- Get available auxiliary outputssetAuxRouting(auxId: number, routes: boolean[]): Promise<void>
- Set aux routinggetAuxSendRouting(auxId: number): Promise<boolean[]>
- Get aux routingsetAuxOutputLevel(auxId: number, level: number): Promise<void>
- Set aux output levelgetAuxOutputLevel(auxId: number): Promise<number>
- Get aux output level
getAvailableMains(): Promise<boolean[]>
- Get available main outputssetRouteToMain(mainId: number, routes: boolean[]): Promise<void>
- Set main routing
setStereoImage(faderId: number, image: StereoImage): Promise<void>
- Set stereo imagegetStereoImage(faderId: number): Promise<StereoImage>
- Get stereo image
The client extends EventEmitter and provides the following events:
connect
- Connected to consoledisconnect
- Disconnected from consoleready
- Client fully initialized and readyerror
- Connection or protocol errorconnectionStateChange
- Connection state changed
faderLevelChange
- Fader level changedfaderCutChange
- Fader mute state changedfaderPflChange
- Fader PFL state changedfaderLabelChange
- Fader label changedfaderAssignmentChange
- Fader assignment changed
mainLevelChange
- Main fader level changedmainPflChange
- Main fader PFL state changedmainLabelChange
- Main fader label changed
availableAuxesChange
- Available auxes changedauxRoutingChange
- Aux routing changedauxOutputLevelChange
- Aux output level changed
availableMainsChange
- Available mains changedmainRoutingChange
- Main routing changed
stereoImageChange
- Stereo image settings changed
unsolicitedMessage
- Raw unsolicited message received (only for truly unknown commands)
The library includes an examples script that demonstrates the available functionality organized by protocol levels:
# Show help
npm run examples -- --help
# Run all examples (default)
npm run examples
# Run only basic commands (V1)
npm run examples -- --level v1
# Run V1 + V20 commands
npm run examples -- --level v20
# Run V1 + V20 + V21 commands
npm run examples -- --level v21
# Use custom console settings
npm run examples -- --host 192.168.1.100 --port 1338
The examples are organized by protocol levels:
- V1: Basic commands (all consoles)
- V20: V1 + Auxiliary send routing extensions
- V21: V20 + Channel/Group routing to mains extensions
Note: The examples script includes event handling for unsolicited messages from the console, providing real-time feedback on state changes while minimizing debug noise.
The library exports detailed TypeScript types:
import {
ConnectionState,
CalrecClientOptions,
CalrecClientSettings,
ConsoleInfo,
FaderAssignment,
AudioType,
AudioWidth,
StereoImage,
NakError,
ClientState,
ParsedMessage,
CalrecClientEvents
} from '@bitfocusas/calrec-cscp';
Utility functions for converting between different units:
import {
dbToChannelLevel,
dbToMainLevel,
channelLevelToDb,
mainLevelToDb
} from '@bitfocusas/calrec-cscp';
- Configure your Calrec console to enable CSCP over TCP/IP
- Set the appropriate IP address and port
- Ensure network connectivity between your application and the console
The library allows you to configure protocol timing for optimal performance:
const client = new CalrecClient(
{ host: '192.168.1.100', port: 3322 },
{
globalCommandRateMs: 10, // Minimum ms between any command
faderLevelRateMs: 100, // Minimum ms between fader level commands
commandResponseTimeoutMs: 20, // Timeout for command responses
}
);
// Update settings at runtime
client.updateSettings({
faderLevelRateMs: 50, // Faster fader updates
});
- TCP/IP connectivity to the console
- Port access (typically 3322, but configurable)
- Stable network connection for reliable operation
The library provides detailed error handling with informative error messages:
client.on('error', (error) => {
console.error('Client error:', error.message);
});
// Handle specific error types
try {
await client.setFaderLevel(1, 500);
} catch (error) {
if (error.message.includes('NAK')) {
console.error('Protocol error - command rejected by console');
} else if (error.message.includes('timeout')) {
console.error('Command timed out');
} else if (error.message.includes('not connected')) {
console.error('Client is not connected');
} else {
console.error('Unexpected error:', error);
}
}
git clone https://github.com/bitfocusas/calrec-cscp.git
cd calrec-cscp
npm install
npm run build
npm run dev
npm run lint # Lint code
npm run format # Format code
npm run check # Run all checks
The library includes both unit tests and integration tests. Integration tests require a physical Calrec console for full testing.
We welcome contributions! This library is provided free of charge by Bitfocus AS to the audio community as a useful tool for basic Calrec console control.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature
) - Make your changes
- Add tests if applicable
- Run the linter and formatter (
npm run check
) - Commit your changes (
git commit -m 'Add amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
- Follow the existing code style (enforced by Biome)
- Add TypeScript types for all new features
- Include JSDoc comments for public APIs
- Test your changes thoroughly
- Update documentation as needed
This project is licensed under the MIT License - see the LICENSE file for details.
- Issues: GitHub Issues
- Documentation: This README and inline code documentation
- Email: william@bitfocus.io
Note: This is a community project. While we strive to help with issues, support is provided on a best-effort basis.
- Calrec Audio for the CSCP protocol specification
- All contributors who help improve this library
- The audio community for feedback and testing
Made with ❤️ by Bitfocus AS