mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 05:27:45 +00:00
Piano: Start working on a desktop piano.
The idea here is to implement a simple synhesizer that allows you to play music with your keyboard. :^) It's a huge hack currently but we can improve upon this.
This commit is contained in:
parent
f712ead1fb
commit
c962c54610
7 changed files with 531 additions and 0 deletions
23
Applications/Piano/Makefile
Normal file
23
Applications/Piano/Makefile
Normal file
|
@ -0,0 +1,23 @@
|
|||
include ../../Makefile.common
|
||||
|
||||
OBJS = \
|
||||
PianoWidget.o \
|
||||
main.o
|
||||
|
||||
APP = Piano
|
||||
|
||||
DEFINES += -DUSERLAND
|
||||
|
||||
all: $(APP)
|
||||
|
||||
$(APP): $(OBJS)
|
||||
$(LD) -o $(APP) $(LDFLAGS) $(OBJS) -lgui -lcore -lc
|
||||
|
||||
.cpp.o:
|
||||
@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
|
||||
|
||||
-include $(OBJS:%.o=%.d)
|
||||
|
||||
clean:
|
||||
@echo "CLEAN"; rm -f $(APP) $(OBJS) *.d
|
||||
|
62
Applications/Piano/Music.h
Normal file
62
Applications/Piano/Music.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Types.h>
|
||||
|
||||
namespace Music {
|
||||
|
||||
struct Sample {
|
||||
i16 left;
|
||||
i16 right;
|
||||
};
|
||||
|
||||
enum WaveType { Sine, Saw, Square, InvalidWave };
|
||||
|
||||
enum PianoKey {
|
||||
K_C1, K_Db1, K_D1, K_Eb1, K_E1, K_F1, K_Gb1, K_G1, K_Ab1, K_A1, K_Bb1, K_B1,
|
||||
K_C2, K_Db2, K_D2, K_Eb2, K_E2, K_F2, K_Gb2, K_G2,
|
||||
};
|
||||
|
||||
inline bool is_white(PianoKey n)
|
||||
{
|
||||
switch (n) {
|
||||
case K_C1:
|
||||
case K_D1:
|
||||
case K_E1:
|
||||
case K_F1:
|
||||
case K_G1:
|
||||
case K_A1:
|
||||
case K_B1:
|
||||
case K_C2:
|
||||
case K_D2:
|
||||
case K_E2:
|
||||
case K_F2:
|
||||
case K_G2:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
enum Note {
|
||||
C1, Db1, D1, Eb1, E1, F1, Gb1, G1, Ab1, A1, Bb1, B1,
|
||||
C2, Db2, D2, Eb2, E2, F2, Gb2, G2, Ab2, A2, Bb2, B2,
|
||||
C3, Db3, D3, Eb3, E3, F3, Gb3, G3, Ab3, A3, Bb3, B3,
|
||||
C4, Db4, D4, Eb4, E4, F4, Gb4, G4, Ab4, A4, Bb4, B4,
|
||||
C5, Db5, D5, Eb5, E5, F5, Gb5, G5, Ab5, A5, Bb5, B5,
|
||||
C6, Db6, D6, Eb6, E6, F6, Gb6, G6, Ab6, A6, Bb6, B6,
|
||||
C7, Db7, D7, Eb7, E7, F7, Gb7, G7, Ab7, A7, Bb7, B7,
|
||||
};
|
||||
|
||||
const double note_frequency[] = {
|
||||
/* Octave 1 */ 32.70, 34.65, 36.71, 38.89, 41.20, 43.65, 46.25, 49.00, 51.91, 55.00, 58.27, 61.74,
|
||||
/* Octave 2 */ 65.41, 69.30, 73.42, 77.78, 82.41, 87.31, 92.50, 98.00, 103.83, 110.00, 116.54, 123.47,
|
||||
/* Octave 3 */ 130.81, 138.59, 146.83, 155.56, 164.81, 174.61, 185.00, 196.00, 207.65, 220.00, 233.08, 246.94,
|
||||
/* Octave 4 */ 261.63, 277.18, 293.66, 311.13, 329.63, 349.23, 369.99, 392.00, 415.30, 440.00, 466.16, 493.88,
|
||||
/* Octave 5 */ 523.25, 554.37, 587.33, 622.25, 659.25, 698.46, 739.99, 783.99, 830.61, 880.00, 932.33, 987.77,
|
||||
/* Octave 6 */ 1046.50, 1108.73, 1174.66, 1244.51, 1318.51, 1396.91, 1479.98, 1567.98, 1661.22, 1760.00, 1864.66, 1975.53,
|
||||
/* Octave 7 */ 2093.00, 2217.46, 2349.32, 2489.02, 2637.02, 2793.83, 2959.96, 3135.96, 3322.44, 3520.00, 3729.31, 3951.07,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using namespace Music;
|
353
Applications/Piano/PianoWidget.cpp
Normal file
353
Applications/Piano/PianoWidget.cpp
Normal file
|
@ -0,0 +1,353 @@
|
|||
#include "PianoWidget.h"
|
||||
#include <AK/Queue.h>
|
||||
#include <LibGUI/GPainter.h>
|
||||
#include <SharedGraphics/GraphicsBitmap.h>
|
||||
#include <math.h>
|
||||
|
||||
PianoWidget::PianoWidget()
|
||||
{
|
||||
memset(keys, 0, sizeof(keys));
|
||||
m_bitmap = GraphicsBitmap::create(GraphicsBitmap::Format::RGB32, { m_width, m_height });
|
||||
}
|
||||
|
||||
PianoWidget::~PianoWidget()
|
||||
{
|
||||
}
|
||||
|
||||
void PianoWidget::paint_event(GPaintEvent& event)
|
||||
{
|
||||
GPainter painter(*this);
|
||||
painter.add_clip_rect(event.rect());
|
||||
painter.blit({ 0, 0 }, *m_bitmap, m_bitmap->rect());
|
||||
}
|
||||
|
||||
void PianoWidget::fill_audio_buffer(uint8_t* stream, int len)
|
||||
{
|
||||
size_t sample_count = len / sizeof(Sample);
|
||||
memset(stream, 0, len);
|
||||
|
||||
Sample* sst = (Sample*)stream;
|
||||
for (size_t i = 0; i < sample_count; ++i) {
|
||||
static const double VOLUME = 3000;
|
||||
for (size_t n = 0; n < (sizeof(m_note_on) / sizeof(bool)); ++n) {
|
||||
if (!m_note_on[n])
|
||||
continue;
|
||||
double val = 0;
|
||||
if (m_wave_type == WaveType::Sine)
|
||||
val = ((VOLUME * m_power[n]) * w_sine(n));
|
||||
else if (m_wave_type == WaveType::Saw)
|
||||
val = ((VOLUME * m_power[n]) * w_saw(n));
|
||||
else if (m_wave_type == WaveType::Square)
|
||||
val = ((VOLUME * m_power[n]) * w_square(n));
|
||||
if (sst[i].left == 0)
|
||||
sst[i].left = val;
|
||||
else
|
||||
sst[i].left += val;
|
||||
}
|
||||
sst[i].right = sst[i].left;
|
||||
}
|
||||
|
||||
// Release pressed notes.
|
||||
if (m_release_enabled) {
|
||||
for (size_t n = 0; n < (sizeof(m_note_on) / sizeof(bool)); ++n) {
|
||||
if (m_note_on[n])
|
||||
m_power[n] *= 0.965;
|
||||
}
|
||||
}
|
||||
|
||||
static Queue<Sample*> delay_frames;
|
||||
static const int delay_length_in_frames = 50;
|
||||
|
||||
//assert((int)sample_count == m_width);
|
||||
|
||||
if (m_delay_enabled) {
|
||||
if (delay_frames.size() >= delay_length_in_frames) {
|
||||
auto* to_blend = delay_frames.dequeue();
|
||||
for (size_t i = 0; i < sample_count; ++i) {
|
||||
sst[i].left += to_blend[i].left * 0.333333;
|
||||
sst[i].right += to_blend[i].right * 0.333333;
|
||||
}
|
||||
delete[] to_blend;
|
||||
}
|
||||
Sample* frame = new Sample[sample_count];
|
||||
memcpy(frame, sst, sample_count * sizeof(Sample));
|
||||
|
||||
delay_frames.enqueue(frame);
|
||||
}
|
||||
|
||||
GPainter painter(*m_bitmap);
|
||||
painter.fill_rect(m_bitmap->rect(), Color::Black);
|
||||
|
||||
Sample* samples = (Sample*)stream;
|
||||
Color wave_color;
|
||||
if (m_wave_type == WaveType::Sine)
|
||||
wave_color = Color(255, 192, 0);
|
||||
else if (m_wave_type == WaveType::Saw)
|
||||
wave_color = Color(240, 100, 128);
|
||||
else if (m_wave_type == WaveType::Square)
|
||||
wave_color = Color(128, 160, 255);
|
||||
|
||||
int prev_x = 0;
|
||||
int prev_y = m_height / 2;
|
||||
for (int x = 0; x < (int)sample_count; ++x) {
|
||||
double val = samples[x].left;
|
||||
val /= 32768;
|
||||
val *= m_height * 2;
|
||||
int y = (m_height / 2) + val;
|
||||
if (x == 0)
|
||||
painter.set_pixel({ x, y }, wave_color);
|
||||
else
|
||||
painter.draw_line({ prev_x, prev_y }, { x, y }, wave_color);
|
||||
prev_x = x;
|
||||
prev_y = y;
|
||||
}
|
||||
|
||||
render_piano(painter);
|
||||
render_knobs(painter);
|
||||
}
|
||||
|
||||
double PianoWidget::w_sine(size_t n)
|
||||
{
|
||||
double pos = note_frequency[n] / 44100.0;
|
||||
double sin_step = pos * 2 * M_PI;
|
||||
double w = sin(m_sin_pos[n]);
|
||||
m_sin_pos[n] += sin_step;
|
||||
return w;
|
||||
}
|
||||
|
||||
static inline double hax_floor(double t)
|
||||
{
|
||||
return (int)t;
|
||||
}
|
||||
|
||||
double PianoWidget::w_saw(size_t n)
|
||||
{
|
||||
double saw_step = note_frequency[n] / 44100.0;
|
||||
double t = m_saw_pos[n];
|
||||
double w = (0.5 - (t - hax_floor(t))) * 2;
|
||||
//printf("w: %g, step: %g\n", w, saw_step);
|
||||
m_saw_pos[n] += saw_step;
|
||||
return w;
|
||||
}
|
||||
|
||||
double PianoWidget::w_square(size_t n)
|
||||
{
|
||||
double pos = note_frequency[n] / 44100.0;
|
||||
double square_step = pos * 2 * M_PI;
|
||||
double w = sin(m_square_pos[n]);
|
||||
if (w > 0)
|
||||
w = 1;
|
||||
else
|
||||
w = -1;
|
||||
//printf("w: %g, step: %g\n", w, square_step);
|
||||
m_square_pos[n] += square_step;
|
||||
return w;
|
||||
}
|
||||
|
||||
int PianoWidget::octave_base() const
|
||||
{
|
||||
return (m_octave - m_octave_min) * 12;
|
||||
}
|
||||
|
||||
void PianoWidget::note(PianoKey offset_n, bool is_down)
|
||||
{
|
||||
int n = offset_n + octave_base();
|
||||
if (m_note_on[n] == is_down)
|
||||
return;
|
||||
m_note_on[n] = is_down;
|
||||
m_sin_pos[n] = 0;
|
||||
m_saw_pos[n] = 0;
|
||||
if (is_down)
|
||||
m_power[n] = 1;
|
||||
//printf("note[%u] = %u (%g)\n", (unsigned)n, is_down, note_frequency[n]);
|
||||
}
|
||||
|
||||
void PianoWidget::update_keys()
|
||||
{
|
||||
note(K_C1, keys[KeyCode::Key_A]);
|
||||
note(K_Db1, keys[KeyCode::Key_W]);
|
||||
note(K_D1, keys[KeyCode::Key_S]);
|
||||
note(K_Eb1, keys[KeyCode::Key_E]);
|
||||
note(K_E1, keys[KeyCode::Key_D]);
|
||||
note(K_F1, keys[KeyCode::Key_F]);
|
||||
note(K_Gb1, keys[KeyCode::Key_T]);
|
||||
note(K_G1, keys[KeyCode::Key_G]);
|
||||
note(K_Ab1, keys[KeyCode::Key_Y]);
|
||||
note(K_A1, keys[KeyCode::Key_H]);
|
||||
note(K_Bb1, keys[KeyCode::Key_U]);
|
||||
note(K_B1, keys[KeyCode::Key_J]);
|
||||
note(K_C2, keys[KeyCode::Key_K]);
|
||||
note(K_Db2, keys[KeyCode::Key_O]);
|
||||
note(K_D2, keys[KeyCode::Key_L]);
|
||||
note(K_Eb2, keys[KeyCode::Key_P]);
|
||||
note(K_E2, keys[KeyCode::Key_Semicolon]);
|
||||
note(K_F2, keys[KeyCode::Key_Apostrophe]);
|
||||
note(K_Gb2, keys[KeyCode::Key_RightBracket]);
|
||||
note(K_G2, keys[KeyCode::Key_Return]);
|
||||
}
|
||||
|
||||
void PianoWidget::keydown_event(GKeyEvent& event)
|
||||
{
|
||||
switch (event.key()) {
|
||||
case KeyCode::Key_C:
|
||||
|
||||
if (++m_wave_type == InvalidWave)
|
||||
m_wave_type = 0;
|
||||
break;
|
||||
case KeyCode::Key_V:
|
||||
m_delay_enabled = !m_delay_enabled;
|
||||
break;
|
||||
case KeyCode::Key_B:
|
||||
m_release_enabled = !m_release_enabled;
|
||||
break;
|
||||
case KeyCode::Key_Z:
|
||||
if (m_octave > m_octave_min)
|
||||
--m_octave;
|
||||
memset(m_note_on, 0, sizeof(m_note_on));
|
||||
break;
|
||||
case KeyCode::Key_X:
|
||||
if (m_octave < m_octave_max)
|
||||
++m_octave;
|
||||
memset(m_note_on, 0, sizeof(m_note_on));
|
||||
break;
|
||||
}
|
||||
|
||||
keys[event.key()] = true;
|
||||
update_keys();
|
||||
update();
|
||||
}
|
||||
|
||||
void PianoWidget::keyup_event(GKeyEvent& event)
|
||||
{
|
||||
keys[event.key()] = false;
|
||||
update_keys();
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
static int white_key_width = 22;
|
||||
static int white_key_height = 60;
|
||||
static int black_key_width = 16;
|
||||
static int black_key_height = 35;
|
||||
static int black_key_stride = white_key_width - black_key_width;
|
||||
static int black_key_offset = white_key_width - black_key_width / 2;
|
||||
|
||||
void PianoWidget::render_piano_key(GPainter& painter, int index, PianoKey n, const StringView& text)
|
||||
{
|
||||
Color color;
|
||||
if (m_note_on[octave_base() + n]) {
|
||||
color = Color(64, 64, 255);
|
||||
} else {
|
||||
if (is_white(n))
|
||||
color = Color::White;
|
||||
else
|
||||
color = Color::Black;
|
||||
}
|
||||
Rect rect;
|
||||
int stride = 0;
|
||||
int offset = 0;
|
||||
if (is_white(n)) {
|
||||
rect.set_width(white_key_width);
|
||||
rect.set_height(white_key_height);
|
||||
} else {
|
||||
rect.set_width(black_key_width);
|
||||
rect.set_height(black_key_height);
|
||||
stride = black_key_stride;
|
||||
offset = black_key_offset;
|
||||
}
|
||||
rect.set_x(offset + index * rect.width() + (index * stride));
|
||||
rect.set_y(m_height - white_key_height);
|
||||
|
||||
painter.fill_rect(rect, color);
|
||||
painter.draw_rect(rect, Color::Black);
|
||||
|
||||
Color text_color;
|
||||
if (is_white(n)) {
|
||||
text_color = Color::Black;
|
||||
} else {
|
||||
text_color = Color::White;
|
||||
}
|
||||
Rect r(rect.x(), rect.y() + rect.height() / 2, rect.width(), rect.height() / 2);
|
||||
painter.draw_text(r, text, TextAlignment::Center, text_color);
|
||||
}
|
||||
|
||||
void PianoWidget::render_piano(GPainter& painter)
|
||||
{
|
||||
render_piano_key(painter, 0, K_C1, "A");
|
||||
render_piano_key(painter, 1, K_D1, "S");
|
||||
render_piano_key(painter, 2, K_E1, "D");
|
||||
render_piano_key(painter, 3, K_F1, "F");
|
||||
render_piano_key(painter, 4, K_G1, "G");
|
||||
render_piano_key(painter, 5, K_A1, "H");
|
||||
render_piano_key(painter, 6, K_B1, "J");
|
||||
render_piano_key(painter, 7, K_C2, "K");
|
||||
render_piano_key(painter, 8, K_D2, "L");
|
||||
render_piano_key(painter, 9, K_E2, ";");
|
||||
render_piano_key(painter, 10, K_F2, "'");
|
||||
render_piano_key(painter, 11, K_G2, "r");
|
||||
|
||||
render_piano_key(painter, 0, K_Db1, "W");
|
||||
render_piano_key(painter, 1, K_Eb1, "E");
|
||||
render_piano_key(painter, 3, K_Gb1, "T");
|
||||
render_piano_key(painter, 4, K_Ab1, "Y");
|
||||
render_piano_key(painter, 5, K_Bb1, "U");
|
||||
render_piano_key(painter, 7, K_Db2, "O");
|
||||
render_piano_key(painter, 8, K_Eb2, "P");
|
||||
render_piano_key(painter, 10, K_Gb2, "]");
|
||||
}
|
||||
|
||||
static int knob_width = 100;
|
||||
|
||||
void PianoWidget::render_knob(GPainter& painter, const Rect& rect, bool state, const StringView& text)
|
||||
{
|
||||
Color text_color;
|
||||
if (state) {
|
||||
painter.fill_rect(rect, Color(0, 200, 0));
|
||||
text_color = Color::Black;
|
||||
} else {
|
||||
painter.draw_rect(rect, Color(180, 0, 0));
|
||||
text_color = Color(180, 0, 0);
|
||||
}
|
||||
painter.draw_text(rect, text, TextAlignment::Center, text_color);
|
||||
}
|
||||
|
||||
void PianoWidget::render_knobs(GPainter& painter)
|
||||
{
|
||||
Rect delay_knob_rect(m_width - knob_width - 16, m_height - 50, knob_width, 16);
|
||||
render_knob(painter, delay_knob_rect, m_delay_enabled, "V: Delay ");
|
||||
|
||||
Rect release_knob_rect(m_width - knob_width - 16, m_height - 30, knob_width, 16);
|
||||
render_knob(painter, release_knob_rect, m_release_enabled, "B: Release ");
|
||||
|
||||
Rect octave_knob_rect(m_width - knob_width - 16 - knob_width - 16, m_height - 50, knob_width, 16);
|
||||
auto text = String::format("Z/X: Oct %d ", m_octave);
|
||||
int oct_rgb_step = 255 / (m_octave_max + 4);
|
||||
int oshade = (m_octave + 4) * oct_rgb_step;
|
||||
painter.draw_rect(octave_knob_rect, Color(oshade, oshade, oshade));
|
||||
painter.draw_text(octave_knob_rect, text, TextAlignment::Center, Color(oshade, oshade, oshade));
|
||||
|
||||
int r = 0, g = 0, b = 0;
|
||||
if (m_wave_type == WaveType::Sine) {
|
||||
r = 255;
|
||||
g = 192;
|
||||
b = 0;
|
||||
} else if (m_wave_type == WaveType::Saw) {
|
||||
r = 240;
|
||||
g = 100;
|
||||
b = 128;
|
||||
} else if (m_wave_type == WaveType::Square) {
|
||||
r = 128;
|
||||
g = 160;
|
||||
b = 255;
|
||||
}
|
||||
Rect wave_knob_rect(m_width - knob_width - 16 - knob_width - 16, m_height - 30, knob_width, 16);
|
||||
const char* wave_name = "";
|
||||
if (m_wave_type == WaveType::Sine)
|
||||
wave_name = "C: Sine ";
|
||||
else if (m_wave_type == WaveType::Saw)
|
||||
wave_name = "C: Sawtooth";
|
||||
else if (m_wave_type == WaveType::Square)
|
||||
wave_name = "C: Square ";
|
||||
painter.draw_rect(wave_knob_rect, Color(r, g, b));
|
||||
painter.draw_text(wave_knob_rect, wave_name, TextAlignment::Center, Color(r, g, b));
|
||||
}
|
55
Applications/Piano/PianoWidget.h
Normal file
55
Applications/Piano/PianoWidget.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
#pragma once
|
||||
|
||||
#include "Music.h"
|
||||
#include <LibGUI/GWidget.h>
|
||||
|
||||
class GPainter;
|
||||
|
||||
class PianoWidget final : public GWidget {
|
||||
public:
|
||||
PianoWidget();
|
||||
virtual ~PianoWidget() override;
|
||||
|
||||
virtual void paint_event(GPaintEvent&) override;
|
||||
virtual void keydown_event(GKeyEvent&) override;
|
||||
virtual void keyup_event(GKeyEvent&) override;
|
||||
|
||||
void fill_audio_buffer(uint8_t* stream, int len);
|
||||
|
||||
private:
|
||||
double w_sine(size_t);
|
||||
double w_saw(size_t);
|
||||
double w_square(size_t);
|
||||
|
||||
void render_piano_key(GPainter&, int index, PianoKey, const StringView&);
|
||||
void render_piano(GPainter&);
|
||||
void render_knobs(GPainter&);
|
||||
void render_knob(GPainter&, const Rect&, bool state, const StringView&);
|
||||
|
||||
void note(Music::PianoKey offset_n, bool is_down);
|
||||
void update_keys();
|
||||
int octave_base() const;
|
||||
|
||||
RefPtr<GraphicsBitmap> m_bitmap;
|
||||
|
||||
#define note_count sizeof(note_frequency) / sizeof(double)
|
||||
|
||||
bool m_note_on[note_count];
|
||||
double m_power[note_count];
|
||||
double m_sin_pos[note_count];
|
||||
double m_square_pos[note_count];
|
||||
double m_saw_pos[note_count];
|
||||
|
||||
int m_octave_min { 1 };
|
||||
int m_octave_max { 6 };
|
||||
int m_octave { 4 };
|
||||
|
||||
int m_width { 512 };
|
||||
int m_height { 512 };
|
||||
|
||||
int m_wave_type { 0 };
|
||||
bool m_delay_enabled { false };
|
||||
bool m_release_enabled { false };
|
||||
|
||||
bool keys[256];
|
||||
};
|
35
Applications/Piano/main.cpp
Normal file
35
Applications/Piano/main.cpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#include "Music.h"
|
||||
#include "PianoWidget.h"
|
||||
#include <LibCore/CFile.h>
|
||||
#include <LibGUI/GApplication.h>
|
||||
#include <LibGUI/GEventLoop.h>
|
||||
#include <LibGUI/GWindow.h>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
CFile audio("/dev/audio");
|
||||
if (!audio.open(CIODevice::WriteOnly)) {
|
||||
dbgprintf("Can't open audio device: %s", audio.error_string());
|
||||
return 1;
|
||||
}
|
||||
|
||||
GApplication app(argc, argv);
|
||||
|
||||
auto* window = new GWindow;
|
||||
window->set_title("Piano");
|
||||
window->set_rect(100, 100, 512, 512);
|
||||
|
||||
auto* piano_widget = new PianoWidget;
|
||||
window->set_main_widget(piano_widget);
|
||||
|
||||
window->show();
|
||||
|
||||
for (;;) {
|
||||
GEventLoop::current().pump(GEventLoop::WaitMode::PollForEvents);
|
||||
u8 buffer[4096];
|
||||
piano_widget->fill_audio_buffer(buffer, sizeof(buffer));
|
||||
audio.write(buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -77,6 +77,7 @@ cp ../Applications/Terminal/Terminal mnt/bin/Terminal
|
|||
cp ../Applications/TextEditor/TextEditor mnt/bin/TextEditor
|
||||
cp ../Applications/PaintBrush/PaintBrush mnt/bin/PaintBrush
|
||||
cp ../Applications/QuickShow/QuickShow mnt/bin/QuickShow
|
||||
cp ../Applications/Piano/Piano mnt/bin/Piano
|
||||
cp ../Demos/HelloWorld/HelloWorld mnt/bin/HelloWorld
|
||||
cp ../Demos/HelloWorld2/HelloWorld2 mnt/bin/HelloWorld2
|
||||
cp ../Demos/RetroFetch/RetroFetch mnt/bin/RetroFetch
|
||||
|
@ -108,6 +109,7 @@ ln -s WidgetGallery mnt/bin/wg
|
|||
ln -s TextEditor mnt/bin/te
|
||||
ln -s PaintBrush mnt/bin/pb
|
||||
ln -s QuickShow mnt/bin/qs
|
||||
ln -s Piano mnt/bin/pi
|
||||
echo "done"
|
||||
|
||||
# Run local sync script, if it exists
|
||||
|
|
|
@ -37,6 +37,7 @@ build_targets="$build_targets ../Applications/Taskbar"
|
|||
build_targets="$build_targets ../Applications/Downloader"
|
||||
build_targets="$build_targets ../Applications/PaintBrush"
|
||||
build_targets="$build_targets ../Applications/QuickShow"
|
||||
build_targets="$build_targets ../Applications/Piano"
|
||||
build_targets="$build_targets ../DevTools/VisualBuilder"
|
||||
build_targets="$build_targets ../Games/Minesweeper"
|
||||
build_targets="$build_targets ../Games/Snake"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue