Setup and context
In modern application development, high-quality sound design is a significant competitive advantage. However, creating professional music and sound effects traditionally requires hiring audio engineers or composers—a time-consuming and expensive process.
Suno AI is an AI-powered service that generates realistic music from text descriptions, and when combined with Antigravity, it dramatically streamlines your audio production workflow. This guide walks you through integrating Suno AI with Antigravity, from setup to real-world implementation in web and mobile applications.
What Is Suno AI?
Overview and Capabilities
Suno AI is an AI platform that generates high-quality music from text prompts. Key features include:
- Text-to-Music Generation: Create complete compositions from descriptive prompts
- Multi-Genre Support: Generate rock, pop, classical, ambient, EDM, and many other styles
- Fine-Grained Control: Specify instruments, tempo, vocal style, and other parameters
- API Access: Programmatic integration for automated workflows
Why Antigravity Enhances the Workflow
Antigravity's AI assistance capabilities enable:
- Automatic prompt generation for Suno AI from natural language descriptions
- Batch music generation workflow automation
- Metadata organization and management of generated audio assets
- Intelligent code generation for API integration
Getting Started with Suno AI
Account Setup
# 1. Sign up for Suno AI
# Visit https://www.suno.ai and create an account
# 2. Generate your API key
# Navigate to Dashboard > Settings > API Keys and copy your key
# 3. Store in environment variables
export SUNO_API_KEY="your_api_key_here"Configuring Antigravity for Audio Generation
Craft your system prompt to optimize audio generation:
You are an expert in music and sound design for applications.
Your role is to generate high-quality BGM and sound effects.
When given application requirements:
- Specify genre, tempo, and mood clearly
- Include technical specifications (sample rate, duration)
- Consider licensing and commercial use requirements
- Format requests for the Suno API
Generating Background Music (BGM)
Strategy for Game Applications
Generate BGM for adventure game "Escape Chronicles"
Specifications:
- Genre: Epic Adventure Ambient
- Tempo: 120 BPM
- Duration: 3-minute loopable track
- Instruments: Synthesizers, Percussion
- Vocals: None
- Atmosphere: Mysterious and exciting
Suno Prompt:
"Epic adventure ambient track with mysterious synth layers,
tribal percussion elements, building tension, 120 BPM,
loopable 3-minute composition"Creating Loopable BGM for Productivity Apps
// Generate seamless loop for focus/productivity app
const bgmRequest = {
prompt: "Calm, minimalist ambient background music suitable for focus apps. Soft piano with subtle string pads. 60 BPM, 2-minute loopable composition",
model: "chirp-v3",
duration: 120,
loop: true,
style_preset: "ambient"
};
// Execute generation
async function generateFocusBGM(request) {
const response = await fetch('https://api.suno.ai/v1/generate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.SUNO_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
});
const result = await response.json();
return result.audio_url;
}Creating Sound Effects (SFX)
Effective SFX Prompt Design
Sound effects perform best with concise, specific prompts:
Sound Effect: Button Click
Requirements:
- Type: Digital notification ping
- Duration: 500ms
- Frequency: Bright, high-pitched
- Character: Crisp and responsive
Suno Prompt:
"Bright digital ping sound effect for UI button click,
500ms duration, high frequency, crisp and clear response"Sound Effect Manager Implementation
class SoundEffectManager {
constructor() {
this.sfxCache = new Map();
}
async generateSFX(sfxName, prompt) {
// Check cache first
if (this.sfxCache.has(sfxName)) {
return this.sfxCache.get(sfxName);
}
const response = await fetch('https://api.suno.ai/v1/generate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.SUNO_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
prompt: prompt,
duration: 2, // Max 2 seconds for SFX
model: 'chirp-v3'
})
});
const result = await response.json();
this.sfxCache.set(sfxName, result);
return result;
}
playSFX(sfxName) {
const sfx = this.sfxCache.get(sfxName);
if (sfx) {
const audio = new Audio(sfx.audio_url);
audio.play();
}
}
async preloadAllSFX(sfxDefinitions) {
const promises = sfxDefinitions.map(def =>
this.generateSFX(def.name, def.prompt)
);
await Promise.all(promises);
}
}API Integration and Workflow Automation
Batch Generation with Antigravity
// Use Antigravity to generate comprehensive audio package specification
const batchGenPrompt = `
Generate specifications for a complete mobile game audio package.
For each of the following, create a detailed Suno AI prompt:
1. Main Menu BGM - Uplifting, 3 minutes, loopable
2. Level 1 Background - Ambient, 2 minutes, loopable
3. Victory Sound Effect - Celebratory, 2 seconds
4. Game Over Sound Effect - Dramatic, 3 seconds
5. Coin Pickup - Digital jingle, 0.5 seconds
6. Power-up Activation - Energetic whoosh, 1 second
Format each as JSON with: name, prompt, duration, type
`;
// Process generated prompts through Suno API
async function generateGameAudioPackage(sunoPrompts) {
const audioAssets = [];
for (const item of sunoPrompts) {
try {
const response = await fetch('https://api.suno.ai/v1/generate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.SUNO_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
prompt: item.prompt,
duration: item.duration
})
});
const result = await response.json();
audioAssets.push({
name: item.name,
type: item.type,
url: result.audio_url,
duration: item.duration,
generatedAt: new Date().toISOString()
});
// Respect API rate limits
await new Promise(resolve => setTimeout(resolve, 1500));
} catch (error) {
console.error(`Failed to generate ${item.name}:`, error);
}
}
return audioAssets;
}Asset Metadata Management
class AudioAssetRepository {
async saveAudioAsset(audioData) {
const asset = {
id: crypto.randomUUID(),
name: audioData.name,
type: audioData.type,
duration: audioData.duration,
url: audioData.url,
format: 'mp3',
sampleRate: 48000,
bitrate: '192kbps',
license: 'commercial-use-allowed',
createdAt: new Date().toISOString(),
checksums: {
md5: await calculateMD5(audioData.url)
}
};
// Store in database
await database.audioAssets.insert(asset);
return asset;
}
async generateAudioManifest(projectId) {
const assets = await database.audioAssets.find({ projectId });
return {
projectId,
version: '1.0',
totalAssets: assets.length,
totalDuration: assets.reduce((sum, a) => sum + a.duration, 0),
assets: assets.map(a => ({
id: a.id,
name: a.name,
type: a.type,
url: a.url,
duration: a.duration
})),
exportedAt: new Date().toISOString()
};
}
}Licensing and Legal Considerations
Suno AI Terms of Use
- Commercial Use: Verify that your usage tier permits commercial use
- Attribution: Check if credit attribution is required in your application
- Copyright: Clearly document copyright ownership of generated audio
- Restrictions: Review any geo-restrictions or platform limitations
Pre-Launch Compliance Checklist
## Audio Licensing Compliance
- [ ] Verified commercial use rights with Suno AI plan
- [ ] Documented attribution requirements (if any)
- [ ] Recorded copyright holder information
- [ ] Added license notices to app documentation/settings
- [ ] Reviewed platform-specific audio requirements
- [ ] Established update schedule for audio licenses
- [ ] Tested audio playback on target devices
- [ ] Created fallback audio for license expiration scenariosWeb Application Implementation
React Integration Example
import { useState, useCallback } from 'react';
function AudioGeneratorWidget({ appType }) {
const [audioUrl, setAudioUrl] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
const generateAudio = useCallback(async () => {
setIsLoading(true);
setError(null);
try {
// Call Antigravity to generate optimized prompt
const promptResponse = await fetch('/api/audio-prompts', {
method: 'POST',
body: JSON.stringify({ appType, purpose: 'bgm' })
});
if (!promptResponse.ok) throw new Error('Prompt generation failed');
const { prompt } = await promptResponse.json();
// Call Suno API via backend
const audioResponse = await fetch('/api/audio/generate', {
method: 'POST',
body: JSON.stringify({ prompt })
});
if (!audioResponse.ok) throw new Error('Audio generation failed');
const { audioUrl: url } = await audioResponse.json();
setAudioUrl(url);
} catch (err) {
setError(err.message);
} finally {
setIsLoading(false);
}
}, [appType]);
return (
<div className="audio-generator">
<button
onClick={generateAudio}
disabled={isLoading}
className="btn btn-primary"
>
{isLoading ? 'Generating Audio...' : 'Generate BGM'}
</button>
{error && (
<div className="alert alert-error">{error}</div>
)}
{audioUrl && (
<div className="audio-player">
<audio controls controlsList="nodownload">
<source src={audioUrl} type="audio/mpeg" />
Your browser does not support the audio element.
</audio>
</div>
)}
</div>
);
}
export default AudioGeneratorWidget;Backend API Implementation
// api/audio/generate.js
import { Suno } from '@suno/sdk';
const suno = new Suno({
apiKey: process.env.SUNO_API_KEY
});
export async function POST(request) {
const { prompt } = await request.json();
if (!prompt) {
return new Response(
JSON.stringify({ error: 'Prompt is required' }),
{ status: 400 }
);
}
try {
const generation = await suno.generate({
prompt,
model: 'chirp-v3',
make_instrumental: false
});
// Poll for completion
let result = generation;
let attempts = 0;
const maxAttempts = 30;
while (result.status === 'pending' && attempts < maxAttempts) {
await new Promise(resolve => setTimeout(resolve, 2000));
result = await suno.getGeneration(generation.id);
attempts++;
}
if (result.status !== 'completed') {
throw new Error('Audio generation did not complete in time');
}
return new Response(
JSON.stringify({
audioUrl: result.audio_url,
duration: result.duration,
generatedAt: new Date().toISOString()
}),
{ status: 200, headers: { 'Content-Type': 'application/json' } }
);
} catch (error) {
console.error('Audio generation error:', error);
return new Response(
JSON.stringify({ error: error.message }),
{ status: 500 }
);
}
}Mobile Application Implementation
iOS with SwiftUI
import AVFoundation
import Combine
class AudioService: NSObject, ObservableObject {
@Published var isPlaying = false
@Published var currentAudioUrl: URL?
@Published var isGenerating = false
private var audioPlayer: AVAudioPlayer?
func generateAndPlayBGM(for appType: String) async {
DispatchQueue.main.async {
self.isGenerating = true
}
do {
// Generate prompt via Antigravity
let promptRequest = URLRequest(
url: URL(string: "https://api.antigravity.app/audio-prompts")!
)
// Call Suno API
let audioUrl = try await fetchGeneratedAudio(for: appType)
// Play generated audio
playAudio(from: audioUrl)
DispatchQueue.main.async {
self.currentAudioUrl = audioUrl
self.isGenerating = false
}
} catch {
print("Audio generation error: \(error)")
DispatchQueue.main.async {
self.isGenerating = false
}
}
}
private func playAudio(from url: URL) {
do {
try AVAudioSession.sharedInstance().setCategory(.playback)
audioPlayer = try AVAudioPlayer(contentsOf: url)
audioPlayer?.play()
isPlaying = true
} catch {
print("Playback error: \(error)")
}
}
private func fetchGeneratedAudio(for appType: String) async throws -> URL {
// Implementation to fetch from Suno API
fatalError("Implement Suno API call")
}
func stopPlayback() {
audioPlayer?.stop()
isPlaying = false
}
}
struct AudioPlayerView: View {
@StateObject private var audioService = AudioService()
let appType: String
var body: some View {
VStack(spacing: 20) {
if audioService.isGenerating {
ProgressView("Generating audio...")
} else {
Button(action: {
Task {
await audioService.generateAndPlayBGM(for: appType)
}
}) {
Label("Generate BGM", systemImage: "waveform")
}
.disabled(audioService.isGenerating)
}
if let url = audioService.currentAudioUrl {
HStack {
Button(action: {
audioService.stopPlayback()
}) {
Image(systemName: audioService.isPlaying ? "stop.fill" : "play.fill")
}
Text(audioService.isPlaying ? "Playing..." : "Paused")
.foregroundColor(.secondary)
}
}
}
.padding()
}
}Android with Kotlin
import android.media.MediaPlayer
import kotlinx.coroutines.launch
class AudioViewModel : ViewModel() {
private val _isPlaying = MutableLiveData<Boolean>(false)
val isPlaying: LiveData<Boolean> = _isPlaying
private val _isGenerating = MutableLiveData<Boolean>(false)
val isGenerating: LiveData<Boolean> = _isGenerating
private var mediaPlayer: MediaPlayer? = null
fun generateAndPlayBGM(appType: String) {
viewModelScope.launch {
_isGenerating.value = true
try {
// Generate prompt via Antigravity
val prompt = generateAudioPrompt(appType)
// Get audio from Suno API
val audioUrl = generateSunoAudio(prompt)
// Play audio
playAudio(audioUrl)
_isGenerating.value = false
} catch (e: Exception) {
Log.e("AudioViewModel", "Generation failed", e)
_isGenerating.value = false
}
}
}
private fun playAudio(audioUrl: String) {
mediaPlayer?.release()
mediaPlayer = MediaPlayer().apply {
setDataSource(audioUrl)
prepareAsync()
setOnPreparedListener { mp ->
mp.start()
_isPlaying.value = true
}
setOnCompletionListener {
_isPlaying.value = false
}
}
}
private suspend fun generateSunoAudio(prompt: String): String {
return withContext(Dispatchers.IO) {
// Implementation to call Suno API
""
}
}
fun stopPlayback() {
mediaPlayer?.stop()
mediaPlayer?.release()
mediaPlayer = null
_isPlaying.value = false
}
override fun onCleared() {
mediaPlayer?.release()
super.onCleared()
}
}Troubleshooting and Optimization
Handling API Rate Limits
class RateLimitManager {
constructor(requestsPerMinute = 10) {
this.maxRequests = requestsPerMinute;
this.requestQueue = [];
this.processing = false;
}
async executeWithRateLimit(fn) {
return new Promise((resolve, reject) => {
this.requestQueue.push({ fn, resolve, reject });
this.processQueue();
});
}
private async processQueue() {
if (this.processing || this.requestQueue.length === 0) {
return;
}
this.processing = true;
const now = Date.now();
const oneMinuteAgo = now - 60000;
// Remove old timestamps
this.requestTimestamps = this.requestTimestamps.filter(
ts => ts > oneMinuteAgo
);
// Check if we can process next request
if (this.requestTimestamps.length < this.maxRequests) {
const { fn, resolve, reject } = this.requestQueue.shift();
try {
const result = await fn();
this.requestTimestamps.push(now);
resolve(result);
} catch (error) {
reject(error);
}
this.processing = false;
this.processQueue();
} else {
// Wait before processing next request
const waitTime = 60000 - (now - this.requestTimestamps[0]);
setTimeout(() => {
this.processing = false;
this.processQueue();
}, waitTime);
}
}
}Audio Quality Best Practices
- Format: MP3 (128-320 kbps) or WAV for lossless
- Sample Rate: 44.1 kHz or 48 kHz
- Bit Depth: 16-bit minimum, 24-bit for high fidelity
- Mono vs Stereo: Stereo for music, mono acceptable for SFX
Performance Optimization
class OptimizedAudioCache {
constructor(maxSize = 100) {
this.cache = new Map();
this.maxSize = maxSize;
}
async getOrGenerate(key, generator) {
if (this.cache.has(key)) {
return this.cache.get(key);
}
const result = await generator();
if (this.cache.size >= this.maxSize) {
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
this.cache.set(key, result);
return result;
}
prefetch(keys, generator) {
return Promise.all(
keys.map(key => this.getOrGenerate(key, () => generator(key)))
);
}
}Conclusion
The combination of Suno AI and Antigravity transforms audio production for your applications:
- Speed: Generate professional-quality music in seconds
- Customization: Fine-grained control through natural language prompts
- Cost Efficiency: Eliminate expensive audio production workflows
- Scalability: Seamlessly integrate across multiple projects via API
By mastering prompt design, managing licenses responsibly, and optimizing API usage, you can add sophisticated audio experiences to any application—all without requiring specialized audio expertise.